Skip to content

Commit aa3478b

Browse files
Add phantom invoice route hints filtering tests
1 parent cdf574a commit aa3478b

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

lightning-invoice/src/utils.rs

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,4 +737,197 @@ mod test {
737737
_ => panic!("Unexpected event")
738738
}
739739
}
740+
741+
#[test]
742+
#[cfg(feature = "std")]
743+
fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes() {
744+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
745+
let seed_1 = [42 as u8; 32];
746+
let seed_2 = [43 as u8; 32];
747+
let cross_node_seed = [44 as u8; 32];
748+
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
749+
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
750+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
751+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
752+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
753+
let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
754+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1.1);
755+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1.0);
756+
let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
757+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
758+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
759+
760+
let payment_amt = 10_000;
761+
let (_, payment_hash, payment_secret) = {
762+
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
763+
let payment_preimage = nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
764+
(payment_preimage, payment_hash, payment_secret)
765+
};
766+
let route_hints = vec![
767+
nodes[1].node.get_phantom_route_hints(),
768+
nodes[2].node.get_phantom_route_hints(),
769+
];
770+
let invoice = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt), "test".to_string(), payment_hash, payment_secret, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
771+
772+
let hints = invoice.private_routes();
773+
assert_eq!(hints.len(), 2);
774+
775+
let mut short_chan_ids = HashSet::new();
776+
short_chan_ids.insert(chan_0_1.0.contents.short_channel_id.clone());
777+
short_chan_ids.insert(chan_0_2.0.contents.short_channel_id.clone());
778+
for hint in hints {
779+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
780+
assert!(short_chan_ids.contains(&hint_short_chan_id));
781+
short_chan_ids.remove(&hint_short_chan_id);
782+
}
783+
}
784+
785+
#[test]
786+
#[cfg(feature = "std")]
787+
fn test_multi_node_hints_has_only_highest_inbound_capacity_channel() {
788+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
789+
let seed_1 = [42 as u8; 32];
790+
let seed_2 = [43 as u8; 32];
791+
let cross_node_seed = [44 as u8; 32];
792+
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
793+
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
794+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
795+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
796+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
797+
let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
798+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1_low_inbound_capacity.1);
799+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1_low_inbound_capacity.0);
800+
let chan_0_1_high_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, InitFeatures::known(), InitFeatures::known());
801+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1_high_inbound_capacity.1);
802+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1_high_inbound_capacity.0);
803+
let chan_0_1_medium_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
804+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1_medium_inbound_capacity.1);
805+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1_medium_inbound_capacity.0);
806+
let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
807+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
808+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
809+
810+
let payment_amt = 10_000;
811+
let (_, payment_hash, payment_secret) = {
812+
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
813+
let payment_preimage = nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
814+
(payment_preimage, payment_hash, payment_secret)
815+
};
816+
let route_hints = vec![
817+
nodes[1].node.get_phantom_route_hints(),
818+
nodes[2].node.get_phantom_route_hints(),
819+
];
820+
let invoice = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt), "test".to_string(), payment_hash, payment_secret, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
821+
822+
let hints = invoice.private_routes();
823+
assert_eq!(hints.len(), 2);
824+
825+
let mut short_chan_ids = HashSet::new();
826+
short_chan_ids.insert(chan_0_1_high_inbound_capacity.0.contents.short_channel_id.clone());
827+
short_chan_ids.insert(chan_0_2.0.contents.short_channel_id.clone());
828+
for hint in hints {
829+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
830+
assert!(short_chan_ids.contains(&hint_short_chan_id));
831+
short_chan_ids.remove(&hint_short_chan_id);
832+
}
833+
}
834+
835+
#[test]
836+
#[cfg(feature = "std")]
837+
fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt() {
838+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
839+
let seed_1 = [42 as u8; 32];
840+
let seed_2 = [43 as u8; 32];
841+
let cross_node_seed = [44 as u8; 32];
842+
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
843+
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
844+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
845+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
846+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
847+
let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
848+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1.1);
849+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1.0);
850+
let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
851+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
852+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
853+
854+
// 1 msat above chan_0_1's inbound capacity
855+
let payment_amt_99_000_001_msat = 99_000_001;
856+
let (_, payment_hash_99_000_001_msat, payment_secret_99_000_001_msat) = {
857+
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt_99_000_001_msat), 3600).unwrap();
858+
let payment_preimage = nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
859+
(payment_preimage, payment_hash, payment_secret)
860+
};
861+
862+
let route_hints_99_000_001_msat = vec![
863+
nodes[1].node.get_phantom_route_hints(),
864+
nodes[2].node.get_phantom_route_hints(),
865+
];
866+
867+
let invoice_99_000_001_msat = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt_99_000_001_msat), "test".to_string(), payment_hash_99_000_001_msat, payment_secret_99_000_001_msat, route_hints_99_000_001_msat, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
868+
869+
let hints_99_000_001_msat = invoice_99_000_001_msat.private_routes();
870+
assert_eq!(hints_99_000_001_msat.len(), 1);
871+
872+
let mut short_chan_ids_99_000_001_msat = HashSet::new();
873+
short_chan_ids_99_000_001_msat.insert(chan_0_2.0.contents.short_channel_id.clone());
874+
for hint in hints_99_000_001_msat {
875+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
876+
assert!(short_chan_ids_99_000_001_msat.contains(&hint_short_chan_id));
877+
short_chan_ids_99_000_001_msat.remove(&hint_short_chan_id);
878+
}
879+
880+
// Exactly at chan_0_1's inbound capacity
881+
let payment_amt_99_000_000_msat = 99_000_000;
882+
let (_, payment_hash_99_000_000_msat, payment_secret_99_000_000_msat) = {
883+
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt_99_000_000_msat), 3600).unwrap();
884+
let payment_preimage = nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
885+
(payment_preimage, payment_hash, payment_secret)
886+
};
887+
888+
let route_hints_99_000_000_msat = vec![
889+
nodes[1].node.get_phantom_route_hints(),
890+
nodes[2].node.get_phantom_route_hints(),
891+
];
892+
893+
let invoice_99_000_000_msat = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt_99_000_000_msat), "test".to_string(), payment_hash_99_000_000_msat, payment_secret_99_000_000_msat, route_hints_99_000_000_msat, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
894+
895+
let hints_99_000_000_msat = invoice_99_000_000_msat.private_routes();
896+
assert_eq!(hints_99_000_000_msat.len(), 2);
897+
898+
let mut short_chan_ids_99_000_000_msat = HashSet::new();
899+
short_chan_ids_99_000_000_msat.insert(chan_0_1.0.contents.short_channel_id.clone());
900+
short_chan_ids_99_000_000_msat.insert(chan_0_2.0.contents.short_channel_id.clone());
901+
for hint in hints_99_000_000_msat {
902+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
903+
assert!(short_chan_ids_99_000_000_msat.contains(&hint_short_chan_id));
904+
short_chan_ids_99_000_000_msat.remove(&hint_short_chan_id);
905+
}
906+
907+
// An invoice with no specified amount should include all participating nodes in the hints.
908+
let (_, payment_hash_no_specified_amount, payment_secret_no_specified_amount) = {
909+
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(None, 3600).unwrap();
910+
let payment_preimage = nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
911+
(payment_preimage, payment_hash, payment_secret)
912+
};
913+
914+
let route_hints_no_specified_amount = vec![
915+
nodes[1].node.get_phantom_route_hints(),
916+
nodes[2].node.get_phantom_route_hints(),
917+
];
918+
919+
let invoice_no_specified_amount = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(None, "test".to_string(), payment_hash_no_specified_amount, payment_secret_no_specified_amount, route_hints_no_specified_amount, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
920+
921+
let hints_no_specified_amount = invoice_no_specified_amount.private_routes();
922+
assert_eq!(hints_no_specified_amount.len(), 2);
923+
924+
let mut short_chan_ids_no_specified_amount = HashSet::new();
925+
short_chan_ids_no_specified_amount.insert(chan_0_1.0.contents.short_channel_id.clone());
926+
short_chan_ids_no_specified_amount.insert(chan_0_2.0.contents.short_channel_id.clone());
927+
for hint in hints_no_specified_amount {
928+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
929+
assert!(short_chan_ids_no_specified_amount.contains(&hint_short_chan_id));
930+
short_chan_ids_no_specified_amount.remove(&hint_short_chan_id);
931+
}
932+
}
740933
}

0 commit comments

Comments
 (0)