X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Frouter.rs;h=dc58f6d20ec374f3476ffa2ab404e1b339225a65;hb=81cea88d38c58595a12182a63abe7af090a374b5;hp=d2d428a38bc70a27d3cfec4fc04c09bbc744947f;hpb=c91f72c131e8390ec86ace9cc4c70a55cf5f9438;p=rust-lightning diff --git a/src/ln/router.rs b/src/ln/router.rs index d2d428a3..dc58f6d2 100644 --- a/src/ln/router.rs +++ b/src/ln/router.rs @@ -1,27 +1,34 @@ +//! The top-level routing/network map tracking logic lives here. +//! +//! You probably want to create a Router and use that as your RoutingMessageHandler and then +//! interrogate it to get routes for your own payments. + use secp256k1::key::PublicKey; -use secp256k1::{Secp256k1,Message}; +use secp256k1::Secp256k1; use secp256k1; -use bitcoin::util::hash::Sha256dHash; +use bitcoin_hashes::sha256d::Hash as Sha256dHash; +use bitcoin_hashes::Hash; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; use chain::chaininterface::{ChainError, ChainWatchInterface}; use ln::channelmanager; -use ln::msgs::{ErrorAction,HandleError,RoutingMessageHandler,NetAddress,GlobalFeatures}; +use ln::msgs::{DecodeError,ErrorAction,HandleError,RoutingMessageHandler,NetAddress,GlobalFeatures}; use ln::msgs; -use util::ser::Writeable; +use util::ser::{Writeable, Readable, Writer, ReadableArgs}; use util::logger::Logger; use std::cmp; use std::sync::{RwLock,Arc}; -use std::collections::{HashMap,BinaryHeap}; -use std::collections::hash_map::Entry; +use std::collections::{HashMap,BinaryHeap,BTreeMap}; +use std::collections::btree_map::Entry as BtreeEntry; use std; /// A hop in a route -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct RouteHop { + /// The node_id of the node at this hop. pub pubkey: PublicKey, /// The channel that should be used from the previous hop to reach this node. pub short_channel_id: u64, @@ -33,7 +40,7 @@ pub struct RouteHop { } /// A route from us through the network to a destination -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct Route { /// The list of hops, NOT INCLUDING our own, where the last hop is the destination. Thus, this /// must always be at least length one. By protocol rules, this may not currently exceed 20 in @@ -41,6 +48,38 @@ pub struct Route { pub hops: Vec, } +impl Writeable for Route { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + (self.hops.len() as u8).write(writer)?; + for hop in self.hops.iter() { + hop.pubkey.write(writer)?; + hop.short_channel_id.write(writer)?; + hop.fee_msat.write(writer)?; + hop.cltv_expiry_delta.write(writer)?; + } + Ok(()) + } +} + +impl Readable for Route { + fn read(reader: &mut R) -> Result { + let hops_count: u8 = Readable::read(reader)?; + let mut hops = Vec::with_capacity(hops_count as usize); + for _ in 0..hops_count { + hops.push(RouteHop { + pubkey: Readable::read(reader)?, + short_channel_id: Readable::read(reader)?, + fee_msat: Readable::read(reader)?, + cltv_expiry_delta: Readable::read(reader)?, + }); + } + Ok(Route { + hops + }) + } +} + +#[derive(PartialEq)] struct DirectionalChannelInfo { src_node_id: PublicKey, last_update: u32, @@ -49,6 +88,7 @@ struct DirectionalChannelInfo { htlc_minimum_msat: u64, fee_base_msat: u32, fee_proportional_millionths: u32, + last_update_message: Option, } impl std::fmt::Display for DirectionalChannelInfo { @@ -58,10 +98,25 @@ impl std::fmt::Display for DirectionalChannelInfo { } } +impl_writeable!(DirectionalChannelInfo, 0, { + src_node_id, + last_update, + enabled, + cltv_expiry_delta, + htlc_minimum_msat, + fee_base_msat, + fee_proportional_millionths, + last_update_message +}); + +#[derive(PartialEq)] struct ChannelInfo { features: GlobalFeatures, one_to_two: DirectionalChannelInfo, two_to_one: DirectionalChannelInfo, + //this is cached here so we can send out it later if required by route_init_sync + //keep an eye on this to see if the extra memory is a problem + announcement_message: Option, } impl std::fmt::Display for ChannelInfo { @@ -71,6 +126,14 @@ impl std::fmt::Display for ChannelInfo { } } +impl_writeable!(ChannelInfo, 0, { + features, + one_to_two, + two_to_one, + announcement_message +}); + +#[derive(PartialEq)] struct NodeInfo { #[cfg(feature = "non_bitcoin_chain_hash_routing")] channels: Vec<(u64, Sha256dHash)>, @@ -85,6 +148,9 @@ struct NodeInfo { rgb: [u8; 3], alias: [u8; 32], addresses: Vec, + //this is cached here so we can send out it later if required by route_init_sync + //keep an eye on this to see if the extra memory is a problem + announcement_message: Option, } impl std::fmt::Display for NodeInfo { @@ -94,21 +160,126 @@ impl std::fmt::Display for NodeInfo { } } +impl Writeable for NodeInfo { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + (self.channels.len() as u64).write(writer)?; + for ref chan in self.channels.iter() { + chan.write(writer)?; + } + self.lowest_inbound_channel_fee_base_msat.write(writer)?; + self.lowest_inbound_channel_fee_proportional_millionths.write(writer)?; + self.features.write(writer)?; + self.last_update.write(writer)?; + self.rgb.write(writer)?; + self.alias.write(writer)?; + (self.addresses.len() as u64).write(writer)?; + for ref addr in &self.addresses { + addr.write(writer)?; + } + self.announcement_message.write(writer)?; + Ok(()) + } +} + +const MAX_ALLOC_SIZE: u64 = 64*1024; + +impl Readable for NodeInfo { + fn read(reader: &mut R) -> Result { + let channels_count: u64 = Readable::read(reader)?; + let mut channels = Vec::with_capacity(cmp::min(channels_count, MAX_ALLOC_SIZE / 8) as usize); + for _ in 0..channels_count { + channels.push(Readable::read(reader)?); + } + let lowest_inbound_channel_fee_base_msat = Readable::read(reader)?; + let lowest_inbound_channel_fee_proportional_millionths = Readable::read(reader)?; + let features = Readable::read(reader)?; + let last_update = Readable::read(reader)?; + let rgb = Readable::read(reader)?; + let alias = Readable::read(reader)?; + let addresses_count: u64 = Readable::read(reader)?; + let mut addresses = Vec::with_capacity(cmp::min(addresses_count, MAX_ALLOC_SIZE / 40) as usize); + for _ in 0..addresses_count { + match Readable::read(reader) { + Ok(Ok(addr)) => { addresses.push(addr); }, + Ok(Err(_)) => return Err(DecodeError::InvalidValue), + Err(DecodeError::ShortRead) => return Err(DecodeError::BadLengthDescriptor), + _ => unreachable!(), + } + } + let announcement_message = Readable::read(reader)?; + Ok(NodeInfo { + channels, + lowest_inbound_channel_fee_base_msat, + lowest_inbound_channel_fee_proportional_millionths, + features, + last_update, + rgb, + alias, + addresses, + announcement_message + }) + } +} + +#[derive(PartialEq)] struct NetworkMap { #[cfg(feature = "non_bitcoin_chain_hash_routing")] - channels: HashMap<(u64, Sha256dHash), ChannelInfo>, + channels: BTreeMap<(u64, Sha256dHash), ChannelInfo>, #[cfg(not(feature = "non_bitcoin_chain_hash_routing"))] - channels: HashMap, + channels: BTreeMap, our_node_id: PublicKey, - nodes: HashMap, + nodes: BTreeMap, +} + +impl Writeable for NetworkMap { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + (self.channels.len() as u64).write(writer)?; + for (ref chan_id, ref chan_info) in self.channels.iter() { + (*chan_id).write(writer)?; + chan_info.write(writer)?; + } + self.our_node_id.write(writer)?; + (self.nodes.len() as u64).write(writer)?; + for (ref node_id, ref node_info) in self.nodes.iter() { + node_id.write(writer)?; + node_info.write(writer)?; + } + Ok(()) + } +} + +impl Readable for NetworkMap { + fn read(reader: &mut R) -> Result { + let channels_count: u64 = Readable::read(reader)?; + let mut channels = BTreeMap::new(); + for _ in 0..channels_count { + let chan_id: u64 = Readable::read(reader)?; + let chan_info = Readable::read(reader)?; + channels.insert(chan_id, chan_info); + } + let our_node_id = Readable::read(reader)?; + let nodes_count: u64 = Readable::read(reader)?; + let mut nodes = BTreeMap::new(); + for _ in 0..nodes_count { + let node_id = Readable::read(reader)?; + let node_info = Readable::read(reader)?; + nodes.insert(node_id, node_info); + } + Ok(NetworkMap { + channels, + our_node_id, + nodes, + }) + } } + struct MutNetworkMap<'a> { #[cfg(feature = "non_bitcoin_chain_hash_routing")] - channels: &'a mut HashMap<(u64, Sha256dHash), ChannelInfo>, + channels: &'a mut BTreeMap<(u64, Sha256dHash), ChannelInfo>, #[cfg(not(feature = "non_bitcoin_chain_hash_routing"))] - channels: &'a mut HashMap, - nodes: &'a mut HashMap, + channels: &'a mut BTreeMap, + nodes: &'a mut BTreeMap, } impl NetworkMap { fn borrow_parts(&mut self) -> MutNetworkMap { @@ -160,11 +331,18 @@ impl NetworkMap { /// A channel descriptor which provides a last-hop route to get_route pub struct RouteHint { + /// The node_id of the non-target end of the route pub src_node_id: PublicKey, + /// The short_channel_id of this channel pub short_channel_id: u64, + /// The static msat-denominated fee which must be paid to use this channel pub fee_base_msat: u32, + /// The dynamic proportional fee which must be paid to use this channel, denominated in + /// millionths of the value being forwarded to the next hop. pub fee_proportional_millionths: u32, + /// The difference in CLTV values between this node and the next node. pub cltv_expiry_delta: u16, + /// The minimum value, in msat, which must be relayed to the next hop. pub htlc_minimum_msat: u64, } @@ -177,6 +355,51 @@ pub struct Router { logger: Arc, } +const SERIALIZATION_VERSION: u8 = 1; +const MIN_SERIALIZATION_VERSION: u8 = 1; + +impl Writeable for Router { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + writer.write_all(&[SERIALIZATION_VERSION; 1])?; + writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?; + + let network = self.network_map.read().unwrap(); + network.write(writer)?; + Ok(()) + } +} + +/// Arguments for the creation of a Router that are not deserialized. +/// At a high-level, the process for deserializing a Router and resuming normal operation is: +/// 1) Deserialize the Router by filling in this struct and calling ::read(reaser, args). +/// 2) Register the new Router with your ChainWatchInterface +pub struct RouterReadArgs { + /// The ChainWatchInterface for use in the Router in the future. + /// + /// No calls to the ChainWatchInterface will be made during deserialization. + pub chain_monitor: Arc, + /// The Logger for use in the ChannelManager and which may be used to log information during + /// deserialization. + pub logger: Arc, +} + +impl ReadableArgs for Router { + fn read(reader: &mut R, args: RouterReadArgs) -> Result { + let _ver: u8 = Readable::read(reader)?; + let min_ver: u8 = Readable::read(reader)?; + if min_ver > SERIALIZATION_VERSION { + return Err(DecodeError::UnknownVersion); + } + let network_map = Readable::read(reader)?; + Ok(Router { + secp_ctx: Secp256k1::verification_only(), + network_map: RwLock::new(network_map), + chain_monitor: args.chain_monitor, + logger: args.logger, + }) + } +} + macro_rules! secp_verify_sig { ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => { match $secp_ctx.verify($msg, $sig, $pubkey) { @@ -188,7 +411,7 @@ macro_rules! secp_verify_sig { impl RoutingMessageHandler for Router { fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result { - let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap(); + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id); if msg.contents.features.requires_unknown_bits() { @@ -208,7 +431,10 @@ impl RoutingMessageHandler for Router { node.rgb = msg.contents.rgb; node.alias = msg.contents.alias; node.addresses = msg.contents.addresses.clone(); - Ok(msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty() && !msg.contents.features.supports_unknown_bits()) + + let should_relay = msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty() && !msg.contents.features.supports_unknown_bits(); + node.announcement_message = if should_relay { Some(msg.clone()) } else { None }; + Ok(should_relay) } } } @@ -218,7 +444,7 @@ impl RoutingMessageHandler for Router { return Err(HandleError{err: "Channel announcement node had a channel with itself", action: Some(ErrorAction::IgnoreError)}); } - let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap(); + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1); secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2); secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1); @@ -230,10 +456,11 @@ impl RoutingMessageHandler for Router { let checked_utxo = match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) { Ok((script_pubkey, _value)) => { - let expected_script = Builder::new().push_opcode(opcodes::All::OP_PUSHNUM_2) + let expected_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2) .push_slice(&msg.contents.bitcoin_key_1.serialize()) .push_slice(&msg.contents.bitcoin_key_2.serialize()) - .push_opcode(opcodes::All::OP_PUSHNUM_2).push_opcode(opcodes::All::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); + .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(HandleError{err: "Channel announcement keys didn't match on-chain script", action: Some(ErrorAction::IgnoreError)}); } @@ -256,6 +483,8 @@ impl RoutingMessageHandler for Router { let mut network_lock = self.network_map.write().unwrap(); let network = network_lock.borrow_parts(); + let should_relay = msg.contents.excess_data.is_empty() && !msg.contents.features.supports_unknown_bits(); + let chan_info = ChannelInfo { features: msg.contents.features.clone(), one_to_two: DirectionalChannelInfo { @@ -266,6 +495,7 @@ impl RoutingMessageHandler for Router { htlc_minimum_msat: u64::max_value(), fee_base_msat: u32::max_value(), fee_proportional_millionths: u32::max_value(), + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: msg.contents.node_id_2.clone(), @@ -275,13 +505,15 @@ impl RoutingMessageHandler for Router { htlc_minimum_msat: u64::max_value(), fee_base_msat: u32::max_value(), fee_proportional_millionths: u32::max_value(), - } + last_update_message: None, + }, + announcement_message: if should_relay { Some(msg.clone()) } else { None }, }; match network.channels.entry(NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)) { - Entry::Occupied(mut entry) => { + BtreeEntry::Occupied(mut entry) => { //TODO: because asking the blockchain if short_channel_id is valid is only optional - //in the blockchain API, we need to handle it smartly here, though its unclear + //in the blockchain API, we need to handle it smartly here, though it's unclear //exactly how... if checked_utxo { // Either our UTXO provider is busted, there was a reorg, or the UTXO provider @@ -298,7 +530,7 @@ impl RoutingMessageHandler for Router { return Err(HandleError{err: "Already have knowledge of channel", action: Some(ErrorAction::IgnoreError)}) } }, - Entry::Vacant(entry) => { + BtreeEntry::Vacant(entry) => { entry.insert(chan_info); } }; @@ -306,10 +538,10 @@ impl RoutingMessageHandler for Router { macro_rules! add_channel_to_node { ( $node_id: expr ) => { match network.nodes.entry($node_id) { - Entry::Occupied(node_entry) => { + BtreeEntry::Occupied(node_entry) => { node_entry.into_mut().channels.push(NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)); }, - Entry::Vacant(node_entry) => { + BtreeEntry::Vacant(node_entry) => { node_entry.insert(NodeInfo { channels: vec!(NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)), lowest_inbound_channel_fee_base_msat: u32::max_value(), @@ -319,6 +551,7 @@ impl RoutingMessageHandler for Router { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); } } @@ -328,7 +561,7 @@ impl RoutingMessageHandler for Router { add_channel_to_node!(msg.contents.node_id_1); add_channel_to_node!(msg.contents.node_id_2); - Ok(msg.contents.excess_data.is_empty() && !msg.contents.features.supports_unknown_bits()) + Ok(should_relay) } fn handle_htlc_fail_channel_update(&self, update: &msgs::HTLCFailChannelUpdate) { @@ -336,10 +569,24 @@ impl RoutingMessageHandler for Router { &msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => { let _ = self.handle_channel_update(msg); }, - &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id } => { + &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id, ref is_permanent } => { let mut network = self.network_map.write().unwrap(); - if let Some(chan) = network.channels.remove(short_channel_id) { - Self::remove_channel_in_nodes(&mut network.nodes, &chan, *short_channel_id); + if *is_permanent { + if let Some(chan) = network.channels.remove(short_channel_id) { + Self::remove_channel_in_nodes(&mut network.nodes, &chan, *short_channel_id); + } + } else { + if let Some(chan) = network.channels.get_mut(short_channel_id) { + chan.one_to_two.enabled = false; + chan.two_to_one.enabled = false; + } + } + }, + &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, ref is_permanent } => { + if *is_permanent { + //TODO: Wholly remove the node + } else { + self.mark_node_bad(node_id, false); } }, } @@ -366,10 +613,14 @@ impl RoutingMessageHandler for Router { $target.htlc_minimum_msat = msg.contents.htlc_minimum_msat; $target.fee_base_msat = msg.contents.fee_base_msat; $target.fee_proportional_millionths = msg.contents.fee_proportional_millionths; + $target.last_update_message = if msg.contents.excess_data.is_empty() { + Some(msg.clone()) + } else { + None + }; } } - - let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap(); + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); if msg.contents.flags & 1 == 1 { dest_node_id = channel.one_to_two.src_node_id.clone(); secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &channel.two_to_one.src_node_id); @@ -413,6 +664,52 @@ impl RoutingMessageHandler for Router { Ok(msg.contents.excess_data.is_empty()) } + + + fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, msgs::ChannelUpdate,msgs::ChannelUpdate)> { + let mut result = Vec::with_capacity(batch_amount as usize); + let network = self.network_map.read().unwrap(); + let mut iter = network.channels.range(starting_point..); + while result.len() < batch_amount as usize { + if let Some((_, ref chan)) = iter.next() { + if chan.announcement_message.is_some() && + chan.one_to_two.last_update_message.is_some() && + chan.two_to_one.last_update_message.is_some() { + result.push((chan.announcement_message.clone().unwrap(), + chan.one_to_two.last_update_message.clone().unwrap(), + chan.two_to_one.last_update_message.clone().unwrap())); + } else { + // TODO: We may end up sending un-announced channel_updates if we are sending + // initial sync data while receiving announce/updates for this channel. + } + } else { + return result; + } + } + result + } + + fn get_next_node_announcements(&self, starting_point: Option<&PublicKey>, batch_amount: u8) -> Vec { + let mut result = Vec::with_capacity(batch_amount as usize); + let network = self.network_map.read().unwrap(); + let mut iter = if let Some(pubkey) = starting_point { + let mut iter = network.nodes.range((*pubkey)..); + iter.next(); + iter + } else { + network.nodes.range(..) + }; + while result.len() < batch_amount as usize { + if let Some((_, ref node)) = iter.next() { + if node.announcement_message.is_some() { + result.push(node.announcement_message.clone().unwrap()); + } + } else { + return result; + } + } + result + } } #[derive(Eq, PartialEq)] @@ -444,8 +741,9 @@ struct DummyDirectionalChannelInfo { } impl Router { + /// Creates a new router with the given node_id to be used as the source for get_route() pub fn new(our_pubkey: PublicKey, chain_monitor: Arc, logger: Arc) -> Router { - let mut nodes = HashMap::new(); + let mut nodes = BTreeMap::new(); nodes.insert(our_pubkey.clone(), NodeInfo { channels: Vec::new(), lowest_inbound_channel_fee_base_msat: u32::max_value(), @@ -455,11 +753,12 @@ impl Router { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); Router { secp_ctx: Secp256k1::verification_only(), network_map: RwLock::new(NetworkMap { - channels: HashMap::new(), + channels: BTreeMap::new(), our_node_id: our_pubkey, nodes: nodes, }), @@ -481,7 +780,7 @@ impl Router { } /// Marks a node as having failed a route. This will avoid re-using the node in routes for now, - /// with an expotnential decay in node "badness". Note that there is deliberately no + /// with an exponential decay in node "badness". Note that there is deliberately no /// mark_channel_bad as a node may simply lie and suggest that an upstream channel from it is /// what failed the route and not the node itself. Instead, setting the blamed_upstream_node /// boolean will reduce the penalty, returning the node to usability faster. If the node is @@ -490,10 +789,10 @@ impl Router { unimplemented!(); } - fn remove_channel_in_nodes(nodes: &mut HashMap, chan: &ChannelInfo, short_channel_id: u64) { + fn remove_channel_in_nodes(nodes: &mut BTreeMap, chan: &ChannelInfo, short_channel_id: u64) { macro_rules! remove_from_node { ($node_id: expr) => { - if let Entry::Occupied(mut entry) = nodes.entry($node_id) { + if let BtreeEntry::Occupied(mut entry) = nodes.entry($node_id) { entry.get_mut().channels.retain(|chan_id| { short_channel_id != *NetworkMap::get_short_id(chan_id) }); @@ -510,13 +809,18 @@ impl Router { } /// Gets a route from us to the given target node. + /// /// Extra routing hops between known nodes and the target will be used if they are included in /// last_hops. + /// /// If some channels aren't announced, it may be useful to fill in a first_hops with the /// results from a local ChannelManager::list_usable_channels() call. If it is filled in, our /// (this Router's) view of our local channels will be ignored, and only those in first_hops - /// will be used. Panics if first_hops contains channels without short_channel_ids + /// will be used. + /// + /// Panics if first_hops contains channels without short_channel_ids /// (ChannelManager::list_usable_channels will never include such channels). + /// /// The fees on channels from us to next-hops are ignored (as they are assumed to all be /// equal), however the enabled/disabled bit on such channels as well as the htlc_minimum_msat /// *is* checked as they may change based on the receiving node. @@ -577,7 +881,7 @@ impl Router { // $directional_info. ( $chan_id: expr, $dest_node_id: expr, $directional_info: expr, $starting_fee_msat: expr ) => { //TODO: Explore simply adding fee to hit htlc_minimum_msat - if $starting_fee_msat as u64 + final_value_msat > $directional_info.htlc_minimum_msat { + if $starting_fee_msat as u64 + final_value_msat >= $directional_info.htlc_minimum_msat { let proportional_fee_millions = ($starting_fee_msat + final_value_msat).checked_mul($directional_info.fee_proportional_millionths as u64); if let Some(new_fee) = proportional_fee_millions.and_then(|part| { ($directional_info.fee_base_msat as u64).checked_add(part / 1000000) }) @@ -713,9 +1017,12 @@ mod tests { use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint}; use ln::msgs::GlobalFeatures; use util::test_utils; + use util::test_utils::TestVecWriter; use util::logger::Logger; + use util::ser::{Writeable, Readable}; - use bitcoin::util::hash::Sha256dHash; + use bitcoin_hashes::sha256d::Hash as Sha256dHash; + use bitcoin_hashes::Hash; use bitcoin::network::constants::Network; use hex; @@ -728,7 +1035,7 @@ mod tests { #[test] fn route_test() { let secp_ctx = Secp256k1::new(); - let our_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap()); + let our_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap()); let logger: Arc = Arc::new(test_utils::TestLogger::new()); let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger))); let router = Router::new(our_id, chain_monitor, Arc::clone(&logger)); @@ -790,16 +1097,16 @@ mod tests { // chan11 1-to-2: enabled, 0 fee // chan11 2-to-1: enabled, 0 fee - let node1 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()[..]).unwrap()); - let node2 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()[..]).unwrap()); - let node3 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap()[..]).unwrap()); - let node4 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0505050505050505050505050505050505050505050505050505050505050505").unwrap()[..]).unwrap()); - let node5 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0606060606060606060606060606060606060606060606060606060606060606").unwrap()[..]).unwrap()); - let node6 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0707070707070707070707070707070707070707070707070707070707070707").unwrap()[..]).unwrap()); - let node7 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0808080808080808080808080808080808080808080808080808080808080808").unwrap()[..]).unwrap()); - let node8 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0909090909090909090909090909090909090909090909090909090909090909").unwrap()[..]).unwrap()); + let node1 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()[..]).unwrap()); + let node2 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()[..]).unwrap()); + let node3 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap()[..]).unwrap()); + let node4 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0505050505050505050505050505050505050505050505050505050505050505").unwrap()[..]).unwrap()); + let node5 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0606060606060606060606060606060606060606060606060606060606060606").unwrap()[..]).unwrap()); + let node6 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0707070707070707070707070707070707070707070707070707070707070707").unwrap()[..]).unwrap()); + let node7 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0808080808080808080808080808080808080808080808080808080808080808").unwrap()[..]).unwrap()); + let node8 = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0909090909090909090909090909090909090909090909090909090909090909").unwrap()[..]).unwrap()); - let zero_hash = Sha256dHash::from_data(&[0; 32]); + let zero_hash = Sha256dHash::hash(&[0; 32]); { let mut network = router.network_map.write().unwrap(); @@ -813,6 +1120,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(1, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -824,6 +1132,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: u32::max_value(), // This value should be ignored fee_proportional_millionths: u32::max_value(), // This value should be ignored + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node1.clone(), last_update: 0, @@ -832,7 +1141,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.nodes.insert(node2.clone(), NodeInfo { channels: vec!(NetworkMap::get_key(2, zero_hash.clone()), NetworkMap::get_key(4, zero_hash.clone())), @@ -843,6 +1154,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(2, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -854,6 +1166,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: u32::max_value(), // This value should be ignored fee_proportional_millionths: u32::max_value(), // This value should be ignored + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node2.clone(), last_update: 0, @@ -862,7 +1175,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.nodes.insert(node8.clone(), NodeInfo { channels: vec!(NetworkMap::get_key(12, zero_hash.clone()), NetworkMap::get_key(13, zero_hash.clone())), @@ -873,6 +1188,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(12, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -884,6 +1200,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: u32::max_value(), // This value should be ignored fee_proportional_millionths: u32::max_value(), // This value should be ignored + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node8.clone(), last_update: 0, @@ -892,7 +1209,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.nodes.insert(node3.clone(), NodeInfo { channels: vec!( @@ -909,6 +1228,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(3, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -920,6 +1240,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node3.clone(), last_update: 0, @@ -928,7 +1249,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 100, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(4, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -940,6 +1263,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 1000000, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node3.clone(), last_update: 0, @@ -948,7 +1272,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(13, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -960,6 +1286,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 2000000, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node3.clone(), last_update: 0, @@ -968,7 +1295,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.nodes.insert(node4.clone(), NodeInfo { channels: vec!(NetworkMap::get_key(5, zero_hash.clone()), NetworkMap::get_key(11, zero_hash.clone())), @@ -979,6 +1308,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(5, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -990,6 +1320,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 100, fee_proportional_millionths: 0, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node4.clone(), last_update: 0, @@ -998,7 +1329,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.nodes.insert(node5.clone(), NodeInfo { channels: vec!(NetworkMap::get_key(6, zero_hash.clone()), NetworkMap::get_key(11, zero_hash.clone())), @@ -1009,6 +1342,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(6, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -1020,6 +1354,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node5.clone(), last_update: 0, @@ -1028,7 +1363,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(11, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -1040,6 +1377,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node4.clone(), last_update: 0, @@ -1048,7 +1386,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); network.nodes.insert(node6.clone(), NodeInfo { channels: vec!(NetworkMap::get_key(7, zero_hash.clone())), @@ -1059,6 +1399,7 @@ mod tests { rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), + announcement_message: None, }); network.channels.insert(NetworkMap::get_key(7, zero_hash.clone()), ChannelInfo { features: GlobalFeatures::new(), @@ -1070,6 +1411,7 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 1000000, + last_update_message: None, }, two_to_one: DirectionalChannelInfo { src_node_id: node6.clone(), last_update: 0, @@ -1078,7 +1420,9 @@ mod tests { htlc_minimum_msat: 0, fee_base_msat: 0, fee_proportional_millionths: 0, + last_update_message: None, }, + announcement_message: None, }); } @@ -1270,5 +1614,14 @@ mod tests { assert_eq!(route.hops[4].fee_msat, 2000); assert_eq!(route.hops[4].cltv_expiry_delta, 42); } + + { // Test Router serialization/deserialization + let mut w = TestVecWriter(Vec::new()); + let network = router.network_map.read().unwrap(); + assert!(!network.channels.is_empty()); + assert!(!network.nodes.is_empty()); + network.write(&mut w).unwrap(); + assert!(::read(&mut ::std::io::Cursor::new(&w.0)).unwrap() == *network); + } } }