Skip to content

Commit 945816a

Browse files
Add phantom invoice route hints filtering tests
1 parent 1a4af35 commit 945816a

File tree

1 file changed

+153
-1
lines changed

1 file changed

+153
-1
lines changed

lightning-invoice/src/utils.rs

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ mod test {
361361
use bitcoin_hashes::sha256::Hash as Sha256;
362362
use lightning::chain::keysinterface::PhantomKeysManager;
363363
use lightning::ln::{PaymentPreimage, PaymentHash};
364-
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY;
364+
use lightning::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY};
365365
use lightning::ln::functional_test_utils::*;
366366
use lightning::ln::features::InitFeatures;
367367
use lightning::ln::msgs::ChannelMessageHandler;
@@ -707,4 +707,156 @@ mod test {
707707
_ => panic!("Unexpected event")
708708
}
709709
}
710+
711+
#[test]
712+
#[cfg(feature = "std")]
713+
fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes() {
714+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
715+
let seed_1 = [42 as u8; 32];
716+
let seed_2 = [43 as u8; 32];
717+
let cross_node_seed = [44 as u8; 32];
718+
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
719+
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
720+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
721+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
722+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
723+
let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
724+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1.1);
725+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1.0);
726+
let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
727+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
728+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
729+
730+
let mut short_chan_ids = HashSet::new();
731+
short_chan_ids.insert(chan_0_1.0.contents.short_channel_id.clone());
732+
short_chan_ids.insert(chan_0_2.0.contents.short_channel_id.clone());
733+
734+
match_multi_node_invoice_routes(
735+
Some(10_000),
736+
&nodes[1],
737+
vec![&nodes[1], &nodes[2],],
738+
short_chan_ids.clone(),
739+
);
740+
}
741+
742+
#[test]
743+
#[cfg(feature = "std")]
744+
fn test_multi_node_hints_has_only_highest_inbound_capacity_channel() {
745+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
746+
let seed_1 = [42 as u8; 32];
747+
let seed_2 = [43 as u8; 32];
748+
let cross_node_seed = [44 as u8; 32];
749+
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
750+
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
751+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
752+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
753+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
754+
let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
755+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1_low_inbound_capacity.1);
756+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1_low_inbound_capacity.0);
757+
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());
758+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1_high_inbound_capacity.1);
759+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1_high_inbound_capacity.0);
760+
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());
761+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1_medium_inbound_capacity.1);
762+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1_medium_inbound_capacity.0);
763+
let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
764+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
765+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
766+
767+
let mut short_chan_ids = HashSet::new();
768+
short_chan_ids.insert(chan_0_1_high_inbound_capacity.0.contents.short_channel_id.clone());
769+
short_chan_ids.insert(chan_0_2.0.contents.short_channel_id.clone());
770+
771+
match_multi_node_invoice_routes(
772+
Some(10_000),
773+
&nodes[1],
774+
vec![&nodes[1], &nodes[2],],
775+
short_chan_ids.clone(),
776+
);
777+
}
778+
779+
#[test]
780+
#[cfg(feature = "std")]
781+
fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt() {
782+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
783+
let seed_1 = [42 as u8; 32];
784+
let seed_2 = [43 as u8; 32];
785+
let cross_node_seed = [44 as u8; 32];
786+
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
787+
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
788+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
789+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
790+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
791+
let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
792+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1.1);
793+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1.0);
794+
let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
795+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
796+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
797+
798+
// 1 msat above chan_0_1's inbound capacity
799+
let mut short_chan_ids_99_000_001_msat = HashSet::new();
800+
short_chan_ids_99_000_001_msat.insert(chan_0_2.0.contents.short_channel_id.clone());
801+
802+
match_multi_node_invoice_routes(
803+
Some(99_000_001),
804+
&nodes[1],
805+
vec![&nodes[1], &nodes[2],],
806+
short_chan_ids_99_000_001_msat.clone(),
807+
);
808+
809+
// Exactly at chan_0_1's inbound capacity
810+
let mut short_chan_ids_99_000_000_msat = HashSet::new();
811+
short_chan_ids_99_000_000_msat.insert(chan_0_1.0.contents.short_channel_id.clone());
812+
short_chan_ids_99_000_000_msat.insert(chan_0_2.0.contents.short_channel_id.clone());
813+
814+
815+
match_multi_node_invoice_routes(
816+
Some(99_000_000),
817+
&nodes[1],
818+
vec![&nodes[1], &nodes[2],],
819+
short_chan_ids_99_000_000_msat.clone(),
820+
);
821+
822+
// An invoice with no specified amount should include all participating nodes in the hints.
823+
let mut short_chan_ids_no_specified_amount = HashSet::new();
824+
short_chan_ids_no_specified_amount.insert(chan_0_1.0.contents.short_channel_id.clone());
825+
short_chan_ids_no_specified_amount.insert(chan_0_2.0.contents.short_channel_id.clone());
826+
827+
match_multi_node_invoice_routes(
828+
None,
829+
&nodes[1],
830+
vec![&nodes[1], &nodes[2],],
831+
short_chan_ids_no_specified_amount.clone(),
832+
);
833+
}
834+
835+
#[cfg(feature = "std")]
836+
fn match_multi_node_invoice_routes<'a, 'b: 'a, 'c: 'b>(
837+
invoice_amt: Option<u64>,
838+
invoice_node: &Node<'a, 'b, 'c>,
839+
network_multi_nodes: Vec<&Node<'a, 'b, 'c>>,
840+
mut chan_ids_to_match: HashSet<u64>
841+
){
842+
let (_, payment_hash, payment_secret) = {
843+
let (payment_hash, payment_secret) = invoice_node.node.create_inbound_payment(invoice_amt, 3600).unwrap();
844+
let payment_preimage = invoice_node.node.get_payment_preimage(payment_hash, payment_secret).unwrap();
845+
(payment_preimage, payment_hash, payment_secret)
846+
};
847+
let phantom_route_hints = network_multi_nodes.iter()
848+
.map(|node| node.node.get_phantom_route_hints())
849+
.collect::<Vec<PhantomRouteHints>>();
850+
851+
let invoice = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(invoice_amt, "test".to_string(), payment_hash, payment_secret, phantom_route_hints, &invoice_node.keys_manager, Currency::BitcoinTestnet).unwrap();
852+
853+
let invoice_hints = invoice.private_routes();
854+
assert_eq!(invoice_hints.len(), chan_ids_to_match.len());
855+
856+
for hint in invoice_hints {
857+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
858+
assert!(chan_ids_to_match.contains(&hint_short_chan_id));
859+
chan_ids_to_match.remove(&hint_short_chan_id);
860+
}
861+
}
710862
}

0 commit comments

Comments
 (0)