X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Frouting%2Fnetwork_graph.rs;h=9c93b246f0762b72e2601151d5eff2f64ca7cdee;hb=ed84b02a0aef7d97a887d187ea0429dcd780a6b3;hp=faf2b5ff208ae1789df094e20d45f9e647fe84cd;hpb=07a7e34f89323540f17abbf9a4b708d27f6bd18f;p=rust-lightning diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index faf2b5ff..9c93b246 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -16,34 +16,35 @@ use ln::msgs; use util::ser::{Writeable, Readable, Writer}; use util::logger::Logger; -use std::cmp; -use std::sync::{RwLock,Arc}; +use std::{cmp, fmt}; +use std::sync::RwLock; use std::sync::atomic::{AtomicUsize, Ordering}; use std::collections::BTreeMap; use std::collections::btree_map::Entry as BtreeEntry; -use std; +use std::ops::Deref; +use bitcoin::hashes::hex::ToHex; /// Receives and validates network updates from peers, /// stores authentic and relevant data as a network graph. /// This network graph is then used for routing payments. /// Provides interface to help with initial routing sync by /// serving historical announcements. -pub struct NetGraphMsgHandler { +pub struct NetGraphMsgHandler where C::Target: ChainWatchInterface, L::Target: Logger { secp_ctx: Secp256k1, /// Representation of the payment channel network pub network_graph: RwLock, - chain_monitor: Arc, + chain_monitor: C, full_syncs_requested: AtomicUsize, - logger: Arc, + logger: L, } -impl NetGraphMsgHandler { +impl NetGraphMsgHandler where C::Target: ChainWatchInterface, L::Target: Logger { /// Creates a new tracker of the actual state of the network of channels and nodes, /// assuming a fresh network graph. /// Chain monitor is used to make sure announced channels exist on-chain, /// channel data is correct, and that the announcement is signed with /// channel owners' keys. - pub fn new(chain_monitor: Arc, logger: Arc) -> Self { + pub fn new(chain_monitor: C, logger: L) -> Self { NetGraphMsgHandler { secp_ctx: Secp256k1::verification_only(), network_graph: RwLock::new(NetworkGraph { @@ -52,40 +53,21 @@ impl NetGraphMsgHandler { }), full_syncs_requested: AtomicUsize::new(0), chain_monitor, - logger: logger.clone(), + logger, } } /// Creates a new tracker of the actual state of the network of channels and nodes, /// assuming an existing Network Graph. - pub fn from_net_graph(chain_monitor: Arc, logger: Arc, network_graph: RwLock) -> Self { + pub fn from_net_graph(chain_monitor: C, logger: L, network_graph: NetworkGraph) -> Self { NetGraphMsgHandler { secp_ctx: Secp256k1::verification_only(), - network_graph: network_graph, + network_graph: RwLock::new(network_graph), full_syncs_requested: AtomicUsize::new(0), chain_monitor, - logger: logger.clone(), + logger, } } - - /// Get network addresses by node id. - /// 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> { - let network = self.network_graph.read().unwrap(); - if let Some(node) = network.get_nodes().get(pubkey) { - if let Some(node_info) = node.announcement_info.as_ref() { - return Some(node_info.addresses.clone()) - } - } - None - } - - /// Dumps the entire network view of this NetGraphMsgHandler to the logger provided in the constructor at - /// level Trace - pub fn trace_state(&self) { - log_trace!(self, "{}", self.network_graph.read().unwrap()); - } } @@ -93,19 +75,19 @@ macro_rules! secp_verify_sig { ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => { match $secp_ctx.verify($msg, $sig, $pubkey) { Ok(_) => {}, - Err(_) => return Err(LightningError{err: "Invalid signature from remote node", action: ErrorAction::IgnoreError}), + Err(_) => return Err(LightningError{err: "Invalid signature from remote node".to_owned(), action: ErrorAction::IgnoreError}), } }; } -impl RoutingMessageHandler for NetGraphMsgHandler { +impl RoutingMessageHandler for NetGraphMsgHandler where C::Target: ChainWatchInterface, L::Target: Logger { fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result { self.network_graph.write().unwrap().update_node_from_announcement(msg, Some(&self.secp_ctx)) } fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result { if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 { - return Err(LightningError{err: "Channel announcement node had a channel with itself", action: ErrorAction::IgnoreError}); + return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError}); } let checked_utxo = match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) { @@ -116,7 +98,7 @@ impl RoutingMessageHandler for NetGraphMsgHandler { .push_opcode(opcodes::all::OP_PUSHNUM_2) .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); if script_pubkey != expected_script { - return Err(LightningError{err: "Channel announcement keys didn't match on-chain script", action: ErrorAction::IgnoreError}); + return Err(LightningError{err: format!("Channel announcement key ({}) didn't match on-chain script ({})", script_pubkey.to_hex(), expected_script.to_hex()), action: ErrorAction::IgnoreError}); } //TODO: Check if value is worth storing, use it to inform routing, and compare it //to the new HTLC max field in channel_update @@ -127,14 +109,14 @@ impl RoutingMessageHandler for NetGraphMsgHandler { false }, Err(ChainError::NotWatched) => { - return Err(LightningError{err: "Channel announced on an unknown chain", action: ErrorAction::IgnoreError}); + return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.contents.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError}); }, Err(ChainError::UnknownTx) => { - return Err(LightningError{err: "Channel announced without corresponding UTXO entry", action: ErrorAction::IgnoreError}); + return Err(LightningError{err: "Channel announced without corresponding UTXO entry".to_owned(), action: ErrorAction::IgnoreError}); }, }; let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, checked_utxo, Some(&self.secp_ctx)); - log_trace!(self, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" }); + log_trace!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" }); result } @@ -143,11 +125,11 @@ impl RoutingMessageHandler for NetGraphMsgHandler { &msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => { let _ = self.network_graph.write().unwrap().update_channel(msg, Some(&self.secp_ctx)); }, - &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id, ref is_permanent } => { - self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, &is_permanent); + &msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id, is_permanent } => { + self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, is_permanent); }, - &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, ref is_permanent } => { - self.network_graph.write().unwrap().fail_node(node_id, &is_permanent); + &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, is_permanent } => { + self.network_graph.write().unwrap().fail_node(node_id, is_permanent); }, } } @@ -236,11 +218,14 @@ pub struct DirectionalChannelInfo { /// Fees charged when the channel is used for routing pub fees: RoutingFees, /// Most recent update for the channel received from the network + /// Mostly redundant with the data we store in fields explicitly. + /// Everything else is useful only for sending out for initial routing sync. + /// Not stored if contains excess data to prevent DoS. pub last_update_message: Option, } -impl std::fmt::Display for DirectionalChannelInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { +impl fmt::Display for DirectionalChannelInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "last_update {}, enabled {}, cltv_expiry_delta {}, htlc_minimum_msat {}, fees {:?}", self.last_update, self.enabled, self.cltv_expiry_delta, self.htlc_minimum_msat, self.fees)?; Ok(()) } @@ -276,8 +261,8 @@ pub struct ChannelInfo { pub announcement_message: Option, } -impl std::fmt::Display for ChannelInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { +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_pubkey!(self.node_one), self.one_to_two, log_pubkey!(self.node_two), self.two_to_one)?; Ok(()) @@ -327,10 +312,10 @@ impl Writeable for RoutingFees { /// Information received in the latest node_announcement from this node. pub struct NodeAnnouncementInfo { /// Protocol features the node announced support for - pub features: NodeFeatures, + pub features: NodeFeatures, /// When the last known update to the node state was issued. /// Value is opaque, as set in the announcement. - pub last_update: u32, + pub last_update: u32, /// Color assigned to the node pub rgb: [u8; 3], /// Moniker assigned to the node. @@ -394,8 +379,8 @@ impl Readable for NodeAnnouncementInfo { pub struct NodeInfo { /// All valid channels a node has announced pub channels: Vec, - /// Lowest fees enabling routing via any of the known channels to a node. - /// The two fields (flat and proportional fee) are independent, + /// Lowest fees enabling routing via any of the enabled, known channels to a node. + /// The two fields (flat and proportional fee) are independent, /// meaning they don't have to refer to the same channel. pub lowest_inbound_channel_fees: Option, /// More information about a node from node_announcement. @@ -404,8 +389,8 @@ pub struct NodeInfo { pub announcement_info: Option } -impl std::fmt::Display for NodeInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { +impl fmt::Display for NodeInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "lowest_inbound_channel_fees: {:?}, channels: {:?}, announcement_info: {:?}", self.lowest_inbound_channel_fees, &self.channels[..], self.announcement_info)?; Ok(()) @@ -489,8 +474,8 @@ impl Readable for NetworkGraph { } } -impl std::fmt::Display for NetworkGraph { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { +impl fmt::Display for NetworkGraph { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "Network map\n[Channels]\n")?; for (key, val) in self.channels.iter() { write!(f, " {}: {}\n", key, val)?; @@ -509,6 +494,26 @@ impl NetworkGraph { /// Returns all known nodes' public keys along with announced node info. pub fn get_nodes<'a>(&'a self) -> &'a BTreeMap { &self.nodes } + /// Get network addresses by node id. + /// Returns None if the requested node is completely unknown, + /// or if node announcement for the node was never received. + pub fn get_addresses<'a>(&'a self, pubkey: &PublicKey) -> Option<&'a Vec> { + if let Some(node) = self.nodes.get(pubkey) { + if let Some(node_info) = node.announcement_info.as_ref() { + return Some(&node_info.addresses) + } + } + None + } + + /// Creates a new, empty, network graph. + pub fn new() -> NetworkGraph { + Self { + channels: BTreeMap::new(), + nodes: BTreeMap::new(), + } + } + /// For an already known node (from channel announcements), update its stored properties from a given node announcement /// Announcement signatures are checked here only if Secp256k1 object is provided. fn update_node_from_announcement(&mut self, msg: &msgs::NodeAnnouncement, secp_ctx: Option<&Secp256k1>) -> Result { @@ -518,11 +523,11 @@ impl NetworkGraph { } match self.nodes.get_mut(&msg.contents.node_id) { - None => Err(LightningError{err: "No existing channels for node_announcement", action: ErrorAction::IgnoreError}), + None => Err(LightningError{err: "No existing channels for node_announcement".to_owned(), action: ErrorAction::IgnoreError}), Some(node) => { if let Some(node_info) = node.announcement_info.as_ref() { if node_info.last_update >= msg.contents.timestamp { - return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError}); + return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError}); } } @@ -584,7 +589,7 @@ impl NetworkGraph { Self::remove_channel_in_nodes(&mut self.nodes, &entry.get(), msg.contents.short_channel_id); *entry.get_mut() = chan_info; } else { - return Err(LightningError{err: "Already have knowledge of channel", action: ErrorAction::IgnoreError}) + return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreError}) } }, BtreeEntry::Vacant(entry) => { @@ -619,10 +624,10 @@ impl NetworkGraph { /// If permanent, removes a channel from the local storage. /// May cause the removal of nodes too, if this was their last channel. /// If not permanent, makes channels unavailable for routing. - pub fn close_channel_from_update(&mut self, short_channel_id: &u64, is_permanent: &bool) { - if *is_permanent { - if let Some(chan) = self.channels.remove(short_channel_id) { - Self::remove_channel_in_nodes(&mut self.nodes, &chan, *short_channel_id); + pub fn close_channel_from_update(&mut self, short_channel_id: u64, is_permanent: bool) { + if is_permanent { + if let Some(chan) = self.channels.remove(&short_channel_id) { + Self::remove_channel_in_nodes(&mut self.nodes, &chan, short_channel_id); } } else { if let Some(chan) = self.channels.get_mut(&short_channel_id) { @@ -636,8 +641,8 @@ impl NetworkGraph { } } - fn fail_node(&mut self, _node_id: &PublicKey, is_permanent: &bool) { - if *is_permanent { + fn fail_node(&mut self, _node_id: &PublicKey, is_permanent: bool) { + if is_permanent { // TODO: Wholly remove the node } else { // TODO: downgrade the node @@ -652,13 +657,13 @@ impl NetworkGraph { let chan_was_enabled; match self.channels.get_mut(&msg.contents.short_channel_id) { - None => return Err(LightningError{err: "Couldn't find channel for update", action: ErrorAction::IgnoreError}), + None => return Err(LightningError{err: "Couldn't find channel for update".to_owned(), action: ErrorAction::IgnoreError}), Some(channel) => { macro_rules! maybe_update_channel_info { ( $target: expr, $src_node: expr) => { if let Some(existing_chan_info) = $target.as_ref() { if existing_chan_info.last_update >= msg.contents.timestamp { - return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError}); + return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError}); } chan_was_enabled = existing_chan_info.enabled; } else { @@ -716,34 +721,28 @@ impl NetworkGraph { proportional_millionths }); } else if chan_was_enabled { - let mut lowest_inbound_channel_fee_base_msat = u32::max_value(); - let mut lowest_inbound_channel_fee_proportional_millionths = u32::max_value(); - - { - let node = self.nodes.get(&dest_node_id).unwrap(); - - for chan_id in node.channels.iter() { - let chan = self.channels.get(chan_id).unwrap(); - // Since direction was enabled, the channel indeed had directional info - let chan_info; - if chan.node_one == dest_node_id { - chan_info = chan.two_to_one.as_ref().unwrap(); - } else { - chan_info = chan.one_to_two.as_ref().unwrap(); + let node = self.nodes.get_mut(&dest_node_id).unwrap(); + let mut lowest_inbound_channel_fees = None; + + for chan_id in node.channels.iter() { + let chan = self.channels.get(chan_id).unwrap(); + let chan_info_opt; + if chan.node_one == dest_node_id { + chan_info_opt = chan.two_to_one.as_ref(); + } else { + chan_info_opt = chan.one_to_two.as_ref(); + } + if let Some(chan_info) = chan_info_opt { + if chan_info.enabled { + let fees = lowest_inbound_channel_fees.get_or_insert(RoutingFees { + base_msat: u32::max_value(), proportional_millionths: u32::max_value() }); + fees.base_msat = cmp::min(fees.base_msat, chan_info.fees.base_msat); + fees.proportional_millionths = cmp::min(fees.proportional_millionths, chan_info.fees.proportional_millionths); } - lowest_inbound_channel_fee_base_msat = cmp::min(lowest_inbound_channel_fee_base_msat, chan_info.fees.base_msat); - lowest_inbound_channel_fee_proportional_millionths = cmp::min(lowest_inbound_channel_fee_proportional_millionths, chan_info.fees.proportional_millionths); } } - //TODO: satisfy the borrow-checker without a double-map-lookup :( - let mut_node = self.nodes.get_mut(&dest_node_id).unwrap(); - if mut_node.channels.len() > 0 { - mut_node.lowest_inbound_channel_fees = Some(RoutingFees { - base_msat: lowest_inbound_channel_fee_base_msat, - proportional_millionths: lowest_inbound_channel_fee_proportional_millionths - }); - } + node.lowest_inbound_channel_fees = lowest_inbound_channel_fees; } Ok(msg.contents.excess_data.is_empty()) @@ -776,7 +775,7 @@ mod tests { use ln::features::{ChannelFeatures, NodeFeatures}; use routing::network_graph::{NetGraphMsgHandler, NetworkGraph}; use ln::msgs::{RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement, - UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, HTLCFailChannelUpdate}; + UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, HTLCFailChannelUpdate}; use util::test_utils; use util::logger::Logger; use util::ser::{Readable, Writeable}; @@ -796,10 +795,10 @@ mod tests { use std::sync::Arc; - fn create_net_graph_msg_handler() -> (Secp256k1, NetGraphMsgHandler) { + fn create_net_graph_msg_handler() -> (Secp256k1, NetGraphMsgHandler, Arc>) { let secp_ctx = Secp256k1::new(); - let logger: Arc = Arc::new(test_utils::TestLogger::new()); - let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger))); + let logger = Arc::new(test_utils::TestLogger::new()); + let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet)); let net_graph_msg_handler = NetGraphMsgHandler::new(chain_monitor, Arc::clone(&logger)); (secp_ctx, net_graph_msg_handler) } @@ -855,7 +854,7 @@ mod tests { // Announce a channel to add a corresponding node. let unsigned_announcement = UnsignedChannelAnnouncement { features: ChannelFeatures::known(), - chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(), + chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(), short_channel_id: 0, node_id_1, node_id_2,