Skip to content

Commit 52a9287

Browse files
Add tests for create invoice route hints filtering
1 parent 9ea5649 commit 52a9287

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

lightning-invoice/src/utils.rs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,9 @@ mod test {
356356
use lightning::util::enforcing_trait_impls::EnforcingSigner;
357357
use lightning::util::events::{MessageSendEvent, MessageSendEventsProvider, Event};
358358
use lightning::util::test_utils;
359+
use lightning::util::config::UserConfig;
359360
use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
361+
use std::collections::HashSet;
360362

361363
#[test]
362364
fn test_from_channelmanager() {
@@ -411,6 +413,148 @@ mod test {
411413
assert_eq!(events.len(), 2);
412414
}
413415

416+
#[test]
417+
fn test_hints_includes_single_public_channels_to_nodes() {
418+
let chanmon_cfgs = create_chanmon_cfgs(3);
419+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
420+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
421+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
422+
let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
423+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
424+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
425+
let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
426+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
427+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
428+
429+
let mut short_chan_ids = HashSet::new();
430+
short_chan_ids.insert(chan_1_0.0.contents.short_channel_id.clone());
431+
short_chan_ids.insert(chan_2_0.0.contents.short_channel_id.clone());
432+
433+
match_invoice_routes(
434+
Some(5000),
435+
&nodes[0],
436+
short_chan_ids.clone(),
437+
);
438+
}
439+
440+
#[test]
441+
fn test_hints_has_only_highest_inbound_capacity_channel() {
442+
let chanmon_cfgs = create_chanmon_cfgs(2);
443+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
444+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
445+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
446+
let chan_1_0_low_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, InitFeatures::known(), InitFeatures::known());
447+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0_low_inbound_capacity.0);
448+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0_low_inbound_capacity.1);
449+
let chan_1_0_high_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 10_000_000, 0, InitFeatures::known(), InitFeatures::known());
450+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0_high_inbound_capacity.0);
451+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0_high_inbound_capacity.1);
452+
let chan_1_0_medium_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
453+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0_medium_inbound_capacity.0);
454+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0_medium_inbound_capacity.1);
455+
456+
let mut short_chan_ids = HashSet::new();
457+
short_chan_ids.insert(chan_1_0_high_inbound_capacity.0.contents.short_channel_id.clone());
458+
459+
match_invoice_routes(
460+
Some(5000),
461+
&nodes[0],
462+
short_chan_ids.clone(),
463+
);
464+
}
465+
466+
#[test]
467+
fn test_no_hints_if_any_private_channels_exists() {
468+
let mut nodes_2_priv_channels_conf = UserConfig::default();
469+
nodes_2_priv_channels_conf.channel_options.announced_channel = false;
470+
let chanmon_cfgs = create_chanmon_cfgs(3);
471+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
472+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, Some(nodes_2_priv_channels_conf)]);
473+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
474+
let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
475+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
476+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
477+
478+
let chan_2_0 = create_private_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
479+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
480+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
481+
482+
// Ensure that the invoice doesn't include any route hints for any of `nodes[0]` channels,
483+
// even though all channels between `nodes[1]` and `nodes[0]` are public, as there is a
484+
// private channel between `nodes[2]` and `nodes[0]`
485+
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
486+
&nodes[0].node, nodes[0].keys_manager, Currency::BitcoinTestnet, Some(5000), "test".to_string(),
487+
Duration::from_secs(1234567)).unwrap();
488+
let hints = invoice.private_routes();
489+
490+
assert!(hints.is_empty());
491+
}
492+
493+
#[test]
494+
fn test_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt() {
495+
let chanmon_cfgs = create_chanmon_cfgs(3);
496+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
497+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
498+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
499+
let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, InitFeatures::known(), InitFeatures::known());
500+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
501+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
502+
let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
503+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
504+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
505+
506+
// 1 msat above chan_1_0's inbound capacity
507+
let mut short_chan_ids_99_000_001_msat = HashSet::new();
508+
short_chan_ids_99_000_001_msat.insert(chan_2_0.0.contents.short_channel_id.clone());
509+
510+
match_invoice_routes(
511+
Some(99_000_001),
512+
&nodes[0],
513+
short_chan_ids_99_000_001_msat.clone(),
514+
);
515+
516+
// Exactly at chan_1_0's inbound capacity
517+
let mut short_chan_ids_99_000_000_msat = HashSet::new();
518+
short_chan_ids_99_000_000_msat.insert(chan_1_0.0.contents.short_channel_id.clone());
519+
short_chan_ids_99_000_000_msat.insert(chan_2_0.0.contents.short_channel_id.clone());
520+
521+
match_invoice_routes(
522+
Some(99_000_000),
523+
&nodes[0],
524+
short_chan_ids_99_000_000_msat.clone(),
525+
);
526+
527+
// An invoice with no specified amount should include all route hints.
528+
let mut short_chan_ids_no_specified_amount = HashSet::new();
529+
short_chan_ids_no_specified_amount.insert(chan_1_0.0.contents.short_channel_id.clone());
530+
short_chan_ids_no_specified_amount.insert(chan_2_0.0.contents.short_channel_id.clone());
531+
532+
match_invoice_routes(
533+
None,
534+
&nodes[0],
535+
short_chan_ids_no_specified_amount.clone(),
536+
);
537+
}
538+
539+
fn match_invoice_routes<'a, 'b: 'a, 'c: 'b>(
540+
invoice_amt: Option<u64>,
541+
invoice_node: &Node<'a, 'b, 'c>,
542+
mut chan_ids_to_match: HashSet<u64>
543+
){
544+
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
545+
&invoice_node.node, invoice_node.keys_manager, Currency::BitcoinTestnet, invoice_amt, "test".to_string(),
546+
Duration::from_secs(1234567)).unwrap();
547+
let hints = invoice.private_routes();
548+
549+
assert_eq!(hints.len(), chan_ids_to_match.len());
550+
551+
for hint in hints {
552+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
553+
assert!(chan_ids_to_match.contains(&hint_short_chan_id));
554+
chan_ids_to_match.remove(&hint_short_chan_id);
555+
}
556+
}
557+
414558
#[test]
415559
#[cfg(feature = "std")]
416560
fn test_multi_node_receive() {

0 commit comments

Comments
 (0)