X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Fgossip.rs;h=c15a7547b996e455bfc752b8befae2ab83b86c84;hb=0c250468d632ed6df93d8a9d34389a2cb61eac40;hp=5ac2f9ed6979c6509ca9b070d2f5a8f658a0081f;hpb=142fdca66e82750b0b023158d9ef5ad7979d168b;p=rust-lightning diff --git a/lightning/src/routing/gossip.rs b/lightning/src/routing/gossip.rs index 5ac2f9ed..c15a7547 100644 --- a/lightning/src/routing/gossip.rs +++ b/lightning/src/routing/gossip.rs @@ -10,7 +10,7 @@ //! The [`NetworkGraph`] stores the network gossip and [`P2PGossipSync`] fetches it from peers use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE; -use bitcoin::secp256k1::PublicKey; +use bitcoin::secp256k1::{PublicKey, Verification}; use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1; @@ -88,12 +88,12 @@ impl NodeId { impl fmt::Debug for NodeId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "NodeId({})", log_bytes!(self.0)) + write!(f, "NodeId({})", crate::util::logger::DebugBytes(&self.0)) } } impl fmt::Display for NodeId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", log_bytes!(self.0)) + crate::util::logger::DebugBytes(&self.0).fmt(f) } } @@ -409,6 +409,29 @@ macro_rules! get_pubkey_from_node_id { } } +/// Verifies the signature of a [`NodeAnnouncement`]. +/// +/// Returns an error if it is invalid. +pub fn verify_node_announcement(msg: &NodeAnnouncement, secp_ctx: &Secp256k1) -> Result<(), LightningError> { + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &get_pubkey_from_node_id!(msg.contents.node_id, "node_announcement"), "node_announcement"); + + Ok(()) +} + +/// Verifies all signatures included in a [`ChannelAnnouncement`]. +/// +/// Returns an error if one of the signatures is invalid. +pub fn verify_channel_announcement(msg: &ChannelAnnouncement, secp_ctx: &Secp256k1) -> Result<(), LightningError> { + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &get_pubkey_from_node_id!(msg.contents.node_id_1, "channel_announcement"), "channel_announcement"); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &get_pubkey_from_node_id!(msg.contents.node_id_2, "channel_announcement"), "channel_announcement"); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_1, "channel_announcement"), "channel_announcement"); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_2, "channel_announcement"), "channel_announcement"); + + Ok(()) +} + impl>, U: Deref, L: Deref> RoutingMessageHandler for P2PGossipSync where U::Target: UtxoLookup, L::Target: Logger { @@ -876,7 +899,7 @@ impl ChannelInfo { impl fmt::Display for ChannelInfo { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "features: {}, node_one: {}, one_to_two: {:?}, node_two: {}, two_to_one: {:?}", - log_bytes!(self.features.encode()), log_bytes!(self.node_one.as_slice()), self.one_to_two, log_bytes!(self.node_two.as_slice()), self.two_to_one)?; + log_bytes!(self.features.encode()), &self.node_one, self.one_to_two, &self.node_two, self.two_to_one)?; Ok(()) } } @@ -970,7 +993,7 @@ impl<'a> DirectedChannelInfo<'a> { htlc_maximum_msat = cmp::min(htlc_maximum_msat, capacity_msat); EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: htlc_maximum_msat } }, - None => EffectiveCapacity::MaximumHTLC { amount_msat: htlc_maximum_msat }, + None => EffectiveCapacity::AdvertisedMaxHTLC { amount_msat: htlc_maximum_msat }, }; Self { @@ -1024,7 +1047,7 @@ pub enum EffectiveCapacity { liquidity_msat: u64, }, /// The maximum HTLC amount in one direction as advertised on the gossip network. - MaximumHTLC { + AdvertisedMaxHTLC { /// The maximum HTLC amount denominated in millisatoshi. amount_msat: u64, }, @@ -1038,6 +1061,11 @@ pub enum EffectiveCapacity { /// A capacity sufficient to route any payment, typically used for private channels provided by /// an invoice. Infinite, + /// The maximum HTLC amount as provided by an invoice route hint. + HintMaxHTLC { + /// The maximum HTLC amount denominated in millisatoshi. + amount_msat: u64, + }, /// A capacity that is unknown possibly because either the chain state is unavailable to know /// the total capacity or the `htlc_maximum_msat` was not advertised on the gossip network. Unknown, @@ -1052,8 +1080,9 @@ impl EffectiveCapacity { pub fn as_msat(&self) -> u64 { match self { EffectiveCapacity::ExactLiquidity { liquidity_msat } => *liquidity_msat, - EffectiveCapacity::MaximumHTLC { amount_msat } => *amount_msat, + EffectiveCapacity::AdvertisedMaxHTLC { amount_msat } => *amount_msat, EffectiveCapacity::Total { capacity_msat, .. } => *capacity_msat, + EffectiveCapacity::HintMaxHTLC { amount_msat } => *amount_msat, EffectiveCapacity::Infinite => u64::max_value(), EffectiveCapacity::Unknown => UNKNOWN_CHANNEL_CAPACITY_MSAT, } @@ -1114,26 +1143,26 @@ impl Writeable for NodeAnnouncementInfo { (4, self.rgb, required), (6, self.alias, required), (8, self.announcement_message, option), - (10, empty_addresses, vec_type), // Versions prior to 0.0.115 require this field + (10, empty_addresses, required_vec), // Versions prior to 0.0.115 require this field }); Ok(()) } } impl Readable for NodeAnnouncementInfo { - fn read(reader: &mut R) -> Result { + fn read(reader: &mut R) -> Result { _init_and_read_tlv_fields!(reader, { (0, features, required), (2, last_update, required), (4, rgb, required), (6, alias, required), (8, announcement_message, option), - (10, _addresses, vec_type), // deprecated, not used anymore + (10, _addresses, optional_vec), // deprecated, not used anymore }); let _: Option> = _addresses; Ok(Self { features: features.0.unwrap(), last_update: last_update.0.unwrap(), rgb: rgb.0.unwrap(), alias: alias.0.unwrap(), announcement_message }) - } + } } /// A user-defined name for a node, which may be used when displaying the node in a graph. @@ -1199,7 +1228,7 @@ impl Writeable for NodeInfo { write_tlv_fields!(writer, { // Note that older versions of LDK wrote the lowest inbound fees here at type 0 (2, self.announcement_info, option), - (4, self.channels, vec_type), + (4, self.channels, required_vec), }); Ok(()) } @@ -1230,19 +1259,17 @@ impl Readable for NodeInfo { // with zero inbound fees, causing that heuristic to provide little gain. Worse, because it // requires additional complexity and lookups during routing, it ends up being a // performance loss. Thus, we simply ignore the old field here and no longer track it. - let mut _lowest_inbound_channel_fees: Option = None; - let mut announcement_info_wrap: Option = None; - _init_tlv_field_var!(channels, vec_type); - - read_tlv_fields!(reader, { + _init_and_read_tlv_fields!(reader, { (0, _lowest_inbound_channel_fees, option), (2, announcement_info_wrap, upgradable_option), - (4, channels, vec_type), + (4, channels, required_vec), }); + let _: Option = _lowest_inbound_channel_fees; + let announcement_info_wrap: Option = announcement_info_wrap; Ok(NodeInfo { announcement_info: announcement_info_wrap.map(|w| w.0), - channels: _init_tlv_based_struct_field!(channels, vec_type), + channels, }) } } @@ -1323,7 +1350,7 @@ impl fmt::Display for NetworkGraph where L::Target: Logger { } writeln!(f, "[Nodes]")?; for (&node_id, val) in self.nodes.read().unwrap().unordered_iter() { - writeln!(f, " {}: {}", log_bytes!(node_id.as_slice()), val)?; + writeln!(f, " {}: {}", &node_id, val)?; } Ok(()) } @@ -1397,8 +1424,7 @@ impl NetworkGraph where L::Target: Logger { /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept /// routing messages from a source using a protocol other than the lightning P2P protocol. pub fn update_node_from_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<(), LightningError> { - let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); - secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &get_pubkey_from_node_id!(msg.contents.node_id, "node_announcement"), "node_announcement"); + verify_node_announcement(msg, &self.secp_ctx)?; self.update_node_from_announcement_intern(&msg.contents, Some(&msg)) } @@ -1461,11 +1487,7 @@ impl NetworkGraph where L::Target: Logger { where U::Target: UtxoLookup, { - let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); - secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_1, &get_pubkey_from_node_id!(msg.contents.node_id_1, "channel_announcement"), "channel_announcement"); - secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_2, &get_pubkey_from_node_id!(msg.contents.node_id_2, "channel_announcement"), "channel_announcement"); - secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_1, "channel_announcement"), "channel_announcement"); - secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_2, "channel_announcement"), "channel_announcement"); + verify_channel_announcement(msg, &self.secp_ctx)?; self.update_channel_from_unsigned_announcement_intern(&msg.contents, Some(msg), utxo_lookup) } @@ -1531,6 +1553,8 @@ impl NetworkGraph where L::Target: Logger { let node_id_a = channel_info.node_one.clone(); let node_id_b = channel_info.node_two.clone(); + log_gossip!(self.logger, "Adding channel {} between nodes {} and {}", short_channel_id, node_id_a, node_id_b); + match channels.entry(short_channel_id) { IndexedMapEntry::Occupied(mut entry) => { //TODO: because asking the blockchain if short_channel_id is valid is only optional @@ -1585,7 +1609,7 @@ impl NetworkGraph where L::Target: Logger { if msg.chain_hash != self.genesis_hash { return Err(LightningError { - err: "Channel announcement chain hash does not match genesis hash".to_owned(), + err: "Channel announcement chain hash does not match genesis hash".to_owned(), action: ErrorAction::IgnoreAndLog(Level::Debug), }); } @@ -1766,16 +1790,23 @@ impl NetworkGraph where L::Target: Logger { let mut scids_to_remove = Vec::new(); for (scid, info) in channels.unordered_iter_mut() { if info.one_to_two.is_some() && info.one_to_two.as_ref().unwrap().last_update < min_time_unix { + log_gossip!(self.logger, "Removing directional update one_to_two (0) for channel {} due to its timestamp {} being below {}", + scid, info.one_to_two.as_ref().unwrap().last_update, min_time_unix); info.one_to_two = None; } if info.two_to_one.is_some() && info.two_to_one.as_ref().unwrap().last_update < min_time_unix { + log_gossip!(self.logger, "Removing directional update two_to_one (1) for channel {} due to its timestamp {} being below {}", + scid, info.two_to_one.as_ref().unwrap().last_update, min_time_unix); info.two_to_one = None; } if info.one_to_two.is_none() || info.two_to_one.is_none() { // We check the announcement_received_time here to ensure we don't drop // announcements that we just received and are just waiting for our peer to send a // channel_update for. - if info.announcement_received_time < min_time_unix as u64 { + let announcement_received_timestamp = info.announcement_received_time; + if announcement_received_timestamp < min_time_unix as u64 { + log_gossip!(self.logger, "Removing channel {} because both directional updates are missing and its announcement timestamp {} being below {}", + scid, announcement_received_timestamp, min_time_unix); scids_to_remove.push(*scid); } } @@ -1856,6 +1887,8 @@ impl NetworkGraph where L::Target: Logger { } } + log_gossip!(self.logger, "Updating channel {} in direction {} with timestamp {}", msg.short_channel_id, msg.flags & 1, msg.timestamp); + let mut channels = self.channels.write().unwrap(); match channels.get_mut(&msg.short_channel_id) { None => { @@ -2895,7 +2928,7 @@ pub(crate) mod tests { // It should ignore if gossip_queries feature is not enabled { - let init_msg = Init { features: InitFeatures::empty(), remote_network_address: None }; + let init_msg = Init { features: InitFeatures::empty(), networks: None, remote_network_address: None }; gossip_sync.peer_connected(&node_id_1, &init_msg, true).unwrap(); let events = gossip_sync.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 0); @@ -2905,7 +2938,7 @@ pub(crate) mod tests { { let mut features = InitFeatures::empty(); features.set_gossip_queries_optional(); - let init_msg = Init { features, remote_network_address: None }; + let init_msg = Init { features, networks: None, remote_network_address: None }; gossip_sync.peer_connected(&node_id_1, &init_msg, true).unwrap(); let events = gossip_sync.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); @@ -3396,6 +3429,12 @@ pub(crate) mod tests { // This serialized info has an address field but no announcement_message, therefore the addresses returned by our function will still be empty assert!(ann_info_with_addresses.addresses().is_empty()); } + + #[test] + fn test_node_id_display() { + let node_id = NodeId([42; 33]); + assert_eq!(format!("{}", &node_id), "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"); + } } #[cfg(ldk_bench)]