Skip to content

Commit 80731e8

Browse files
Add tests for create invoice route hints filtering
1 parent 6e9e27f commit 80731e8

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

lightning-invoice/src/utils.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,9 @@ mod test {
368368
use lightning::util::enforcing_trait_impls::EnforcingSigner;
369369
use lightning::util::events::{MessageSendEvent, MessageSendEventsProvider, Event};
370370
use lightning::util::test_utils;
371+
use lightning::util::config::UserConfig;
371372
use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
373+
use std::collections::HashSet;
372374

373375
#[test]
374376
fn test_from_channelmanager() {
@@ -423,6 +425,171 @@ mod test {
423425
assert_eq!(events.len(), 2);
424426
}
425427

428+
#[test]
429+
fn test_hints_includes_single_public_channels_to_nodes() {
430+
let chanmon_cfgs = create_chanmon_cfgs(3);
431+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
432+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
433+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
434+
let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
435+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
436+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
437+
let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
438+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
439+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
440+
441+
let mut short_chan_ids = HashSet::new();
442+
short_chan_ids.insert(chan_1_0.0.contents.short_channel_id.clone());
443+
short_chan_ids.insert(chan_2_0.0.contents.short_channel_id.clone());
444+
445+
match_invoice_routes(
446+
Some(5000),
447+
&nodes[0],
448+
short_chan_ids.clone(),
449+
);
450+
}
451+
452+
#[test]
453+
fn test_hints_has_only_highest_inbound_capacity_channel() {
454+
let chanmon_cfgs = create_chanmon_cfgs(2);
455+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
456+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
457+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
458+
let chan_1_0_low_inbound_capacity = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, InitFeatures::known(), InitFeatures::known());
459+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0_low_inbound_capacity.0);
460+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0_low_inbound_capacity.1);
461+
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());
462+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0_high_inbound_capacity.0);
463+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0_high_inbound_capacity.1);
464+
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());
465+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0_medium_inbound_capacity.0);
466+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0_medium_inbound_capacity.1);
467+
468+
let mut short_chan_ids = HashSet::new();
469+
short_chan_ids.insert(chan_1_0_high_inbound_capacity.0.contents.short_channel_id.clone());
470+
471+
match_invoice_routes(
472+
Some(5000),
473+
&nodes[0],
474+
short_chan_ids.clone(),
475+
);
476+
}
477+
478+
#[test]
479+
fn test_no_hints_if_any_private_channels_exists() {
480+
let mut nodes_2_priv_channels_conf = UserConfig::default();
481+
nodes_2_priv_channels_conf.channel_options.announced_channel = false;
482+
let chanmon_cfgs = create_chanmon_cfgs(3);
483+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
484+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, Some(nodes_2_priv_channels_conf)]);
485+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
486+
let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
487+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
488+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
489+
490+
// Creates a private channel between `nodes[2]` and `nodes[0]`. Note that create_*_chan
491+
// functions in utils can't be used, as they require announcement_signatures.
492+
nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
493+
let open_channel = get_event_msg!(nodes[2], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
494+
nodes[0].node.handle_open_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &open_channel);
495+
let accept_channel = get_event_msg!(nodes[0], MessageSendEvent::SendAcceptChannel, nodes[2].node.get_our_node_id());
496+
nodes[2].node.handle_accept_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
497+
498+
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[2], 100000, 42);
499+
nodes[2].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
500+
nodes[0].node.handle_funding_created(&nodes[2].node.get_our_node_id(), &get_event_msg!(nodes[2], MessageSendEvent::SendFundingCreated, nodes[0].node.get_our_node_id()));
501+
check_added_monitors!(nodes[0], 1);
502+
503+
let cs_funding_signed = get_event_msg!(nodes[0], MessageSendEvent::SendFundingSigned, nodes[2].node.get_our_node_id());
504+
nodes[2].node.handle_funding_signed(&nodes[0].node.get_our_node_id(), &cs_funding_signed);
505+
check_added_monitors!(nodes[2], 1);
506+
507+
let conf_height = core::cmp::max(nodes[2].best_block_info().1 + 1, nodes[0].best_block_info().1 + 1);
508+
confirm_transaction_at(&nodes[2], &tx, conf_height);
509+
connect_blocks(&nodes[2], CHAN_CONFIRM_DEPTH - 1);
510+
confirm_transaction_at(&nodes[0], &tx, conf_height);
511+
connect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH - 1);
512+
let as_funding_locked = get_event_msg!(nodes[2], MessageSendEvent::SendFundingLocked, nodes[0].node.get_our_node_id());
513+
nodes[2].node.handle_funding_locked(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendFundingLocked, nodes[2].node.get_our_node_id()));
514+
get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
515+
nodes[0].node.handle_funding_locked(&nodes[2].node.get_our_node_id(), &as_funding_locked);
516+
get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[2].node.get_our_node_id());
517+
518+
// Ensure that the invoice doesn't include any route hints for any of `nodes[0]` channels,
519+
// even though all channels between `nodes[1]` and `nodes[0]` are public.
520+
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
521+
&nodes[0].node, nodes[0].keys_manager, Currency::BitcoinTestnet, Some(5000), "test".to_string(),
522+
Duration::from_secs(1234567)).unwrap();
523+
let hints = invoice.private_routes();
524+
525+
assert!(hints.is_empty());
526+
}
527+
528+
#[test]
529+
fn test_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt() {
530+
let chanmon_cfgs = create_chanmon_cfgs(3);
531+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
532+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
533+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
534+
let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, InitFeatures::known(), InitFeatures::known());
535+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
536+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
537+
let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
538+
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
539+
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
540+
541+
// 1 msat above chan_1_0's inbound capacity
542+
let mut short_chan_ids_99_000_001_msat = HashSet::new();
543+
short_chan_ids_99_000_001_msat.insert(chan_2_0.0.contents.short_channel_id.clone());
544+
545+
match_invoice_routes(
546+
Some(99_000_001),
547+
&nodes[0],
548+
short_chan_ids_99_000_001_msat.clone(),
549+
);
550+
551+
// Exactly at chan_1_0's inbound capacity
552+
let mut short_chan_ids_99_000_000_msat = HashSet::new();
553+
short_chan_ids_99_000_000_msat.insert(chan_1_0.0.contents.short_channel_id.clone());
554+
short_chan_ids_99_000_000_msat.insert(chan_2_0.0.contents.short_channel_id.clone());
555+
556+
match_invoice_routes(
557+
Some(99_000_000),
558+
&nodes[0],
559+
short_chan_ids_99_000_000_msat.clone(),
560+
);
561+
562+
// An invoice with no specified amount should include all route hints.
563+
let mut short_chan_ids_no_specified_amount = HashSet::new();
564+
short_chan_ids_no_specified_amount.insert(chan_1_0.0.contents.short_channel_id.clone());
565+
short_chan_ids_no_specified_amount.insert(chan_2_0.0.contents.short_channel_id.clone());
566+
567+
match_invoice_routes(
568+
None,
569+
&nodes[0],
570+
short_chan_ids_no_specified_amount.clone(),
571+
);
572+
}
573+
574+
fn match_invoice_routes<'a, 'b: 'a, 'c: 'b>(
575+
invoice_amt: Option<u64>,
576+
invoice_node: &Node<'a, 'b, 'c>,
577+
mut chan_ids_to_match: HashSet<u64>
578+
){
579+
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
580+
&invoice_node.node, invoice_node.keys_manager, Currency::BitcoinTestnet, invoice_amt, "test".to_string(),
581+
Duration::from_secs(1234567)).unwrap();
582+
let hints = invoice.private_routes();
583+
584+
assert_eq!(hints.len(), chan_ids_to_match.len());
585+
586+
for hint in hints {
587+
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
588+
assert!(chan_ids_to_match.contains(&hint_short_chan_id));
589+
chan_ids_to_match.remove(&hint_short_chan_id);
590+
}
591+
}
592+
426593
#[test]
427594
#[cfg(feature = "std")]
428595
fn test_multi_node_receive() {

0 commit comments

Comments
 (0)