X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Fgossip.rs;h=716ca2b305f3a48da3b5c698c571b11fed2fcdd0;hb=daeb5a62914fef04d9d51e8d30ced9d6c1103b42;hp=f404e77b2b825ba894e4a193d693eb222cbbf769;hpb=7adf2c7f5f1e1c4a72108dcc30899a6ed6964c76;p=rust-lightning diff --git a/lightning/src/routing/gossip.rs b/lightning/src/routing/gossip.rs index f404e77b..716ca2b3 100644 --- a/lightning/src/routing/gossip.rs +++ b/lightning/src/routing/gossip.rs @@ -250,7 +250,7 @@ where C::Target: chain::Access, L::Target: Logger impl EventHandler for NetworkGraph where L::Target: Logger { fn handle_event(&self, event: &Event) { - if let Event::PaymentPathFailed { payment_hash: _, rejected_by_dest: _, network_update, .. } = event { + if let Event::PaymentPathFailed { network_update, .. } = event { if let Some(network_update) = network_update { match *network_update { NetworkUpdate::ChannelUpdateMessage { ref msg } => { @@ -745,13 +745,13 @@ impl<'a> DirectedChannelInfo<'a> { let (htlc_maximum_msat, effective_capacity) = match (htlc_maximum_msat, capacity_msat) { (Some(amount_msat), Some(capacity_msat)) => { let htlc_maximum_msat = cmp::min(amount_msat, capacity_msat); - (htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat }) + (htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) }) }, (Some(amount_msat), None) => { (amount_msat, EffectiveCapacity::MaximumHTLC { amount_msat }) }, (None, Some(capacity_msat)) => { - (capacity_msat, EffectiveCapacity::Total { capacity_msat }) + (capacity_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: None }) }, (None, None) => (EffectiveCapacity::Unknown.as_msat(), EffectiveCapacity::Unknown), }; @@ -850,6 +850,8 @@ pub enum EffectiveCapacity { Total { /// The funding amount denominated in millisatoshi. capacity_msat: u64, + /// The maximum HTLC amount denominated in millisatoshi. + htlc_maximum_msat: Option }, /// A capacity sufficient to route any payment, typically used for private channels provided by /// an invoice. @@ -869,7 +871,7 @@ impl EffectiveCapacity { match self { EffectiveCapacity::ExactLiquidity { liquidity_msat } => *liquidity_msat, EffectiveCapacity::MaximumHTLC { amount_msat } => *amount_msat, - EffectiveCapacity::Total { capacity_msat } => *capacity_msat, + EffectiveCapacity::Total { capacity_msat, .. } => *capacity_msat, EffectiveCapacity::Infinite => u64::max_value(), EffectiveCapacity::Unknown => UNKNOWN_CHANNEL_CAPACITY_MSAT, } @@ -904,7 +906,7 @@ pub struct NodeAnnouncementInfo { /// Moniker assigned to the node. /// May be invalid or malicious (eg control chars), /// should not be exposed to the user. - pub alias: [u8; 32], + pub alias: NodeAlias, /// Internet-level addresses via which one can connect to the node pub addresses: Vec, /// An initial announcement of the node @@ -923,6 +925,51 @@ impl_writeable_tlv_based!(NodeAnnouncementInfo, { (10, addresses, vec_type), }); +/// 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)] +pub struct NodeAlias(pub [u8; 32]); + +impl fmt::Display for NodeAlias { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let control_symbol = core::char::REPLACEMENT_CHARACTER; + let first_null = self.0.iter().position(|b| *b == 0).unwrap_or(self.0.len()); + let bytes = self.0.split_at(first_null).0; + match core::str::from_utf8(bytes) { + Ok(alias) => { + for c in alias.chars() { + let mut bytes = [0u8; 4]; + let c = if !c.is_control() { c } else { control_symbol }; + f.write_str(c.encode_utf8(&mut bytes))?; + } + }, + Err(_) => { + for c in bytes.iter().map(|b| *b as char) { + // Display printable ASCII characters + let mut bytes = [0u8; 4]; + let c = if c >= '\x20' && c <= '\x7e' { c } else { control_symbol }; + f.write_str(c.encode_utf8(&mut bytes))?; + } + }, + }; + Ok(()) + } +} + +impl Writeable for NodeAlias { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.write(w) + } +} + +impl Readable for NodeAlias { + fn read(r: &mut R) -> Result { + Ok(NodeAlias(Readable::read(r)?)) + } +} + #[derive(Clone, Debug, PartialEq)] /// Details about a node in the network, known from the network announcement. pub struct NodeInfo { @@ -1126,7 +1173,7 @@ impl NetworkGraph where L::Target: Logger { features: msg.features.clone(), last_update: msg.timestamp, rgb: msg.rgb, - alias: msg.alias, + alias: NodeAlias(msg.alias), addresses: msg.addresses.clone(), announcement_message: if should_relay { full_msg.cloned() } else { None }, }); @@ -1627,12 +1674,11 @@ mod tests { use chain; use ln::PaymentHash; use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; - use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, MAX_EXCESS_BYTES_FOR_RELAY}; + use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, NodeAlias, MAX_EXCESS_BYTES_FOR_RELAY}; use ln::msgs::{Init, OptionalField, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement, UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT}; use util::test_utils; - use util::logger::Logger; use util::ser::{ReadableArgs, Writeable}; use util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider}; use util::scid_utils::scid_from_parts; @@ -1829,7 +1875,7 @@ mod tests { #[test] fn handling_channel_announcements() { let secp_ctx = Secp256k1::new(); - let logger: Arc = Arc::new(test_utils::TestLogger::new()); + let logger = test_utils::TestLogger::new(); let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); @@ -1839,8 +1885,8 @@ mod tests { // Test if the UTXO lookups were not supported let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); - let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger)); - let mut gossip_sync = P2PGossipSync::new(&network_graph, None, Arc::clone(&logger)); + let network_graph = NetworkGraph::new(genesis_hash, &logger); + let mut gossip_sync = P2PGossipSync::new(&network_graph, None, &logger); match gossip_sync.handle_channel_announcement(&valid_announcement) { Ok(res) => assert!(res), _ => panic!() @@ -1861,10 +1907,10 @@ mod tests { }; // Test if an associated transaction were not on-chain (or not confirmed). - let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet)); + let chain_source = test_utils::TestChainSource::new(Network::Testnet); *chain_source.utxo_ret.lock().unwrap() = Err(chain::AccessError::UnknownTx); - let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger)); - gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), Arc::clone(&logger)); + let network_graph = NetworkGraph::new(genesis_hash, &logger); + gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger); let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| { unsigned_announcement.short_channel_id += 1; @@ -1945,11 +1991,11 @@ mod tests { #[test] fn handling_channel_update() { let secp_ctx = Secp256k1::new(); - let logger: Arc = Arc::new(test_utils::TestLogger::new()); - let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet)); + let logger = test_utils::TestLogger::new(); + let chain_source = test_utils::TestChainSource::new(Network::Testnet); let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); - let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger)); - let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), Arc::clone(&logger)); + let network_graph = NetworkGraph::new(genesis_hash, &logger); + let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger); let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); @@ -2151,10 +2197,10 @@ mod tests { fn test_channel_timeouts() { // Test the removal of channels with `remove_stale_channels`. let logger = test_utils::TestLogger::new(); - let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet)); + let chain_source = test_utils::TestChainSource::new(Network::Testnet); let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); let network_graph = NetworkGraph::new(genesis_hash, &logger); - let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), &logger); + let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger); let secp_ctx = Secp256k1::new(); let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); @@ -2731,6 +2777,29 @@ mod tests { }); assert!(result.is_err()); } + + #[test] + fn displays_node_alias() { + let format_str_alias = |alias: &str| { + let mut bytes = [0u8; 32]; + bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); + format!("{}", NodeAlias(bytes)) + }; + + assert_eq!(format_str_alias("I\u{1F496}LDK! \u{26A1}"), "I\u{1F496}LDK! \u{26A1}"); + assert_eq!(format_str_alias("I\u{1F496}LDK!\0\u{26A1}"), "I\u{1F496}LDK!"); + assert_eq!(format_str_alias("I\u{1F496}LDK!\t\u{26A1}"), "I\u{1F496}LDK!\u{FFFD}\u{26A1}"); + + let format_bytes_alias = |alias: &[u8]| { + let mut bytes = [0u8; 32]; + bytes[..alias.len()].copy_from_slice(alias); + format!("{}", NodeAlias(bytes)) + }; + + assert_eq!(format_bytes_alias(b"\xFFI LDK!"), "\u{FFFD}I LDK!"); + assert_eq!(format_bytes_alias(b"\xFFI \0LDK!"), "\u{FFFD}I "); + assert_eq!(format_bytes_alias(b"\xFFI \tLDK!"), "\u{FFFD}I \u{FFFD}LDK!"); + } } #[cfg(all(test, feature = "_bench_unstable"))]