msgs::DecodeError::UnknownVersion => return,
msgs::DecodeError::UnknownRequiredFeature => return,
msgs::DecodeError::InvalidValue => return,
- msgs::DecodeError::ExtraAddressesPerType => return,
msgs::DecodeError::BadLengthDescriptor => return,
msgs::DecodeError::ShortRead => panic!("We picked the length..."),
msgs::DecodeError::Io(e) => panic!(format!("{}", e)),
holding_cell_update_fee: Option<u64>,
next_local_htlc_id: u64,
next_remote_htlc_id: u64,
- channel_update_count: u32,
+ update_time_counter: u32,
feerate_per_kw: u64,
#[cfg(debug_assertions)]
holding_cell_update_fee: None,
next_local_htlc_id: 0,
next_remote_htlc_id: 0,
- channel_update_count: 1,
+ update_time_counter: 1,
resend_order: RAACommitmentOrder::CommitmentFirst,
holding_cell_update_fee: None,
next_local_htlc_id: 0,
next_remote_htlc_id: 0,
- channel_update_count: 1,
+ update_time_counter: 1,
resend_order: RAACommitmentOrder::CommitmentFirst,
self.channel_state |= ChannelState::TheirFundingLocked as u32;
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
} else if (self.channel_state & (ChannelState::ChannelFunded as u32) != 0 &&
// Note that funding_signed/funding_created will have decremented both by 1!
self.cur_local_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
}
Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
self.pending_update_fee = Some(msg.feerate_per_kw as u64);
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
Ok(())
}
// From here on out, we may not fail!
self.channel_state |= ChannelState::RemoteShutdownSent as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
// We can't send our shutdown until we've committed all of our pending HTLCs, but the
// remote side is unlikely to accept any new HTLCs, so we go ahead and "free" any holding
};
self.channel_state |= ChannelState::LocalShutdownSent as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
}
if last_fee == msg.fee_satoshis {
self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &our_sig);
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
return Ok((None, Some(closing_tx)));
}
}
self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &our_sig);
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
Ok((Some(msgs::ClosingSigned {
channel_id: self.channel_id,
}
/// Allowed in any state (including after shutdown)
- pub fn get_channel_update_count(&self) -> u32 {
- self.channel_update_count
+ pub fn get_update_time_counter(&self) -> u32 {
+ self.update_time_counter
}
pub fn get_latest_monitor_update_id(&self) -> u64 {
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
}
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
return Err(msgs::ErrorMessage {
channel_id: self.channel_id(),
data: "funding tx had wrong script/value".to_owned()
}
if header.bitcoin_hash() != self.last_block_connected {
self.last_block_connected = header.bitcoin_hash();
+ self.update_time_counter = cmp::max(self.update_time_counter, header.time);
if let Some(channel_monitor) = self.channel_monitor.as_mut() {
channel_monitor.last_block_hash = self.last_block_connected;
}
true
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
true
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
// We got a reorg but not enough to trigger a force close, just update
} else {
self.channel_state |= ChannelState::LocalShutdownSent as u32;
}
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
// Go ahead and drop holding cell updates as we'd rather fail payments than wait to send
// our shutdown until we've committed all of the pending changes.
}
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
if self.channel_monitor.is_some() {
(self.channel_monitor.as_mut().unwrap().get_latest_local_commitment_txn(), dropped_outbound_htlcs)
} else {
self.next_local_htlc_id.write(writer)?;
(self.next_remote_htlc_id - dropped_inbound_htlcs).write(writer)?;
- self.channel_update_count.write(writer)?;
+ self.update_time_counter.write(writer)?;
self.feerate_per_kw.write(writer)?;
match self.last_sent_closing_fee {
let next_local_htlc_id = Readable::read(reader)?;
let next_remote_htlc_id = Readable::read(reader)?;
- let channel_update_count = Readable::read(reader)?;
+ let update_time_counter = Readable::read(reader)?;
let feerate_per_kw = Readable::read(reader)?;
let last_sent_closing_fee = match <u8 as Readable>::read(reader)? {
holding_cell_update_fee,
next_local_htlc_id,
next_remote_htlc_id,
- channel_update_count,
+ update_time_counter,
feerate_per_kw,
#[cfg(debug_assertions)]
use chain::transaction::OutPoint;
use ln::channel::{Channel, ChannelError};
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, ManyChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
+use ln::features::{InitFeatures, NodeFeatures};
use ln::router::Route;
-use ln::features::InitFeatures;
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
channel_state: Mutex<ChannelHolder<ChanSigner>>,
our_network_key: SecretKey,
+ /// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
+ /// value increases strictly since we don't assume access to a time source.
+ last_node_announcement_serial: AtomicUsize,
+
/// The bulk of our storage will eventually be here (channels and message queues and the like).
/// If we are connected to a peer we always at least have an entry here, even if no channels
/// are currently open with that peer.
}),
our_network_key: keys_manager.get_node_secret(),
+ last_node_announcement_serial: AtomicUsize::new(0),
+
per_peer_state: RwLock::new(HashMap::new()),
pending_events: Mutex::new(Vec::new()),
let unsigned = msgs::UnsignedChannelUpdate {
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
- timestamp: chan.get_channel_update_count(),
+ timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
})
}
+ #[allow(dead_code)]
+ // Messages of up to 64KB should never end up more than half full with addresses, as that would
+ // be absurd. We ensure this by checking that at least 500 (our stated public contract on when
+ // broadcast_node_announcement panics) of the maximum-length addresses would fit in a 64KB
+ // message...
+ const HALF_MESSAGE_IS_ADDRS: u32 = ::std::u16::MAX as u32 / (msgs::NetAddress::MAX_LEN as u32 + 1) / 2;
+ #[deny(const_err)]
+ #[allow(dead_code)]
+ // ...by failing to compile if the number of addresses that would be half of a message is
+ // smaller than 500:
+ const STATIC_ASSERT: u32 = Self::HALF_MESSAGE_IS_ADDRS - 500;
+
+ /// Generates a signed node_announcement from the given arguments and creates a
+ /// BroadcastNodeAnnouncement event. Note that such messages will be ignored unless peers have
+ /// seen a channel_announcement from us (ie unless we have public channels open).
+ ///
+ /// RGB is a node "color" and alias is a printable human-readable string to describe this node
+ /// to humans. They carry no in-protocol meaning.
+ ///
+ /// addresses represent the set (possibly empty) of socket addresses on which this node accepts
+ /// incoming connections. These will be broadcast to the network, publicly tying these
+ /// addresses together. If you wish to preserve user privacy, addresses should likely contain
+ /// only Tor Onion addresses.
+ ///
+ /// Panics if addresses is absurdly large (more than 500).
+ pub fn broadcast_node_announcement(&self, rgb: [u8; 3], alias: [u8; 32], addresses: Vec<msgs::NetAddress>) {
+ let _ = self.total_consistency_lock.read().unwrap();
+
+ if addresses.len() > 500 {
+ panic!("More than half the message size was taken up by public addresses!");
+ }
+
+ let announcement = msgs::UnsignedNodeAnnouncement {
+ features: NodeFeatures::supported(),
+ timestamp: self.last_node_announcement_serial.fetch_add(1, Ordering::AcqRel) as u32,
+ node_id: self.get_our_node_id(),
+ rgb, alias, addresses,
+ excess_address_data: Vec::new(),
+ excess_data: Vec::new(),
+ };
+ let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]);
+
+ let mut channel_state = self.channel_state.lock().unwrap();
+ channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastNodeAnnouncement {
+ msg: msgs::NodeAnnouncement {
+ signature: self.secp_ctx.sign(&msghash, &self.our_network_key),
+ contents: announcement
+ },
+ });
+ }
+
/// Processes HTLCs which are pending waiting on random forward delay.
///
/// Should only really ever be called in response to a PendingHTLCsForwardable event.
}
self.latest_block_height.store(height as usize, Ordering::Release);
*self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = header_hash;
+ loop {
+ // Update last_node_announcement_serial to be the max of its current value and the
+ // block timestamp. This should keep us close to the current time without relying on
+ // having an explicit local time source.
+ // Just in case we end up in a race, we loop until we either successfully update
+ // last_node_announcement_serial or decide we don't need to.
+ let old_serial = self.last_node_announcement_serial.load(Ordering::Acquire);
+ if old_serial >= header.time as usize { break; }
+ if self.last_node_announcement_serial.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
+ break;
+ }
+ }
}
/// We force-close the channel without letting our counterparty participate in the shutdown
&events::MessageSendEvent::SendShutdown { ref node_id, .. } => node_id != their_node_id,
&events::MessageSendEvent::SendChannelReestablish { ref node_id, .. } => node_id != their_node_id,
&events::MessageSendEvent::BroadcastChannelAnnouncement { .. } => true,
+ &events::MessageSendEvent::BroadcastNodeAnnouncement { .. } => true,
&events::MessageSendEvent::BroadcastChannelUpdate { .. } => true,
&events::MessageSendEvent::HandleError { ref node_id, .. } => node_id != their_node_id,
&events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => true,
peer_state.latest_features.write(writer)?;
}
+ (self.last_node_announcement_serial.load(Ordering::Acquire) as u32).write(writer)?;
+
Ok(())
}
}
per_peer_state.insert(peer_pubkey, Mutex::new(peer_state));
}
+ let last_node_announcement_serial: u32 = Readable::read(reader)?;
+
let channel_manager = ChannelManager {
genesis_hash,
fee_estimator: args.fee_estimator,
}),
our_network_key: args.keys_manager.get_node_secret(),
+ last_node_announcement_serial: AtomicUsize::new(last_node_announcement_serial as usize),
+
per_peer_state: RwLock::new(per_peer_state),
pending_events: Mutex::new(Vec::new()),
pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
let chan_announcement = create_chan_between_nodes_with_value(&nodes[a], &nodes[b], channel_value, push_msat, a_flags, b_flags);
+
+ nodes[a].node.broadcast_node_announcement([0, 0, 0], [0; 32], Vec::new());
+ let a_events = nodes[a].node.get_and_clear_pending_msg_events();
+ assert_eq!(a_events.len(), 1);
+ let a_node_announcement = match a_events[0] {
+ MessageSendEvent::BroadcastNodeAnnouncement { ref msg } => {
+ (*msg).clone()
+ },
+ _ => panic!("Unexpected event"),
+ };
+
+ nodes[b].node.broadcast_node_announcement([1, 1, 1], [1; 32], Vec::new());
+ let b_events = nodes[b].node.get_and_clear_pending_msg_events();
+ assert_eq!(b_events.len(), 1);
+ let b_node_announcement = match b_events[0] {
+ MessageSendEvent::BroadcastNodeAnnouncement { ref msg } => {
+ (*msg).clone()
+ },
+ _ => panic!("Unexpected event"),
+ };
+
for node in nodes {
assert!(node.router.handle_channel_announcement(&chan_announcement.0).unwrap());
node.router.handle_channel_update(&chan_announcement.1).unwrap();
node.router.handle_channel_update(&chan_announcement.2).unwrap();
+ node.router.handle_node_announcement(&a_node_announcement).unwrap();
+ node.router.handle_node_announcement(&b_node_announcement).unwrap();
}
(chan_announcement.1, chan_announcement.2, chan_announcement.3, chan_announcement.4)
}
InvalidValue,
/// Buffer too short
ShortRead,
- /// node_announcement included more than one address of a given type!
- ExtraAddressesPerType,
/// A length descriptor in the packet didn't describe the later data correctly
BadLengthDescriptor,
/// Error from std::io
&NetAddress::OnionV3 { .. } => { 37 },
}
}
+
+ /// The maximum length of any address descriptor, not including the 1-byte type
+ pub(crate) const MAX_LEN: u16 = 37;
}
impl Writeable for NetAddress {
fn handle_htlc_fail_channel_update(&self, update: &HTLCFailChannelUpdate);
/// Gets a subset of the channel announcements and updates required to dump our routing table
/// to a remote node, starting at the short_channel_id indicated by starting_point and
- /// including batch_amount entries.
+ /// including the batch_amount entries immediately higher in numerical value than starting_point.
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, ChannelUpdate, ChannelUpdate)>;
/// Gets a subset of the node announcements required to dump our routing table to a remote node,
- /// starting at the node *after* the provided publickey and including batch_amount entries.
+ /// starting at the node *after* the provided publickey and including batch_amount entries
+ /// immediately higher (as defined by <PublicKey as Ord>::cmp) than starting_point.
/// If None is provided for starting_point, we start at the first node.
fn get_next_node_announcements(&self, starting_point: Option<&PublicKey>, batch_amount: u8) -> Vec<NodeAnnouncement>;
/// Returns whether a full sync should be requested from a peer.
DecodeError::UnknownRequiredFeature => "Unknown required feature preventing decode",
DecodeError::InvalidValue => "Nonsense bytes didn't map to the type they were interpreted as",
DecodeError::ShortRead => "Packet extended beyond the provided bytes",
- DecodeError::ExtraAddressesPerType => "More than one address of a single type",
DecodeError::BadLengthDescriptor => "A length descriptor in the packet didn't describe the later data correctly",
DecodeError::Io(ref e) => e.description(),
}
self.alias.write(w)?;
let mut addrs_to_encode = self.addresses.clone();
- addrs_to_encode.sort_unstable_by(|a, b| { a.get_id().cmp(&b.get_id()) });
- addrs_to_encode.dedup_by(|a, b| { a.get_id() == b.get_id() });
+ addrs_to_encode.sort_by(|a, b| { a.get_id().cmp(&b.get_id()) });
let mut addr_len = 0;
for addr in &addrs_to_encode {
addr_len += 1 + addr.len();
let alias: [u8; 32] = Readable::read(r)?;
let addr_len: u16 = Readable::read(r)?;
- let mut addresses: Vec<NetAddress> = Vec::with_capacity(4);
+ let mut addresses: Vec<NetAddress> = Vec::new();
+ let mut highest_addr_type = 0;
let mut addr_readpos = 0;
let mut excess = false;
let mut excess_byte = 0;
if addr_len <= addr_readpos { break; }
match Readable::read(r) {
Ok(Ok(addr)) => {
- match addr {
- NetAddress::IPv4 { .. } => {
- if addresses.len() > 0 {
- return Err(DecodeError::ExtraAddressesPerType);
- }
- },
- NetAddress::IPv6 { .. } => {
- if addresses.len() > 1 || (addresses.len() == 1 && addresses[0].get_id() != 1) {
- return Err(DecodeError::ExtraAddressesPerType);
- }
- },
- NetAddress::OnionV2 { .. } => {
- if addresses.len() > 2 || (addresses.len() > 0 && addresses.last().unwrap().get_id() > 2) {
- return Err(DecodeError::ExtraAddressesPerType);
- }
- },
- NetAddress::OnionV3 { .. } => {
- if addresses.len() > 3 || (addresses.len() > 0 && addresses.last().unwrap().get_id() > 3) {
- return Err(DecodeError::ExtraAddressesPerType);
- }
- },
+ if addr.get_id() < highest_addr_type {
+ // Addresses must be sorted in increasing order
+ return Err(DecodeError::InvalidValue);
}
+ highest_addr_type = addr.get_id();
if addr_len < addr_readpos + 1 + addr.len() {
return Err(DecodeError::BadLengthDescriptor);
}
impl_writeable_len_match!(NodeAnnouncement, {
{ NodeAnnouncement { contents: UnsignedNodeAnnouncement { ref features, ref addresses, ref excess_address_data, ref excess_data, ..}, .. },
- 64 + 76 + features.byte_count() + addresses.len()*38 + excess_address_data.len() + excess_data.len() }
+ 64 + 76 + features.byte_count() + addresses.len()*(NetAddress::MAX_LEN as usize + 1) + excess_address_data.len() + excess_data.len() }
}, {
signature,
contents
/// announcements/updates for the given channel_id then we will send it when we get to that
/// point and we shouldn't send it yet to avoid sending duplicate updates. If we've already
/// sent the old versions, we should send the update, and so return true here.
- fn should_forward_channel(&self, channel_id: u64)->bool{
+ fn should_forward_channel_announcement(&self, channel_id: u64)->bool{
match self.sync_status {
InitSyncTracker::NoSyncRequested => true,
InitSyncTracker::ChannelsSyncing(i) => i < channel_id,
InitSyncTracker::NodesSyncing(_) => true,
}
}
+
+ /// Similar to the above, but for node announcements indexed by node_id.
+ fn should_forward_node_announcement(&self, node_id: PublicKey) -> bool {
+ match self.sync_status {
+ InitSyncTracker::NoSyncRequested => true,
+ InitSyncTracker::ChannelsSyncing(_) => false,
+ InitSyncTracker::NodesSyncing(pk) => pk < node_id,
+ }
+ }
}
struct PeerHolder<Descriptor: SocketDescriptor> {
log_debug!(self, "Deserialization failed due to shortness of message");
return Err(PeerHandleError { no_connection_possible: false });
}
- msgs::DecodeError::ExtraAddressesPerType => {
- log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407");
- continue;
- }
msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }),
msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }),
}
for (ref descriptor, ref mut peer) in peers.peers.iter_mut() {
if !peer.channel_encryptor.is_ready_for_encryption() || peer.their_features.is_none() ||
- !peer.should_forward_channel(msg.contents.short_channel_id) {
+ !peer.should_forward_channel_announcement(msg.contents.short_channel_id) {
continue
}
match peer.their_node_id {
}
}
},
+ MessageSendEvent::BroadcastNodeAnnouncement { ref msg } => {
+ log_trace!(self, "Handling BroadcastNodeAnnouncement event in peer_handler");
+ if self.message_handler.route_handler.handle_node_announcement(msg).is_ok() {
+ let encoded_msg = encode_msg!(msg);
+
+ for (ref descriptor, ref mut peer) in peers.peers.iter_mut() {
+ if !peer.channel_encryptor.is_ready_for_encryption() || peer.their_features.is_none() ||
+ !peer.should_forward_node_announcement(msg.contents.node_id) {
+ continue
+ }
+ peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_msg[..]));
+ self.do_attempt_write_data(&mut (*descriptor).clone(), peer);
+ }
+ }
+ },
MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
log_trace!(self, "Handling BroadcastChannelUpdate event in peer_handler for short channel id {}", msg.contents.short_channel_id);
if self.message_handler.route_handler.handle_channel_update(msg).is_ok() {
for (ref descriptor, ref mut peer) in peers.peers.iter_mut() {
if !peer.channel_encryptor.is_ready_for_encryption() || peer.their_features.is_none() ||
- !peer.should_forward_channel(msg.contents.short_channel_id) {
+ !peer.should_forward_channel_announcement(msg.contents.short_channel_id) {
continue
}
peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_msg[..]));
lowest_inbound_channel_fee_proportional_millionths: u32,
features: NodeFeatures,
- last_update: u32,
+ /// Unlike for channels, we may have a NodeInfo entry before having received a node_update.
+ /// Thus, we have to be able to capture "no update has been received", which we do with an
+ /// Option here.
+ last_update: Option<u32>,
rgb: [u8; 3],
alias: [u8; 32],
addresses: Vec<NetAddress>,
impl std::fmt::Display for NodeInfo {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
- write!(f, "features: {}, last_update: {}, lowest_inbound_channel_fee_base_msat: {}, lowest_inbound_channel_fee_proportional_millionths: {}, channels: {:?}", log_bytes!(self.features.encode()), self.last_update, self.lowest_inbound_channel_fee_base_msat, self.lowest_inbound_channel_fee_proportional_millionths, &self.channels[..])?;
+ write!(f, "features: {}, last_update: {:?}, lowest_inbound_channel_fee_base_msat: {}, lowest_inbound_channel_fee_proportional_millionths: {}, channels: {:?}", log_bytes!(self.features.encode()), self.last_update, self.lowest_inbound_channel_fee_base_msat, self.lowest_inbound_channel_fee_proportional_millionths, &self.channels[..])?;
Ok(())
}
}
match network.nodes.get_mut(&msg.contents.node_id) {
None => Err(LightningError{err: "No existing channels for node_announcement", action: ErrorAction::IgnoreError}),
Some(node) => {
- if node.last_update >= msg.contents.timestamp {
- return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
+ match node.last_update {
+ Some(last_update) => if last_update >= msg.contents.timestamp {
+ return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
+ },
+ None => {},
}
node.features = msg.contents.features.clone();
- node.last_update = msg.contents.timestamp;
+ node.last_update = Some(msg.contents.timestamp);
node.rgb = msg.contents.rgb;
node.alias = msg.contents.alias;
node.addresses = msg.contents.addresses.clone();
lowest_inbound_channel_fee_base_msat: u32::max_value(),
lowest_inbound_channel_fee_proportional_millionths: u32::max_value(),
features: NodeFeatures::empty(),
- last_update: 0,
+ last_update: None,
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: u32::max_value(),
lowest_inbound_channel_fee_proportional_millionths: u32::max_value(),
features: NodeFeatures::empty(),
- last_update: 0,
+ last_update: None,
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 100,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(1)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(2)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(8)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(3)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(4)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(5)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(6)),
- last_update: 1,
+ last_update: Some(1),
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
},
/// Used to indicate that a channel_announcement and channel_update should be broadcast to all
/// peers (except the peer with node_id either msg.contents.node_id_1 or msg.contents.node_id_2).
+ ///
+ /// Note that after doing so, you very likely (unless you did so very recently) want to call
+ /// ChannelManager::broadcast_node_announcement to trigger a BroadcastNodeAnnouncement event.
+ /// This ensures that any nodes which see our channel_announcement also have a relevant
+ /// node_announcement, including relevant feature flags which may be important for routing
+ /// through or to us.
BroadcastChannelAnnouncement {
/// The channel_announcement which should be sent.
msg: msgs::ChannelAnnouncement,
/// The followup channel_update which should be sent.
update_msg: msgs::ChannelUpdate,
},
+ /// Used to indicate that a node_announcement should be broadcast to all peers.
+ BroadcastNodeAnnouncement {
+ /// The node_announcement which should be sent.
+ msg: msgs::NodeAnnouncement,
+ },
/// Used to indicate that a channel_update should be broadcast to all peers.
BroadcastChannelUpdate {
/// The channel_update which should be sent.