X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Fgossip.rs;h=59268b840cd4c411b7a1545905bf17a4b6a24be0;hb=15050895fd409ff8b01092dc2db30d8222063631;hp=48fcd81578395a152c8e61ed0ed6bf4639ea9cd2;hpb=9f8e832c7b2a48f6cbc58165b16b6f79e9ca329c;p=rust-lightning diff --git a/lightning/src/routing/gossip.rs b/lightning/src/routing/gossip.rs index 48fcd815..59268b84 100644 --- a/lightning/src/routing/gossip.rs +++ b/lightning/src/routing/gossip.rs @@ -16,11 +16,13 @@ use bitcoin::secp256k1; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hashes::Hash; +use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::BlockHash; use bitcoin::network::constants::Network; use bitcoin::blockdata::constants::genesis_block; +use crate::events::{MessageSendEvent, MessageSendEventsProvider}; use crate::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures}; use crate::ln::msgs::{DecodeError, ErrorAction, Init, LightningError, RoutingMessageHandler, NetAddress, MAX_VALUE_MSAT}; use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, GossipTimestampFilter}; @@ -29,7 +31,6 @@ use crate::ln::msgs; use crate::routing::utxo::{self, UtxoLookup}; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, MaybeReadable}; use crate::util::logger::{Logger, Level}; -use crate::util::events::{MessageSendEvent, MessageSendEventsProvider}; use crate::util::scid_utils::{block_from_scid, scid_from_parts, MAX_SCID_BLOCK}; use crate::util::string::PrintableString; use crate::util::indexed_map::{IndexedMap, Entry as IndexedMapEntry}; @@ -38,11 +39,13 @@ use crate::io; use crate::io_extras::{copy, sink}; use crate::prelude::*; use core::{cmp, fmt}; +use core::convert::TryFrom; use crate::sync::{RwLock, RwLockReadGuard}; #[cfg(feature = "std")] use core::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::Mutex; use core::ops::{Bound, Deref}; +use core::str::FromStr; #[cfg(feature = "std")] use std::time::{SystemTime, UNIX_EPOCH}; @@ -76,6 +79,11 @@ impl NodeId { pub fn as_slice(&self) -> &[u8] { &self.0 } + + /// Get the public key from this NodeId + pub fn as_pubkey(&self) -> Result { + PublicKey::from_slice(&self.0) + } } impl fmt::Debug for NodeId { @@ -130,6 +138,29 @@ impl Readable for NodeId { } } +impl From for NodeId { + fn from(pubkey: PublicKey) -> Self { + Self::from_pubkey(&pubkey) + } +} + +impl TryFrom for PublicKey { + type Error = secp256k1::Error; + + fn try_from(node_id: NodeId) -> Result { + node_id.as_pubkey() + } +} + +impl FromStr for NodeId { + type Err = bitcoin::hashes::hex::Error; + + fn from_str(s: &str) -> Result { + let data: [u8; PUBLIC_KEY_SIZE] = FromHex::from_hex(s)?; + Ok(NodeId(data)) + } +} + /// Represents the network as nodes and channels between them pub struct NetworkGraph where L::Target: Logger { secp_ctx: Secp256k1, @@ -258,7 +289,7 @@ where U::Target: UtxoLookup, L::Target: Logger /// Gets a reference to the underlying [`NetworkGraph`] which was provided in /// [`P2PGossipSync::new`]. /// - /// (C-not exported) as bindings don't support a reference-to-a-reference yet + /// This is not exported to bindings users as bindings don't support a reference-to-a-reference yet pub fn network_graph(&self) -> &G { &self.network_graph } @@ -310,7 +341,7 @@ where U::Target: UtxoLookup, L::Target: Logger impl NetworkGraph where L::Target: Logger { /// Handles any network updates originating from [`Event`]s. /// - /// [`Event`]: crate::util::events::Event + /// [`Event`]: crate::events::Event pub fn handle_network_update(&self, network_update: &NetworkUpdate) { match *network_update { NetworkUpdate::ChannelUpdateMessage { ref msg } => { @@ -1052,8 +1083,6 @@ pub struct NodeAnnouncementInfo { /// May be invalid or malicious (eg control chars), /// should not be exposed to the user. pub alias: NodeAlias, - /// Internet-level addresses via which one can connect to the node - pub addresses: Vec, /// An initial announcement of the node /// Mostly redundant with the data we store in fields explicitly. /// Everything else is useful only for sending out for initial routing sync. @@ -1061,20 +1090,51 @@ pub struct NodeAnnouncementInfo { pub announcement_message: Option } -impl_writeable_tlv_based!(NodeAnnouncementInfo, { - (0, features, required), - (2, last_update, required), - (4, rgb, required), - (6, alias, required), - (8, announcement_message, option), - (10, addresses, vec_type), -}); +impl NodeAnnouncementInfo { + /// Internet-level addresses via which one can connect to the node + pub fn addresses(&self) -> &[NetAddress] { + self.announcement_message.as_ref() + .map(|msg| msg.contents.addresses.as_slice()) + .unwrap_or_default() + } +} + +impl Writeable for NodeAnnouncementInfo { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let empty_addresses = Vec::::new(); + write_tlv_fields!(writer, { + (0, self.features, required), + (2, self.last_update, required), + (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 + }); + Ok(()) + } +} + +impl Readable for NodeAnnouncementInfo { + 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 + }); + 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. /// /// Since node aliases are provided by third parties, they are a potential avenue for injection /// attacks. Care must be taken when processing. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct NodeAlias(pub [u8; 32]); impl fmt::Display for NodeAlias { @@ -1139,7 +1199,7 @@ impl Writeable for NodeInfo { } } -// A wrapper allowing for the optional deseralization of `NodeAnnouncementInfo`. Utilizing this is +// A wrapper allowing for the optional deserialization of `NodeAnnouncementInfo`. Utilizing this is // necessary to maintain compatibility with previous serializations of `NetAddress` that have an // invalid hostname set. We ignore and eat all errors until we are either able to read a // `NodeAnnouncementInfo` or hit a `ShortRead`, i.e., read the TLV field to the end. @@ -1367,8 +1427,7 @@ impl NetworkGraph where L::Target: Logger { features: msg.features.clone(), last_update: msg.timestamp, rgb: msg.rgb, - alias: NodeAlias(msg.alias), - addresses: msg.addresses.clone(), + alias: msg.alias, announcement_message: if should_relay { full_msg.cloned() } else { None }, }); @@ -1884,7 +1943,7 @@ impl NetworkGraph where L::Target: Logger { impl ReadOnlyNetworkGraph<'_> { /// Returns all known valid channels' short ids along with announced channel info. /// - /// (C-not exported) because we don't want to return lifetime'd references + /// This is not exported to bindings users because we don't want to return lifetime'd references pub fn channels(&self) -> &IndexedMap { &*self.channels } @@ -1902,7 +1961,7 @@ impl ReadOnlyNetworkGraph<'_> { /// Returns all known nodes' public keys along with announced node info. /// - /// (C-not exported) because we don't want to return lifetime'd references + /// This is not exported to bindings users because we don't want to return lifetime'd references pub fn nodes(&self) -> &IndexedMap { &*self.nodes } @@ -1922,17 +1981,14 @@ impl ReadOnlyNetworkGraph<'_> { /// Returns None if the requested node is completely unknown, /// or if node announcement for the node was never received. pub fn get_addresses(&self, pubkey: &PublicKey) -> Option> { - if let Some(node) = self.nodes.get(&NodeId::from_pubkey(&pubkey)) { - if let Some(node_info) = node.announcement_info.as_ref() { - return Some(node_info.addresses.clone()) - } - } - None + self.nodes.get(&NodeId::from_pubkey(&pubkey)) + .and_then(|node| node.announcement_info.as_ref().map(|ann| ann.addresses().to_vec())) } } #[cfg(test)] pub(crate) mod tests { + use crate::events::{MessageSendEvent, MessageSendEventsProvider}; use crate::ln::channelmanager; use crate::ln::chan_utils::make_funding_redeemscript; #[cfg(feature = "std")] @@ -1944,8 +2000,7 @@ pub(crate) mod tests { ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT}; use crate::util::config::UserConfig; use crate::util::test_utils; - use crate::util::ser::{ReadableArgs, Writeable}; - use crate::util::events::{MessageSendEvent, MessageSendEventsProvider}; + use crate::util::ser::{ReadableArgs, Readable, Writeable}; use crate::util::scid_utils::scid_from_parts; use crate::routing::gossip::REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS; @@ -2005,7 +2060,7 @@ pub(crate) mod tests { timestamp: 100, node_id, rgb: [0; 3], - alias: [0; 32], + alias: NodeAlias([0; 32]), addresses: Vec::new(), excess_address_data: Vec::new(), excess_data: Vec::new(), @@ -3250,26 +3305,25 @@ pub(crate) mod tests { #[test] fn node_info_is_readable() { - use std::convert::TryFrom; - // 1. Check we can read a valid NodeAnnouncementInfo and fail on an invalid one - let valid_netaddr = crate::ln::msgs::NetAddress::Hostname { hostname: crate::util::ser::Hostname::try_from("A".to_string()).unwrap(), port: 1234 }; + let announcement_message = hex::decode("d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a000122013413a7031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f2020201010101010101010101010101010101010101010101010101010101010101010000701fffefdfc2607").unwrap(); + let announcement_message = NodeAnnouncement::read(&mut announcement_message.as_slice()).unwrap(); let valid_node_ann_info = NodeAnnouncementInfo { features: channelmanager::provided_node_features(&UserConfig::default()), last_update: 0, rgb: [0u8; 3], alias: NodeAlias([0u8; 32]), - addresses: vec![valid_netaddr], - announcement_message: None, + announcement_message: Some(announcement_message) }; let mut encoded_valid_node_ann_info = Vec::new(); assert!(valid_node_ann_info.write(&mut encoded_valid_node_ann_info).is_ok()); - let read_valid_node_ann_info: NodeAnnouncementInfo = crate::util::ser::Readable::read(&mut encoded_valid_node_ann_info.as_slice()).unwrap(); + let read_valid_node_ann_info = NodeAnnouncementInfo::read(&mut encoded_valid_node_ann_info.as_slice()).unwrap(); assert_eq!(read_valid_node_ann_info, valid_node_ann_info); + assert_eq!(read_valid_node_ann_info.addresses().len(), 1); let encoded_invalid_node_ann_info = hex::decode("3f0009000788a000080a51a20204000000000403000000062000000000000000000000000000000000000000000000000000000000000000000a0505014004d2").unwrap(); - let read_invalid_node_ann_info_res: Result = crate::util::ser::Readable::read(&mut encoded_invalid_node_ann_info.as_slice()); + let read_invalid_node_ann_info_res = NodeAnnouncementInfo::read(&mut encoded_invalid_node_ann_info.as_slice()); assert!(read_invalid_node_ann_info_res.is_err()); // 2. Check we can read a NodeInfo anyways, but set the NodeAnnouncementInfo to None if invalid @@ -3280,13 +3334,22 @@ pub(crate) mod tests { let mut encoded_valid_node_info = Vec::new(); assert!(valid_node_info.write(&mut encoded_valid_node_info).is_ok()); - let read_valid_node_info: NodeInfo = crate::util::ser::Readable::read(&mut encoded_valid_node_info.as_slice()).unwrap(); + let read_valid_node_info = NodeInfo::read(&mut encoded_valid_node_info.as_slice()).unwrap(); assert_eq!(read_valid_node_info, valid_node_info); let encoded_invalid_node_info_hex = hex::decode("4402403f0009000788a000080a51a20204000000000403000000062000000000000000000000000000000000000000000000000000000000000000000a0505014004d20400").unwrap(); - let read_invalid_node_info: NodeInfo = crate::util::ser::Readable::read(&mut encoded_invalid_node_info_hex.as_slice()).unwrap(); + let read_invalid_node_info = NodeInfo::read(&mut encoded_invalid_node_info_hex.as_slice()).unwrap(); assert_eq!(read_invalid_node_info.announcement_info, None); } + + #[test] + fn test_node_info_keeps_compatibility() { + let old_ann_info_with_addresses = hex::decode("3f0009000708a000080a51220204000000000403000000062000000000000000000000000000000000000000000000000000000000000000000a0505014104d2").unwrap(); + let ann_info_with_addresses = NodeAnnouncementInfo::read(&mut old_ann_info_with_addresses.as_slice()) + .expect("to be able to read an old NodeAnnouncementInfo with addresses"); + // 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()); + } } #[cfg(all(test, feature = "_bench_unstable"))]