- { // 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.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.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
- let our_chans = vec![channelmanager::ChannelDetails {
- channel_id: [0; 32],
- short_channel_id: Some(42),
- remote_network_id: node4.clone(),
- counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
- channel_value_satoshis: 0,
- user_id: 0,
- outbound_capacity_msat: 0,
- inbound_capacity_msat: 0,
- is_live: true,
- }];
- let route = router.get_route(&node7, Some(&our_chans), &last_hops, 100, 42).unwrap();
- 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.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.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.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.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
- 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!(<NetworkMap>::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<Logger> = 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);
-
+ // Simple test across 2, 3, 5, and 4 via a last_hop channel
+ let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &node7, None, &last_hops, 100, 42, Arc::clone(&logger)).unwrap();
+ 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.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::<u8>::new()); // We dont pass flags in from invoices yet
+ assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::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
+ let our_chans = vec![channelmanager::ChannelDetails {
+ channel_id: [0; 32],
+ short_channel_id: Some(42),
+ remote_network_id: node4.clone(),
+ counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
+ channel_value_satoshis: 0,
+ user_id: 0,
+ outbound_capacity_msat: 0,
+ inbound_capacity_msat: 0,
+ is_live: true,
+ }];
+ let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &node7, Some(&our_chans), &last_hops, 100, 42, Arc::clone(&logger)).unwrap();
+ 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::<u8>::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::<u8>::new()); // We dont pass flags in from invoices yet
+ assert_eq!(route.paths[0][1].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
+
+ last_hops[0].fees.base_msat = 1000;
+
+ // Revert to via 6 as the fee on 8 goes up
+ let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &node7, None, &last_hops, 100, 42, Arc::clone(&logger)).unwrap();
+ 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.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::<u8>::new()); // We dont pass flags in from invoices yet
+ assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::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 = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &node7, None, &last_hops, 2000, 42, Arc::clone(&logger)).unwrap();
+ 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.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::<u8>::new()); // We dont pass flags in from invoices yet
+ assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly