X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Frouter.rs;h=fb2364f7da3b062a48b941d9e49ba81ec07c7c6b;hb=4bd2c974a2c96a2ce98a4055a72b2b3c687e78bc;hp=0025656087bce2228a7376f2af906a5e0c131e7d;hpb=f70058ea4c451955e72b15d24b67d941d7f3e467;p=rust-lightning diff --git a/lightning/src/ln/router.rs b/lightning/src/ln/router.rs index 00256560..fb2364f7 100644 --- a/lightning/src/ln/router.rs +++ b/lightning/src/ln/router.rs @@ -22,6 +22,7 @@ use util::logger::Logger; use std::cmp; use std::sync::{RwLock,Arc}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::collections::{HashMap,BinaryHeap,BTreeMap}; use std::collections::btree_map::Entry as BtreeEntry; use std; @@ -46,19 +47,10 @@ pub struct RouteHop { pub cltv_expiry_delta: u32, } -/// A route from us through the network to a destination -#[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 - /// length. - pub hops: Vec, -} - -impl Writeable for Route { +impl Writeable for Vec { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { - (self.hops.len() as u8).write(writer)?; - for hop in self.hops.iter() { + (self.len() as u8).write(writer)?; + for hop in self.iter() { hop.pubkey.write(writer)?; hop.node_features.write(writer)?; hop.short_channel_id.write(writer)?; @@ -70,8 +62,8 @@ impl Writeable for Route { } } -impl Readable for Route { - fn read(reader: &mut R) -> Result { +impl Readable for Vec { + fn read(reader: &mut R) -> Result, DecodeError> { let hops_count: u8 = Readable::read(reader)?; let mut hops = Vec::with_capacity(hops_count as usize); for _ in 0..hops_count { @@ -84,9 +76,41 @@ impl Readable for Route { cltv_expiry_delta: Readable::read(reader)?, }); } - Ok(Route { - hops - }) + Ok(hops) + } +} + +/// A route directs a payment from the sender (us) to the recipient. If the recipient supports MPP, +/// it can take multiple paths. Each path is composed of one or more hops through the network. +#[derive(Clone, PartialEq)] +pub struct Route { + /// The list of routes taken for a single (potentially-)multi-part payment. The pubkey of the + /// last RouteHop in each path must be the same. + /// Each entry represents a list of hops, NOT INCLUDING our own, where the last hop is the + /// destination. Thus, this must always be at least length one. While the maximum length of any + /// given path is variable, keeping the length of any path to less than 20 should currently + /// ensure it is viable. + pub paths: Vec>, +} + +impl Writeable for Route { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + (self.paths.len() as u64).write(writer)?; + for hops in self.paths.iter() { + hops.write(writer)?; + } + Ok(()) + } +} + +impl Readable for Route { + fn read(reader: &mut R) -> Result { + let path_count: u64 = Readable::read(reader)?; + let mut paths = Vec::with_capacity(cmp::min(path_count, 128) as usize); + for _ in 0..path_count { + paths.push(Readable::read(reader)?); + } + Ok(Route { paths }) } } @@ -155,7 +179,10 @@ struct NodeInfo { lowest_inbound_channel_fee_proportional_millionths: u32, features: NodeFeatures, - last_update: u32, + /// Unlike for channels, we may have a NodeInfo entry before having received a node_update. + /// Thus, we have to be able to capture "no update has been received", which we do with an + /// Option here. + last_update: Option, rgb: [u8; 3], alias: [u8; 32], addresses: Vec, @@ -166,7 +193,7 @@ struct NodeInfo { impl std::fmt::Display for NodeInfo { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!(f, "features: {}, last_update: {}, lowest_inbound_channel_fee_base_msat: {}, lowest_inbound_channel_fee_proportional_millionths: {}, channels: {:?}", log_bytes!(self.features.encode()), self.last_update, self.lowest_inbound_channel_fee_base_msat, self.lowest_inbound_channel_fee_proportional_millionths, &self.channels[..])?; + write!(f, "features: {}, last_update: {:?}, lowest_inbound_channel_fee_base_msat: {}, lowest_inbound_channel_fee_proportional_millionths: {}, channels: {:?}", log_bytes!(self.features.encode()), self.last_update, self.lowest_inbound_channel_fee_base_msat, self.lowest_inbound_channel_fee_proportional_millionths, &self.channels[..])?; Ok(()) } } @@ -194,8 +221,8 @@ impl Writeable for NodeInfo { const MAX_ALLOC_SIZE: u64 = 64*1024; -impl Readable for NodeInfo { - fn read(reader: &mut R) -> Result { +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 { @@ -260,8 +287,8 @@ impl Writeable for NetworkMap { } } -impl Readable for NetworkMap { - fn read(reader: &mut R) -> Result { +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 { @@ -347,6 +374,7 @@ pub struct RouteHint { pub struct Router { secp_ctx: Secp256k1, network_map: RwLock, + full_syncs_requested: AtomicUsize, chain_monitor: Arc, logger: Arc, } @@ -379,8 +407,8 @@ pub struct RouterReadArgs { pub logger: Arc, } -impl ReadableArgs for Router { - fn read(reader: &mut R, args: RouterReadArgs) -> Result { +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 { @@ -390,6 +418,7 @@ impl ReadableArgs for Router { Ok(Router { secp_ctx: Secp256k1::verification_only(), network_map: RwLock::new(network_map), + full_syncs_requested: AtomicUsize::new(0), chain_monitor: args.chain_monitor, logger: args.logger, }) @@ -406,6 +435,7 @@ macro_rules! secp_verify_sig { } impl RoutingMessageHandler for Router { + fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result { 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); @@ -414,12 +444,15 @@ impl RoutingMessageHandler for Router { match network.nodes.get_mut(&msg.contents.node_id) { None => Err(LightningError{err: "No existing channels for node_announcement", action: ErrorAction::IgnoreError}), Some(node) => { - if node.last_update >= msg.contents.timestamp { - return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError}); + match node.last_update { + Some(last_update) => if last_update >= msg.contents.timestamp { + return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError}); + }, + None => {}, } node.features = msg.contents.features.clone(); - node.last_update = msg.contents.timestamp; + node.last_update = Some(msg.contents.timestamp); node.rgb = msg.contents.rgb; node.alias = msg.contents.alias; node.addresses = msg.contents.addresses.clone(); @@ -535,7 +568,7 @@ impl RoutingMessageHandler for Router { lowest_inbound_channel_fee_base_msat: u32::max_value(), lowest_inbound_channel_fee_proportional_millionths: u32::max_value(), features: NodeFeatures::empty(), - last_update: 0, + last_update: None, rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -549,6 +582,7 @@ impl RoutingMessageHandler for Router { add_channel_to_node!(msg.contents.node_id_1); add_channel_to_node!(msg.contents.node_id_2); + log_trace!(self, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !should_relay { " with excess uninterpreted data!" } else { "" }); Ok(should_relay) } @@ -653,19 +687,16 @@ 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)> { + fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option, Option)> { 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() { + if chan.announcement_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())); + chan.one_to_two.last_update_message.clone(), + chan.two_to_one.last_update_message.clone())); } 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. @@ -698,6 +729,17 @@ impl RoutingMessageHandler for Router { } result } + + fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { + //TODO: Determine whether to request a full sync based on the network map. + const FULL_SYNCS_TO_REQUEST: usize = 5; + if self.full_syncs_requested.load(Ordering::Acquire) < FULL_SYNCS_TO_REQUEST { + self.full_syncs_requested.fetch_add(1, Ordering::AcqRel); + true + } else { + false + } + } } #[derive(Eq, PartialEq)] @@ -737,7 +779,7 @@ impl Router { lowest_inbound_channel_fee_base_msat: u32::max_value(), lowest_inbound_channel_fee_proportional_millionths: u32::max_value(), features: NodeFeatures::empty(), - last_update: 0, + last_update: None, rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -750,6 +792,7 @@ impl Router { our_node_id: our_pubkey, nodes: nodes, }), + full_syncs_requested: AtomicUsize::new(0), chain_monitor, logger, } @@ -848,14 +891,14 @@ impl Router { let short_channel_id = chan.short_channel_id.expect("first_hops should be filled in with usable channels, not pending ones"); if chan.remote_network_id == *target { return Ok(Route { - hops: vec![RouteHop { + paths: vec![vec![RouteHop { pubkey: chan.remote_network_id, - node_features: NodeFeatures::with_known_relevant_init_flags(&chan.counterparty_features), + node_features: chan.counterparty_features.to_context(), short_channel_id, - channel_features: ChannelFeatures::with_known_relevant_init_flags(&chan.counterparty_features), + channel_features: chan.counterparty_features.to_context(), fee_msat: final_value_msat, cltv_expiry_delta: final_cltv, - }], + }]], }); } first_hop_targets.insert(chan.remote_network_id, (short_channel_id, chan.counterparty_features.clone())); @@ -929,7 +972,7 @@ impl Router { ( $node: expr, $node_id: expr, $fee_to_target_msat: expr ) => { if first_hops.is_some() { if let Some(&(ref first_hop, ref features)) = first_hop_targets.get(&$node_id) { - add_entry!(first_hop, $node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), $fee_to_target_msat); + add_entry!(first_hop, $node_id, dummy_directional_info, features.to_context(), $fee_to_target_msat); } } @@ -973,7 +1016,7 @@ impl Router { // bit lazy here. In the future, we should pull them out via our // ChannelManager, but there's no reason to waste the space until we // need them. - add_entry!(first_hop, hop.src_node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), 0); + add_entry!(first_hop, hop.src_node_id, dummy_directional_info, features.to_context(), 0); } } // BOLT 11 doesn't allow inclusion of features for the last hop hints, which @@ -988,7 +1031,7 @@ impl Router { let mut res = vec!(dist.remove(&network.our_node_id).unwrap().3); loop { if let Some(&(_, ref features)) = first_hop_targets.get(&res.last().unwrap().pubkey) { - res.last_mut().unwrap().node_features = NodeFeatures::with_known_relevant_init_flags(&features); + res.last_mut().unwrap().node_features = features.to_context(); } else if let Some(node) = network.nodes.get(&res.last().unwrap().pubkey) { res.last_mut().unwrap().node_features = node.features.clone(); } else { @@ -1012,7 +1055,7 @@ impl Router { } res.last_mut().unwrap().fee_msat = final_value_msat; res.last_mut().unwrap().cltv_expiry_delta = final_cltv; - let route = Route { hops: res }; + let route = Route { paths: vec![res] }; log_trace!(self, "Got route: {}", log_route!(route)); return Ok(route); } @@ -1035,7 +1078,8 @@ mod tests { use ln::channelmanager; use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint}; use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; - use ln::msgs::{LightningError, ErrorAction}; + use ln::msgs::{ErrorAction, LightningError, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement, + UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, HTLCFailChannelUpdate}; use util::test_utils; use util::test_utils::TestVecWriter; use util::logger::Logger; @@ -1044,21 +1088,32 @@ mod tests { use bitcoin_hashes::sha256d::Hash as Sha256dHash; use bitcoin_hashes::Hash; use bitcoin::network::constants::Network; + use bitcoin::blockdata::constants::genesis_block; + use bitcoin::blockdata::script::Builder; + use bitcoin::blockdata::opcodes; + use bitcoin::util::hash::BitcoinHash; use hex; use secp256k1::key::{PublicKey,SecretKey}; + use secp256k1::All; use secp256k1::Secp256k1; use std::sync::Arc; + use std::collections::btree_map::Entry as BtreeEntry; - #[test] - fn route_test() { + fn create_router() -> (Secp256k1, PublicKey, Router) { let secp_ctx = Secp256k1::new(); 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)); + (secp_ctx, our_id, router) + } + + #[test] + fn route_test() { + let (secp_ctx, our_id, router) = create_router(); // Build network from our_id to node8: // @@ -1153,7 +1208,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 100, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(1)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1187,7 +1242,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 0, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(2)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1221,7 +1276,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 0, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(8)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1261,7 +1316,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 0, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(3)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1341,7 +1396,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 0, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(4)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1375,7 +1430,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 0, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(5)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1432,7 +1487,7 @@ mod tests { lowest_inbound_channel_fee_base_msat: 0, lowest_inbound_channel_fee_proportional_millionths: 0, features: NodeFeatures::from_le_bytes(id_to_feature_flags!(6)), - last_update: 1, + last_update: Some(1), rgb: [0; 3], alias: [0; 32], addresses: Vec::new(), @@ -1465,21 +1520,21 @@ mod tests { { // Simple route to 3 via 2 let route = router.get_route(&node3, None, &Vec::new(), 100, 42).unwrap(); - assert_eq!(route.hops.len(), 2); - - assert_eq!(route.hops[0].pubkey, node2); - assert_eq!(route.hops[0].short_channel_id, 2); - assert_eq!(route.hops[0].fee_msat, 100); - assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2)); - assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2)); - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 4); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, 42); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4)); + assert_eq!(route.paths[0].len(), 2); + + assert_eq!(route.paths[0][0].pubkey, node2); + assert_eq!(route.paths[0][0].short_channel_id, 2); + assert_eq!(route.paths[0][0].fee_msat, 100); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (4 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags!(2)); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags!(2)); + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 4); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(4)); } { // Disable channels 4 and 12 by requiring unknown feature bits @@ -1507,21 +1562,21 @@ mod tests { is_live: true, }]; let route = router.get_route(&node3, Some(&our_chans), &Vec::new(), 100, 42).unwrap(); - assert_eq!(route.hops.len(), 2); - - assert_eq!(route.hops[0].pubkey, node8); - assert_eq!(route.hops[0].short_channel_id, 42); - assert_eq!(route.hops[0].fee_msat, 200); - assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features - assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 13); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, 42); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13)); + assert_eq!(route.paths[0].len(), 2); + + assert_eq!(route.paths[0][0].pubkey, node8); + assert_eq!(route.paths[0][0].short_channel_id, 42); + assert_eq!(route.paths[0][0].fee_msat, 200); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (13 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features + assert_eq!(route.paths[0][0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 13); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(13)); } { // Re-enable channels 4 and 12 by wiping the unknown feature bits @@ -1556,21 +1611,21 @@ mod tests { is_live: true, }]; let route = router.get_route(&node3, Some(&our_chans), &Vec::new(), 100, 42).unwrap(); - assert_eq!(route.hops.len(), 2); - - assert_eq!(route.hops[0].pubkey, node8); - assert_eq!(route.hops[0].short_channel_id, 42); - assert_eq!(route.hops[0].fee_msat, 200); - assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features - assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 13); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, 42); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13)); + assert_eq!(route.paths[0].len(), 2); + + assert_eq!(route.paths[0][0].pubkey, node8); + assert_eq!(route.paths[0][0].short_channel_id, 42); + assert_eq!(route.paths[0][0].fee_msat, 200); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (13 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features + assert_eq!(route.paths[0][0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 13); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(13)); } { // Re-enable nodes 1, 2, and 8 @@ -1586,28 +1641,28 @@ mod tests { { // Route to 1 via 2 and 3 because our channel to 1 is disabled let route = router.get_route(&node1, None, &Vec::new(), 100, 42).unwrap(); - assert_eq!(route.hops.len(), 3); - - assert_eq!(route.hops[0].pubkey, node2); - assert_eq!(route.hops[0].short_channel_id, 2); - assert_eq!(route.hops[0].fee_msat, 200); - assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2)); - assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2)); - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 4); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, (3 << 8) | 2); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4)); - - assert_eq!(route.hops[2].pubkey, node1); - assert_eq!(route.hops[2].short_channel_id, 3); - assert_eq!(route.hops[2].fee_msat, 100); - assert_eq!(route.hops[2].cltv_expiry_delta, 42); - assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(1)); - assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0].len(), 3); + + assert_eq!(route.paths[0][0].pubkey, node2); + assert_eq!(route.paths[0][0].short_channel_id, 2); + assert_eq!(route.paths[0][0].fee_msat, 200); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (4 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags!(2)); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags!(2)); + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 4); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, (3 << 8) | 2); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(4)); + + assert_eq!(route.paths[0][2].pubkey, node1); + assert_eq!(route.paths[0][2].short_channel_id, 3); + assert_eq!(route.paths[0][2].fee_msat, 100); + assert_eq!(route.paths[0][2].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags!(1)); + assert_eq!(route.paths[0][2].channel_features.le_flags(), &id_to_feature_flags!(3)); } { // If we specify a channel to node8, that overrides our local channel view and that gets used @@ -1623,21 +1678,21 @@ mod tests { is_live: true, }]; let route = router.get_route(&node3, Some(&our_chans), &Vec::new(), 100, 42).unwrap(); - assert_eq!(route.hops.len(), 2); - - assert_eq!(route.hops[0].pubkey, node8); - assert_eq!(route.hops[0].short_channel_id, 42); - assert_eq!(route.hops[0].fee_msat, 200); - assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); - assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 13); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, 42); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13)); + assert_eq!(route.paths[0].len(), 2); + + assert_eq!(route.paths[0][0].pubkey, node8); + assert_eq!(route.paths[0][0].short_channel_id, 42); + assert_eq!(route.paths[0][0].fee_msat, 200); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (13 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &vec![0b11]); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 13); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(13)); } let mut last_hops = vec!(RouteHint { @@ -1665,44 +1720,44 @@ mod tests { { // Simple test across 2, 3, 5, and 4 via a last_hop channel let route = router.get_route(&node7, None, &last_hops, 100, 42).unwrap(); - assert_eq!(route.hops.len(), 5); - - assert_eq!(route.hops[0].pubkey, node2); - assert_eq!(route.hops[0].short_channel_id, 2); - assert_eq!(route.hops[0].fee_msat, 100); - assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2)); - assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2)); - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 4); - assert_eq!(route.hops[1].fee_msat, 0); - assert_eq!(route.hops[1].cltv_expiry_delta, (6 << 8) | 1); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4)); - - assert_eq!(route.hops[2].pubkey, node5); - assert_eq!(route.hops[2].short_channel_id, 6); - assert_eq!(route.hops[2].fee_msat, 0); - assert_eq!(route.hops[2].cltv_expiry_delta, (11 << 8) | 1); - assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(5)); - assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(6)); - - assert_eq!(route.hops[3].pubkey, node4); - assert_eq!(route.hops[3].short_channel_id, 11); - assert_eq!(route.hops[3].fee_msat, 0); - assert_eq!(route.hops[3].cltv_expiry_delta, (8 << 8) | 1); + assert_eq!(route.paths[0].len(), 5); + + assert_eq!(route.paths[0][0].pubkey, node2); + assert_eq!(route.paths[0][0].short_channel_id, 2); + assert_eq!(route.paths[0][0].fee_msat, 100); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (4 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags!(2)); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags!(2)); + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 4); + assert_eq!(route.paths[0][1].fee_msat, 0); + assert_eq!(route.paths[0][1].cltv_expiry_delta, (6 << 8) | 1); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(4)); + + assert_eq!(route.paths[0][2].pubkey, node5); + assert_eq!(route.paths[0][2].short_channel_id, 6); + assert_eq!(route.paths[0][2].fee_msat, 0); + assert_eq!(route.paths[0][2].cltv_expiry_delta, (11 << 8) | 1); + assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags!(5)); + assert_eq!(route.paths[0][2].channel_features.le_flags(), &id_to_feature_flags!(6)); + + assert_eq!(route.paths[0][3].pubkey, node4); + assert_eq!(route.paths[0][3].short_channel_id, 11); + assert_eq!(route.paths[0][3].fee_msat, 0); + assert_eq!(route.paths[0][3].cltv_expiry_delta, (8 << 8) | 1); // If we have a peer in the node map, we'll use their features here since we don't have // a way of figuring out their features from the invoice: - assert_eq!(route.hops[3].node_features.le_flags(), &id_to_feature_flags!(4)); - assert_eq!(route.hops[3].channel_features.le_flags(), &id_to_feature_flags!(11)); - - assert_eq!(route.hops[4].pubkey, node7); - assert_eq!(route.hops[4].short_channel_id, 8); - assert_eq!(route.hops[4].fee_msat, 100); - assert_eq!(route.hops[4].cltv_expiry_delta, 42); - assert_eq!(route.hops[4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet - assert_eq!(route.hops[4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly + assert_eq!(route.paths[0][3].node_features.le_flags(), &id_to_feature_flags!(4)); + assert_eq!(route.paths[0][3].channel_features.le_flags(), &id_to_feature_flags!(11)); + + assert_eq!(route.paths[0][4].pubkey, node7); + assert_eq!(route.paths[0][4].short_channel_id, 8); + assert_eq!(route.paths[0][4].fee_msat, 100); + assert_eq!(route.paths[0][4].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet + assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly } { // Simple test with outbound channel to 4 to test that last_hops and first_hops connect @@ -1718,100 +1773,100 @@ mod tests { is_live: true, }]; let route = router.get_route(&node7, Some(&our_chans), &last_hops, 100, 42).unwrap(); - assert_eq!(route.hops.len(), 2); - - assert_eq!(route.hops[0].pubkey, node4); - assert_eq!(route.hops[0].short_channel_id, 42); - assert_eq!(route.hops[0].fee_msat, 0); - assert_eq!(route.hops[0].cltv_expiry_delta, (8 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); - assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion - - assert_eq!(route.hops[1].pubkey, node7); - assert_eq!(route.hops[1].short_channel_id, 8); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, 42); - assert_eq!(route.hops[1].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet - assert_eq!(route.hops[1].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly + assert_eq!(route.paths[0].len(), 2); + + assert_eq!(route.paths[0][0].pubkey, node4); + assert_eq!(route.paths[0][0].short_channel_id, 42); + assert_eq!(route.paths[0][0].fee_msat, 0); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (8 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &vec![0b11]); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion + + assert_eq!(route.paths[0][1].pubkey, node7); + assert_eq!(route.paths[0][1].short_channel_id, 8); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][1].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet + assert_eq!(route.paths[0][1].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly } last_hops[0].fee_base_msat = 1000; { // Revert to via 6 as the fee on 8 goes up let route = router.get_route(&node7, None, &last_hops, 100, 42).unwrap(); - assert_eq!(route.hops.len(), 4); - - assert_eq!(route.hops[0].pubkey, node2); - assert_eq!(route.hops[0].short_channel_id, 2); - assert_eq!(route.hops[0].fee_msat, 200); // fee increased as its % of value transferred across node - assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2)); - assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2)); - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 4); - assert_eq!(route.hops[1].fee_msat, 100); - assert_eq!(route.hops[1].cltv_expiry_delta, (7 << 8) | 1); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4)); - - assert_eq!(route.hops[2].pubkey, node6); - assert_eq!(route.hops[2].short_channel_id, 7); - assert_eq!(route.hops[2].fee_msat, 0); - assert_eq!(route.hops[2].cltv_expiry_delta, (10 << 8) | 1); + assert_eq!(route.paths[0].len(), 4); + + assert_eq!(route.paths[0][0].pubkey, node2); + assert_eq!(route.paths[0][0].short_channel_id, 2); + assert_eq!(route.paths[0][0].fee_msat, 200); // fee increased as its % of value transferred across node + assert_eq!(route.paths[0][0].cltv_expiry_delta, (4 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags!(2)); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags!(2)); + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 4); + assert_eq!(route.paths[0][1].fee_msat, 100); + assert_eq!(route.paths[0][1].cltv_expiry_delta, (7 << 8) | 1); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(4)); + + assert_eq!(route.paths[0][2].pubkey, node6); + assert_eq!(route.paths[0][2].short_channel_id, 7); + assert_eq!(route.paths[0][2].fee_msat, 0); + assert_eq!(route.paths[0][2].cltv_expiry_delta, (10 << 8) | 1); // If we have a peer in the node map, we'll use their features here since we don't have // a way of figuring out their features from the invoice: - assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(6)); - assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(7)); - - assert_eq!(route.hops[3].pubkey, node7); - assert_eq!(route.hops[3].short_channel_id, 10); - assert_eq!(route.hops[3].fee_msat, 100); - assert_eq!(route.hops[3].cltv_expiry_delta, 42); - assert_eq!(route.hops[3].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet - assert_eq!(route.hops[3].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly + assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags!(6)); + assert_eq!(route.paths[0][2].channel_features.le_flags(), &id_to_feature_flags!(7)); + + assert_eq!(route.paths[0][3].pubkey, node7); + assert_eq!(route.paths[0][3].short_channel_id, 10); + assert_eq!(route.paths[0][3].fee_msat, 100); + assert_eq!(route.paths[0][3].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet + assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly } { // ...but still use 8 for larger payments as 6 has a variable feerate let route = router.get_route(&node7, None, &last_hops, 2000, 42).unwrap(); - assert_eq!(route.hops.len(), 5); - - assert_eq!(route.hops[0].pubkey, node2); - assert_eq!(route.hops[0].short_channel_id, 2); - assert_eq!(route.hops[0].fee_msat, 3000); - assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1); - assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2)); - assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2)); - - assert_eq!(route.hops[1].pubkey, node3); - assert_eq!(route.hops[1].short_channel_id, 4); - assert_eq!(route.hops[1].fee_msat, 0); - assert_eq!(route.hops[1].cltv_expiry_delta, (6 << 8) | 1); - assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3)); - assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4)); - - assert_eq!(route.hops[2].pubkey, node5); - assert_eq!(route.hops[2].short_channel_id, 6); - assert_eq!(route.hops[2].fee_msat, 0); - assert_eq!(route.hops[2].cltv_expiry_delta, (11 << 8) | 1); - assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(5)); - assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(6)); - - assert_eq!(route.hops[3].pubkey, node4); - assert_eq!(route.hops[3].short_channel_id, 11); - assert_eq!(route.hops[3].fee_msat, 1000); - assert_eq!(route.hops[3].cltv_expiry_delta, (8 << 8) | 1); + assert_eq!(route.paths[0].len(), 5); + + assert_eq!(route.paths[0][0].pubkey, node2); + assert_eq!(route.paths[0][0].short_channel_id, 2); + assert_eq!(route.paths[0][0].fee_msat, 3000); + assert_eq!(route.paths[0][0].cltv_expiry_delta, (4 << 8) | 1); + assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags!(2)); + assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags!(2)); + + assert_eq!(route.paths[0][1].pubkey, node3); + assert_eq!(route.paths[0][1].short_channel_id, 4); + assert_eq!(route.paths[0][1].fee_msat, 0); + assert_eq!(route.paths[0][1].cltv_expiry_delta, (6 << 8) | 1); + assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags!(3)); + assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags!(4)); + + assert_eq!(route.paths[0][2].pubkey, node5); + assert_eq!(route.paths[0][2].short_channel_id, 6); + assert_eq!(route.paths[0][2].fee_msat, 0); + assert_eq!(route.paths[0][2].cltv_expiry_delta, (11 << 8) | 1); + assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags!(5)); + assert_eq!(route.paths[0][2].channel_features.le_flags(), &id_to_feature_flags!(6)); + + assert_eq!(route.paths[0][3].pubkey, node4); + assert_eq!(route.paths[0][3].short_channel_id, 11); + assert_eq!(route.paths[0][3].fee_msat, 1000); + assert_eq!(route.paths[0][3].cltv_expiry_delta, (8 << 8) | 1); // If we have a peer in the node map, we'll use their features here since we don't have // a way of figuring out their features from the invoice: - assert_eq!(route.hops[3].node_features.le_flags(), &id_to_feature_flags!(4)); - assert_eq!(route.hops[3].channel_features.le_flags(), &id_to_feature_flags!(11)); - - assert_eq!(route.hops[4].pubkey, node7); - assert_eq!(route.hops[4].short_channel_id, 8); - assert_eq!(route.hops[4].fee_msat, 2000); - assert_eq!(route.hops[4].cltv_expiry_delta, 42); - assert_eq!(route.hops[4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet - assert_eq!(route.hops[4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly + assert_eq!(route.paths[0][3].node_features.le_flags(), &id_to_feature_flags!(4)); + assert_eq!(route.paths[0][3].channel_features.le_flags(), &id_to_feature_flags!(11)); + + assert_eq!(route.paths[0][4].pubkey, node7); + assert_eq!(route.paths[0][4].short_channel_id, 8); + assert_eq!(route.paths[0][4].fee_msat, 2000); + assert_eq!(route.paths[0][4].cltv_expiry_delta, 42); + assert_eq!(route.paths[0][4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet + assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly } { // Test Router serialization/deserialization @@ -1823,4 +1878,783 @@ mod tests { assert!(::read(&mut ::std::io::Cursor::new(&w.0)).unwrap() == *network); } } + + #[test] + fn request_full_sync_finite_times() { + let (secp_ctx, _, router) = create_router(); + let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()[..]).unwrap()); + + assert!(router.should_request_full_sync(&node_id)); + assert!(router.should_request_full_sync(&node_id)); + assert!(router.should_request_full_sync(&node_id)); + assert!(router.should_request_full_sync(&node_id)); + assert!(router.should_request_full_sync(&node_id)); + assert!(!router.should_request_full_sync(&node_id)); + } + + #[test] + fn handling_node_announcements() { + let (secp_ctx, _, router) = create_router(); + + let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); + let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey); + let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap(); + let zero_hash = Sha256dHash::hash(&[0; 32]); + let first_announcement_time = 500; + + let mut unsigned_announcement = UnsignedNodeAnnouncement { + features: NodeFeatures::known(), + timestamp: first_announcement_time, + node_id: node_id_1, + rgb: [0; 3], + alias: [0; 32], + addresses: Vec::new(), + excess_address_data: Vec::new(), + excess_data: Vec::new(), + }; + let mut msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = NodeAnnouncement { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_announcement.clone() + }; + + match router.handle_node_announcement(&valid_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!("No existing channels for node_announcement", e.err) + }; + + { + // Announce a channel to add a corresponding node. + let unsigned_announcement = UnsignedChannelAnnouncement { + features: ChannelFeatures::known(), + chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(), + short_channel_id: 0, + node_id_1, + node_id_2, + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey), + excess_data: Vec::new(), + }; + + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_announcement) { + Ok(res) => assert!(res), + _ => panic!() + }; + } + + match router.handle_node_announcement(&valid_announcement) { + Ok(res) => assert!(res), + Err(_) => panic!() + }; + + let fake_msghash = hash_to_message!(&zero_hash); + match router.handle_node_announcement( + &NodeAnnouncement { + signature: secp_ctx.sign(&fake_msghash, node_1_privkey), + contents: unsigned_announcement.clone() + }) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Invalid signature from remote node") + }; + + unsigned_announcement.timestamp += 1000; + unsigned_announcement.excess_data.push(1); + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let announcement_with_data = NodeAnnouncement { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_announcement.clone() + }; + // Return false because contains excess data. + match router.handle_node_announcement(&announcement_with_data) { + Ok(res) => assert!(!res), + Err(_) => panic!() + }; + unsigned_announcement.excess_data = Vec::new(); + + // Even though previous announcement was not relayed further, we still accepted it, + // so we now won't accept announcements before the previous one. + unsigned_announcement.timestamp -= 10; + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let outdated_announcement = NodeAnnouncement { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_announcement.clone() + }; + match router.handle_node_announcement(&outdated_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Update older than last processed update") + }; + } + + #[test] + fn handling_channel_announcements() { + let secp_ctx = Secp256k1::new(); + 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(test_utils::TestChainWatcher::new()); + let router = Router::new(our_id, chain_monitor.clone(), Arc::clone(&logger)); + + let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); + let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey); + let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap(); + + let good_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2) + .push_slice(&PublicKey::from_secret_key(&secp_ctx, node_1_btckey).serialize()) + .push_slice(&PublicKey::from_secret_key(&secp_ctx, node_2_btckey).serialize()) + .push_opcode(opcodes::all::OP_PUSHNUM_2) + .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); + + + let mut unsigned_announcement = UnsignedChannelAnnouncement { + features: ChannelFeatures::known(), + chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(), + short_channel_id: 0, + node_id_1, + node_id_2, + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey), + excess_data: Vec::new(), + }; + + let channel_key = NetworkMap::get_key(unsigned_announcement.short_channel_id, + unsigned_announcement.chain_hash); + + let mut msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + + // Test if the UTXO lookups were not supported + *chain_monitor.utxo_ret.lock().unwrap() = Err(chaininterface::ChainError::NotSupported); + + match router.handle_channel_announcement(&valid_announcement) { + Ok(res) => assert!(res), + _ => panic!() + }; + { + let network = router.network_map.write().unwrap(); + match network.channels.get(&channel_key) { + None => panic!(), + Some(_) => () + } + } + + // If we receive announcement for the same channel (with UTXO lookups disabled), + // drop new one on the floor, since we can't see any changes. + match router.handle_channel_announcement(&valid_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Already have knowledge of channel") + }; + + + // Test if an associated transaction were not on-chain (or not confirmed). + *chain_monitor.utxo_ret.lock().unwrap() = Err(chaininterface::ChainError::UnknownTx); + unsigned_announcement.short_channel_id += 1; + + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + + match router.handle_channel_announcement(&valid_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Channel announced without corresponding UTXO entry") + }; + + + // Now test if the transaction is found in the UTXO set and the script is correct. + unsigned_announcement.short_channel_id += 1; + *chain_monitor.utxo_ret.lock().unwrap() = Ok((good_script.clone(), 0)); + let channel_key = NetworkMap::get_key(unsigned_announcement.short_channel_id, + unsigned_announcement.chain_hash); + + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_announcement) { + Ok(res) => assert!(res), + _ => panic!() + }; + { + let network = router.network_map.write().unwrap(); + match network.channels.get(&channel_key) { + None => panic!(), + Some(_) => () + } + } + + // If we receive announcement for the same channel (but TX is not confirmed), + // drop new one on the floor, since we can't see any changes. + *chain_monitor.utxo_ret.lock().unwrap() = Err(chaininterface::ChainError::UnknownTx); + match router.handle_channel_announcement(&valid_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Channel announced without corresponding UTXO entry") + }; + + // But if it is confirmed, replace the channel + *chain_monitor.utxo_ret.lock().unwrap() = Ok((good_script, 0)); + unsigned_announcement.features = ChannelFeatures::empty(); + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_announcement) { + Ok(res) => assert!(res), + _ => panic!() + }; + { + let mut network = router.network_map.write().unwrap(); + match network.channels.entry(channel_key) { + BtreeEntry::Occupied(channel_entry) => { + assert_eq!(channel_entry.get().features, ChannelFeatures::empty()); + }, + _ => panic!() + } + } + + // Don't relay valid channels with excess data + unsigned_announcement.short_channel_id += 1; + unsigned_announcement.excess_data.push(1); + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_announcement) { + Ok(res) => assert!(!res), + _ => panic!() + }; + + unsigned_announcement.excess_data = Vec::new(); + let invalid_sig_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_1_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&invalid_sig_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Invalid signature from remote node") + }; + + unsigned_announcement.node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let channel_to_itself_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_1_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&channel_to_itself_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Channel announcement node had a channel with itself") + }; + } + + #[test] + fn handling_channel_update() { + let (secp_ctx, _, router) = create_router(); + let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); + let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey); + let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap(); + + let zero_hash = Sha256dHash::hash(&[0; 32]); + let short_channel_id = 0; + let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash(); + let channel_key = NetworkMap::get_key(short_channel_id, chain_hash); + + + { + // Announce a channel we will update + let unsigned_announcement = UnsignedChannelAnnouncement { + features: ChannelFeatures::empty(), + chain_hash, + short_channel_id, + node_id_1, + node_id_2, + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey), + excess_data: Vec::new(), + }; + + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_channel_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_channel_announcement) { + Ok(_) => (), + Err(_) => panic!() + }; + + } + + let mut unsigned_channel_update = UnsignedChannelUpdate { + chain_hash, + short_channel_id, + timestamp: 100, + flags: 0, + cltv_expiry_delta: 144, + htlc_minimum_msat: 1000000, + fee_base_msat: 10000, + fee_proportional_millionths: 20, + excess_data: Vec::new() + }; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]); + let valid_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + + match router.handle_channel_update(&valid_channel_update) { + Ok(res) => assert!(res), + _ => panic!() + }; + + { + let network = router.network_map.write().unwrap(); + match network.channels.get(&channel_key) { + None => panic!(), + Some(channel_info) => { + assert_eq!(channel_info.one_to_two.cltv_expiry_delta, 144); + assert_eq!(channel_info.two_to_one.cltv_expiry_delta, u16::max_value()); + } + } + } + + unsigned_channel_update.timestamp += 100; + unsigned_channel_update.excess_data.push(1); + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]); + let valid_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + // Return false because contains excess data + match router.handle_channel_update(&valid_channel_update) { + Ok(res) => assert!(!res), + _ => panic!() + }; + + unsigned_channel_update.short_channel_id += 1; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]); + let valid_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + + match router.handle_channel_update(&valid_channel_update) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Couldn't find channel for update") + }; + unsigned_channel_update.short_channel_id = short_channel_id; + + + // Even though previous update was not relayed further, we still accepted it, + // so we now won't accept update before the previous one. + unsigned_channel_update.timestamp -= 10; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]); + let valid_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + + match router.handle_channel_update(&valid_channel_update) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Update older than last processed update") + }; + unsigned_channel_update.timestamp += 500; + + let fake_msghash = hash_to_message!(&zero_hash); + let invalid_sig_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&fake_msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + + match router.handle_channel_update(&invalid_sig_channel_update) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Invalid signature from remote node") + }; + + } + + #[test] + fn handling_htlc_fail_channel_update() { + let (secp_ctx, our_id, router) = create_router(); + let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); + let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey); + let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap(); + + let short_channel_id = 0; + let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash(); + let channel_key = NetworkMap::get_key(short_channel_id, chain_hash); + + { + // There is only local node in the table at the beginning. + let network = router.network_map.read().unwrap(); + assert_eq!(network.nodes.len(), 1); + assert_eq!(network.nodes.contains_key(&our_id), true); + } + + { + // Announce a channel we will update + let unsigned_announcement = UnsignedChannelAnnouncement { + features: ChannelFeatures::empty(), + chain_hash, + short_channel_id, + node_id_1, + node_id_2, + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey), + excess_data: Vec::new(), + }; + + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_channel_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_channel_announcement) { + Ok(_) => (), + Err(_) => panic!() + }; + + } + + let channel_close_msg = HTLCFailChannelUpdate::ChannelClosed { + short_channel_id, + is_permanent: false + }; + + router.handle_htlc_fail_channel_update(&channel_close_msg); + + { + // Non-permanent closing just disables a channel + let network = router.network_map.write().unwrap(); + match network.channels.get(&channel_key) { + None => panic!(), + Some(channel_info) => { + assert!(!channel_info.one_to_two.enabled); + assert!(!channel_info.two_to_one.enabled); + } + } + } + + let channel_close_msg = HTLCFailChannelUpdate::ChannelClosed { + short_channel_id, + is_permanent: true + }; + + router.handle_htlc_fail_channel_update(&channel_close_msg); + + { + // Permanent closing deletes a channel + let network = router.network_map.read().unwrap(); + assert_eq!(network.channels.len(), 0); + // Nodes are also deleted because there are no associated channels anymore + // Only the local node remains in the table. + assert_eq!(network.nodes.len(), 1); + assert_eq!(network.nodes.contains_key(&our_id), true); + } + + // TODO: Test HTLCFailChannelUpdate::NodeFailure, which is not implemented yet. + } + + #[test] + fn getting_next_channel_announcements() { + let (secp_ctx, _, router) = create_router(); + let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); + let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey); + let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap(); + + let short_channel_id = 1; + let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash(); + let channel_key = NetworkMap::get_key(short_channel_id, chain_hash); + + // Channels were not announced yet. + let channels_with_announcements = router.get_next_channel_announcements(0, 1); + assert_eq!(channels_with_announcements.len(), 0); + + { + // Announce a channel we will update + let unsigned_announcement = UnsignedChannelAnnouncement { + features: ChannelFeatures::empty(), + chain_hash, + short_channel_id, + node_id_1, + node_id_2, + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey), + excess_data: Vec::new(), + }; + + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_channel_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_channel_announcement) { + Ok(_) => (), + Err(_) => panic!() + }; + } + + // Contains initial channel announcement now. + let channels_with_announcements = router.get_next_channel_announcements(channel_key, 1); + assert_eq!(channels_with_announcements.len(), 1); + if let Some(channel_announcements) = channels_with_announcements.first() { + let &(_, ref update_1, ref update_2) = channel_announcements; + assert_eq!(update_1, &None); + assert_eq!(update_2, &None); + } else { + panic!(); + } + + + { + // Valid channel update + let unsigned_channel_update = UnsignedChannelUpdate { + chain_hash, + short_channel_id, + timestamp: 101, + flags: 0, + cltv_expiry_delta: 144, + htlc_minimum_msat: 1000000, + fee_base_msat: 10000, + fee_proportional_millionths: 20, + excess_data: Vec::new() + }; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]); + let valid_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + match router.handle_channel_update(&valid_channel_update) { + Ok(_) => (), + Err(_) => panic!() + }; + } + + // Now contains an initial announcement and an update. + let channels_with_announcements = router.get_next_channel_announcements(channel_key, 1); + assert_eq!(channels_with_announcements.len(), 1); + if let Some(channel_announcements) = channels_with_announcements.first() { + let &(_, ref update_1, ref update_2) = channel_announcements; + assert_ne!(update_1, &None); + assert_eq!(update_2, &None); + } else { + panic!(); + } + + + { + // Channel update with excess data. + let unsigned_channel_update = UnsignedChannelUpdate { + chain_hash, + short_channel_id, + timestamp: 102, + flags: 0, + cltv_expiry_delta: 144, + htlc_minimum_msat: 1000000, + fee_base_msat: 10000, + fee_proportional_millionths: 20, + excess_data: [1; 3].to_vec() + }; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]); + let valid_channel_update = ChannelUpdate { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_channel_update.clone() + }; + match router.handle_channel_update(&valid_channel_update) { + Ok(_) => (), + Err(_) => panic!() + }; + } + + // Test that announcements with excess data won't be returned + let channels_with_announcements = router.get_next_channel_announcements(channel_key, 1); + assert_eq!(channels_with_announcements.len(), 1); + if let Some(channel_announcements) = channels_with_announcements.first() { + let &(_, ref update_1, ref update_2) = channel_announcements; + assert_eq!(update_1, &None); + assert_eq!(update_2, &None); + } else { + panic!(); + } + + // Further starting point have no channels after it + let channels_with_announcements = router.get_next_channel_announcements(channel_key + 1000, 1); + assert_eq!(channels_with_announcements.len(), 0); + } + + #[test] + fn getting_next_node_announcements() { + let (secp_ctx, _, router) = create_router(); + let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); + let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey); + let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); + let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap(); + + let short_channel_id = 1; + let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash(); + + // No nodes yet. + let next_announcements = router.get_next_node_announcements(None, 10); + assert_eq!(next_announcements.len(), 0); + + { + // Announce a channel to add 2 nodes + let unsigned_announcement = UnsignedChannelAnnouncement { + features: ChannelFeatures::empty(), + chain_hash, + short_channel_id, + node_id_1, + node_id_2, + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey), + excess_data: Vec::new(), + }; + + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_channel_announcement = ChannelAnnouncement { + node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), + bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), + bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), + contents: unsigned_announcement.clone(), + }; + match router.handle_channel_announcement(&valid_channel_announcement) { + Ok(_) => (), + Err(_) => panic!() + }; + } + + + // Nodes were never announced + let next_announcements = router.get_next_node_announcements(None, 3); + assert_eq!(next_announcements.len(), 0); + + { + let mut unsigned_announcement = UnsignedNodeAnnouncement { + features: NodeFeatures::known(), + timestamp: 1000, + node_id: node_id_1, + rgb: [0; 3], + alias: [0; 32], + addresses: Vec::new(), + excess_address_data: Vec::new(), + excess_data: Vec::new(), + }; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = NodeAnnouncement { + signature: secp_ctx.sign(&msghash, node_1_privkey), + contents: unsigned_announcement.clone() + }; + match router.handle_node_announcement(&valid_announcement) { + Ok(_) => (), + Err(_) => panic!() + }; + + unsigned_announcement.node_id = node_id_2; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = NodeAnnouncement { + signature: secp_ctx.sign(&msghash, node_2_privkey), + contents: unsigned_announcement.clone() + }; + + match router.handle_node_announcement(&valid_announcement) { + Ok(_) => (), + Err(_) => panic!() + }; + } + + let next_announcements = router.get_next_node_announcements(None, 3); + assert_eq!(next_announcements.len(), 2); + + // Skip the first node. + let next_announcements = router.get_next_node_announcements(Some(&node_id_1), 2); + assert_eq!(next_announcements.len(), 1); + + { + // Later announcement which should not be relayed (excess data) prevent us from sharing a node + let unsigned_announcement = UnsignedNodeAnnouncement { + features: NodeFeatures::known(), + timestamp: 1010, + node_id: node_id_2, + rgb: [0; 3], + alias: [0; 32], + addresses: Vec::new(), + excess_address_data: Vec::new(), + excess_data: [1; 3].to_vec(), + }; + let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); + let valid_announcement = NodeAnnouncement { + signature: secp_ctx.sign(&msghash, node_2_privkey), + contents: unsigned_announcement.clone() + }; + match router.handle_node_announcement(&valid_announcement) { + Ok(res) => assert!(!res), + Err(_) => panic!() + }; + } + + let next_announcements = router.get_next_node_announcements(Some(&node_id_1), 2); + assert_eq!(next_announcements.len(), 0); + + } }