X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Fnetwork_graph.rs;h=3168a1fd8503be206063bf23fa9abbd177180699;hb=2087032e7a823f6c63a64dac951e0f4843bc4667;hp=add57c25c145ac9155ecebb0fca734c750d1997f;hpb=7ec98e6206f59330327b25d5460048579b47b9ce;p=rust-lightning diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index add57c25..3168a1fd 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -17,26 +17,34 @@ use util::ser::{Writeable, Readable, Writer}; use util::logger::Logger; use std::cmp; -use std::sync::{RwLock,Arc}; +use std::sync::RwLock; use std::sync::atomic::{AtomicUsize, Ordering}; use std::collections::BTreeMap; use std::collections::btree_map::Entry as BtreeEntry; use std; - -/// Receives network updates from peers to track view of the network. -pub struct NetGraphMsgHandler { +use std::ops::Deref; + +/// 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 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 fresh Network Graph - pub fn new(chain_monitor: Arc, logger: Arc) -> Self { + /// 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: C, logger: L) -> Self { NetGraphMsgHandler { secp_ctx: Secp256k1::verification_only(), network_graph: RwLock::new(NetworkGraph { @@ -45,37 +53,20 @@ 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: RwLock) -> Self { NetGraphMsgHandler { secp_ctx: Secp256k1::verification_only(), - network_graph: network_graph, + network_graph, full_syncs_requested: AtomicUsize::new(0), chain_monitor, - logger: logger.clone(), - } - } - - /// Get network addresses by node id - 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()) - } + logger, } - 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()); } } @@ -89,7 +80,7 @@ macro_rules! secp_verify_sig { }; } -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)) } @@ -125,7 +116,7 @@ impl RoutingMessageHandler for NetGraphMsgHandler { }, }; 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 } @@ -212,19 +203,24 @@ impl RoutingMessageHandler for NetGraphMsgHandler { } #[derive(PartialEq, Debug)] -/// Details regarding one direction of a channel +/// Details about one direction of a channel. Received +/// within a channel update. pub struct DirectionalChannelInfo { - /// When the last update to the channel direction was issued + /// When the last update to the channel direction was issued. + /// Value is opaque, as set in the announcement. pub last_update: u32, - /// Whether the channel can be currently used for payments + /// Whether the channel can be currently used for payments (in this one direction). pub enabled: bool, - /// The difference in CLTV values between the source and the destination node of the channel + /// The difference in CLTV values that you must have when routing through this channel. pub cltv_expiry_delta: u16, /// The minimum value, which must be relayed to the next hop via the channel pub htlc_minimum_msat: u64, /// 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, } @@ -245,7 +241,8 @@ impl_writeable!(DirectionalChannelInfo, 0, { }); #[derive(PartialEq)] -/// Details regarding a channel (both directions) +/// Details about a channel (both directions). +/// Received within a channel announcement. pub struct ChannelInfo { /// Protocol features of a channel communicated during its announcement pub features: ChannelFeatures, @@ -258,8 +255,9 @@ pub struct ChannelInfo { /// Details about the second direction of a channel pub two_to_one: Option, /// An initial announcement of the channel - //this is cached here so we can send out it later if required by initial routing sync - //keep an eye on this to see if the extra memory is a problem + /// 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 announcement_message: Option, } @@ -284,9 +282,10 @@ impl_writeable!(ChannelInfo, 0, { /// Fees for routing via a given channel or a node #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub struct RoutingFees { - /// Flat routing fee + /// Flat routing fee in satoshis pub base_msat: u32, - /// Liquidity-based routing fee + /// Liquidity-based routing fee in millionths of a routed amount. + /// In other words, 10000 is 1%. pub proportional_millionths: u32, } @@ -313,18 +312,22 @@ 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, - /// When the last known update to the node state was issued - pub last_update: u32, + 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, /// Color assigned to the node pub rgb: [u8; 3], - /// Moniker assigned to the node + /// Moniker assigned to the node. + /// May be invalid or malicious (eg control chars), + /// should not be exposed to the user. pub alias: [u8; 32], /// Internet-level addresses via which one can connect to the node pub addresses: Vec, /// An initial announcement of the node - // this is cached here so we can send out it later if required by initial routing sync - // keep an eye on this to see if the extra memory is a problem + /// 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 announcement_message: Option } @@ -372,14 +375,17 @@ impl Readable for NodeAnnouncementInfo { } #[derive(PartialEq)] -/// Details regarding a node in the network +/// Details about a node in the network, known from the network announcement. 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 + /// 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 - /// Optional because we may have a NodeInfo entry before having received the announcement + /// More information about a node from node_announcement. + /// Optional because we store a Node entry after learning about it from + /// a channel announcement, but before receiving a node announcement. pub announcement_info: Option } @@ -483,11 +489,23 @@ impl std::fmt::Display for NetworkGraph { } impl NetworkGraph { - /// Returns all known valid channels + /// Returns all known valid channels' short ids along with announced channel info. pub fn get_channels<'a>(&'a self) -> &'a BTreeMap { &self.channels } - /// Returns all known nodes + /// 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 + } + /// 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 { @@ -520,9 +538,11 @@ impl NetworkGraph { } } - /// For a new or already known (from previous announcement) channel, store or update channel info, - /// after making sure it corresponds to a real transaction on-chain. + /// For a new or already known (from previous announcement) channel, store or update channel info. /// Also store nodes (if not stored yet) the channel is between, and make node aware of this channel. + /// Checking utxo on-chain is useful if we receive an update for already known channel id, + /// which is probably result of a reorg. In that case, we update channel info only if the + /// utxo was checked, otherwise stick to the existing update, to prevent DoS risks. /// Announcement signatures are checked here only if Secp256k1 object is provided. fn update_channel_from_announcement(&mut self, msg: &msgs::ChannelAnnouncement, checked_utxo: bool, secp_ctx: Option<&Secp256k1>) -> Result { if let Some(sig_verifier) = secp_ctx { @@ -621,7 +641,7 @@ impl NetworkGraph { } } - /// For an already known (from announcement) channel, update info regarding one of the directions of a channel. + /// For an already known (from announcement) channel, update info about one of the directions of a channel. /// Announcement signatures are checked here only if Secp256k1 object is provided. fn update_channel(&mut self, msg: &msgs::ChannelUpdate, secp_ctx: Option<&Secp256k1>) -> Result { let dest_node_id; @@ -693,34 +713,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()) @@ -753,7 +767,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}; @@ -773,10 +787,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) } @@ -832,7 +846,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,