Skip to content

Commit 6d5c952

Browse files
authored
Merge pull request #2823 from valentinewallace/2024-01-blinded-forwarding-tests
Test blinded forwarding
2 parents 670b41a + 2027bf4 commit 6d5c952

7 files changed

+571
-127
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 434 additions & 97 deletions
Large diffs are not rendered by default.

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3405,7 +3405,7 @@ fn do_test_reload_mon_update_completion_actions(close_during_reload: bool) {
34053405
let mut events = nodes[1].node.get_and_clear_pending_events();
34063406
assert_eq!(events.len(), if close_during_reload { 2 } else { 1 });
34073407
expect_payment_forwarded(events.pop().unwrap(), &nodes[1], &nodes[0], &nodes[2], Some(1000),
3408-
None, close_during_reload, false);
3408+
None, close_during_reload, false, false);
34093409
if close_during_reload {
34103410
match events[0] {
34113411
Event::ChannelClosed { .. } => {},

lightning/src/ln/functional_test_utils.rs

Lines changed: 125 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,17 +2223,26 @@ macro_rules! expect_payment_path_successful {
22232223
}
22242224
}
22252225

2226+
/// Returns the total fee earned by this HTLC forward, in msat.
22262227
pub fn expect_payment_forwarded<CM: AChannelManager, H: NodeHolder<CM=CM>>(
22272228
event: Event, node: &H, prev_node: &H, next_node: &H, expected_fee: Option<u64>,
22282229
expected_extra_fees_msat: Option<u64>, upstream_force_closed: bool,
2229-
downstream_force_closed: bool
2230-
) {
2230+
downstream_force_closed: bool, allow_1_msat_fee_overpay: bool,
2231+
) -> Option<u64> {
22312232
match event {
22322233
Event::PaymentForwarded {
22332234
total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
22342235
outbound_amount_forwarded_msat: _, skimmed_fee_msat
22352236
} => {
2236-
assert_eq!(total_fee_earned_msat, expected_fee);
2237+
if allow_1_msat_fee_overpay {
2238+
// Aggregating fees for blinded paths may result in a rounding error, causing slight
2239+
// overpayment in fees.
2240+
let actual_fee = total_fee_earned_msat.unwrap();
2241+
let expected_fee = expected_fee.unwrap();
2242+
assert!(actual_fee == expected_fee || actual_fee == expected_fee + 1);
2243+
} else {
2244+
assert_eq!(total_fee_earned_msat, expected_fee);
2245+
}
22372246

22382247
// Check that the (knowingly) withheld amount is always less or equal to the expected
22392248
// overpaid amount.
@@ -2248,6 +2257,7 @@ pub fn expect_payment_forwarded<CM: AChannelManager, H: NodeHolder<CM=CM>>(
22482257
assert!(node.node().list_channels().iter().any(|x| x.counterparty.node_id == next_node.node().get_our_node_id() && x.channel_id == next_channel_id.unwrap()));
22492258
}
22502259
assert_eq!(claim_from_onchain_tx, downstream_force_closed);
2260+
total_fee_earned_msat
22512261
},
22522262
_ => panic!("Unexpected event"),
22532263
}
@@ -2260,7 +2270,7 @@ macro_rules! expect_payment_forwarded {
22602270
assert_eq!(events.len(), 1);
22612271
$crate::ln::functional_test_utils::expect_payment_forwarded(
22622272
events.pop().unwrap(), &$node, &$prev_node, &$next_node, $expected_fee, None,
2263-
$upstream_force_closed, $downstream_force_closed
2273+
$upstream_force_closed, $downstream_force_closed, false
22642274
);
22652275
}
22662276
}
@@ -2472,7 +2482,60 @@ fn fail_payment_along_path<'a, 'b, 'c>(expected_path: &[&Node<'a, 'b, 'c>]) {
24722482
}
24732483
}
24742484

2475-
pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: Option<PaymentSecret>, ev: MessageSendEvent, payment_claimable_expected: bool, clear_recipient_events: bool, expected_preimage: Option<PaymentPreimage>, is_probe: bool) -> Option<Event> {
2485+
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
2486+
pub origin_node: &'a Node<'b, 'c, 'd>,
2487+
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
2488+
pub recv_value: u64,
2489+
pub payment_hash: PaymentHash,
2490+
pub payment_secret: Option<PaymentSecret>,
2491+
pub event: MessageSendEvent,
2492+
pub payment_claimable_expected: bool,
2493+
pub clear_recipient_events: bool,
2494+
pub expected_preimage: Option<PaymentPreimage>,
2495+
pub is_probe: bool,
2496+
}
2497+
2498+
impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
2499+
pub fn new(
2500+
origin_node: &'a Node<'b, 'c, 'd>, expected_path: &'a [&'a Node<'b, 'c, 'd>], recv_value: u64,
2501+
payment_hash: PaymentHash, event: MessageSendEvent,
2502+
) -> Self {
2503+
Self {
2504+
origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event,
2505+
payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None,
2506+
is_probe: false,
2507+
}
2508+
}
2509+
pub fn without_clearing_recipient_events(mut self) -> Self {
2510+
self.clear_recipient_events = false;
2511+
self
2512+
}
2513+
pub fn is_probe(mut self) -> Self {
2514+
self.payment_claimable_expected = false;
2515+
self.is_probe = true;
2516+
self
2517+
}
2518+
pub fn without_claimable_event(mut self) -> Self {
2519+
self.payment_claimable_expected = false;
2520+
self
2521+
}
2522+
pub fn with_payment_secret(mut self, payment_secret: PaymentSecret) -> Self {
2523+
self.payment_secret = Some(payment_secret);
2524+
self
2525+
}
2526+
pub fn with_payment_preimage(mut self, payment_preimage: PaymentPreimage) -> Self {
2527+
self.expected_preimage = Some(payment_preimage);
2528+
self
2529+
}
2530+
}
2531+
2532+
pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event> {
2533+
let PassAlongPathArgs {
2534+
origin_node, expected_path, recv_value, payment_hash: our_payment_hash,
2535+
payment_secret: our_payment_secret, event: ev, payment_claimable_expected,
2536+
clear_recipient_events, expected_preimage, is_probe
2537+
} = args;
2538+
24762539
let mut payment_event = SendEvent::from_event(ev);
24772540
let mut prev_node = origin_node;
24782541
let mut event = None;
@@ -2539,7 +2602,17 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p
25392602
}
25402603

25412604
pub fn pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: Option<PaymentSecret>, ev: MessageSendEvent, payment_claimable_expected: bool, expected_preimage: Option<PaymentPreimage>) -> Option<Event> {
2542-
do_pass_along_path(origin_node, expected_path, recv_value, our_payment_hash, our_payment_secret, ev, payment_claimable_expected, true, expected_preimage, false)
2605+
let mut args = PassAlongPathArgs::new(origin_node, expected_path, recv_value, our_payment_hash, ev);
2606+
if !payment_claimable_expected {
2607+
args = args.without_claimable_event();
2608+
}
2609+
if let Some(payment_secret) = our_payment_secret {
2610+
args = args.with_payment_secret(payment_secret);
2611+
}
2612+
if let Some(payment_preimage) = expected_preimage {
2613+
args = args.with_payment_preimage(payment_preimage);
2614+
}
2615+
do_pass_along_path(args)
25432616
}
25442617

25452618
pub fn send_probe_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&[&Node<'a, 'b, 'c>]]) {
@@ -2551,7 +2624,10 @@ pub fn send_probe_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expect
25512624
for path in expected_route.iter() {
25522625
let ev = remove_first_msg_event_to_node(&path[0].node.get_our_node_id(), &mut events);
25532626

2554-
do_pass_along_path(origin_node, path, 0, PaymentHash([0_u8; 32]), None, ev, false, false, None, true);
2627+
do_pass_along_path(PassAlongPathArgs::new(origin_node, path, 0, PaymentHash([0_u8; 32]), ev)
2628+
.is_probe()
2629+
.without_clearing_recipient_events());
2630+
25552631
let nodes_to_fail_payment: Vec<_> = vec![origin_node].into_iter().chain(path.iter().cloned()).collect();
25562632

25572633
fail_payment_along_path(nodes_to_fail_payment.as_slice());
@@ -2598,6 +2674,14 @@ pub struct ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
25982674
pub expected_min_htlc_overpay: Vec<u32>,
25992675
pub skip_last: bool,
26002676
pub payment_preimage: PaymentPreimage,
2677+
// Allow forwarding nodes to have taken 1 msat more fee than expected based on the downstream
2678+
// fulfill amount.
2679+
//
2680+
// Necessary because our test utils calculate the expected fee for an intermediate node based on
2681+
// the amount was claimed in their downstream peer's fulfill, but blinded intermediate nodes
2682+
// calculate their fee based on the inbound amount from their upstream peer, causing a difference
2683+
// in rounding.
2684+
pub allow_1_msat_fee_overpay: bool,
26012685
}
26022686

26032687
impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
@@ -2608,6 +2692,7 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
26082692
Self {
26092693
origin_node, expected_paths, expected_extra_fees: vec![0; expected_paths.len()],
26102694
expected_min_htlc_overpay: vec![0; expected_paths.len()], skip_last: false, payment_preimage,
2695+
allow_1_msat_fee_overpay: false,
26112696
}
26122697
}
26132698
pub fn skip_last(mut self, skip_last: bool) -> Self {
@@ -2622,15 +2707,21 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
26222707
self.expected_min_htlc_overpay = extra_fees;
26232708
self
26242709
}
2710+
pub fn allow_1_msat_fee_overpay(mut self) -> Self {
2711+
self.allow_1_msat_fee_overpay = true;
2712+
self
2713+
}
26252714
}
26262715

26272716
pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArgs) -> u64 {
26282717
let ClaimAlongRouteArgs {
26292718
origin_node, expected_paths, expected_extra_fees, expected_min_htlc_overpay, skip_last,
2630-
payment_preimage: our_payment_preimage
2719+
payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay,
26312720
} = args;
26322721
let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
26332722
assert_eq!(claim_event.len(), 1);
2723+
#[allow(unused)]
2724+
let mut fwd_amt_msat = 0;
26342725
match claim_event[0] {
26352726
Event::PaymentClaimed {
26362727
purpose: PaymentPurpose::SpontaneousPayment(preimage),
@@ -2647,6 +2738,7 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArg
26472738
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
26482739
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
26492740
expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
2741+
fwd_amt_msat = amount_msat;
26502742
},
26512743
Event::PaymentClaimed {
26522744
purpose: PaymentPurpose::InvoicePayment { .. },
@@ -2659,6 +2751,7 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArg
26592751
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
26602752
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
26612753
expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
2754+
fwd_amt_msat = amount_msat;
26622755
}
26632756
_ => panic!(),
26642757
}
@@ -2690,8 +2783,12 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArg
26902783
per_path_msgs.push(msgs_from_ev!(&events[0]));
26912784
} else {
26922785
for expected_path in expected_paths.iter() {
2693-
// For MPP payments, we always want the message to the first node in the path.
2694-
let ev = remove_first_msg_event_to_node(&expected_path[0].node.get_our_node_id(), &mut events);
2786+
// For MPP payments, we want the fulfill message from the payee to the penultimate hop in the
2787+
// path.
2788+
let penultimate_hop_node_id = expected_path.iter().rev().skip(1).next()
2789+
.map(|n| n.node.get_our_node_id())
2790+
.unwrap_or(origin_node.node.get_our_node_id());
2791+
let ev = remove_first_msg_event_to_node(&penultimate_hop_node_id, &mut events);
26952792
per_path_msgs.push(msgs_from_ev!(&ev));
26962793
}
26972794
}
@@ -2715,15 +2812,20 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArg
27152812
{
27162813
$node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0);
27172814
let mut fee = {
2718-
let per_peer_state = $node.node.per_peer_state.read().unwrap();
2719-
let peer_state = per_peer_state.get(&$prev_node.node.get_our_node_id())
2720-
.unwrap().lock().unwrap();
2721-
let channel = peer_state.channel_by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap();
2722-
if let Some(prev_config) = channel.context().prev_config() {
2723-
prev_config.forwarding_fee_base_msat
2724-
} else {
2725-
channel.context().config().forwarding_fee_base_msat
2726-
}
2815+
let (base_fee, prop_fee) = {
2816+
let per_peer_state = $node.node.per_peer_state.read().unwrap();
2817+
let peer_state = per_peer_state.get(&$prev_node.node.get_our_node_id())
2818+
.unwrap().lock().unwrap();
2819+
let channel = peer_state.channel_by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap();
2820+
if let Some(prev_config) = channel.context().prev_config() {
2821+
(prev_config.forwarding_fee_base_msat as u64,
2822+
prev_config.forwarding_fee_proportional_millionths as u64)
2823+
} else {
2824+
(channel.context().config().forwarding_fee_base_msat as u64,
2825+
channel.context().config().forwarding_fee_proportional_millionths as u64)
2826+
}
2827+
};
2828+
((fwd_amt_msat * prop_fee / 1_000_000) + base_fee) as u32
27272829
};
27282830

27292831
let mut expected_extra_fee = None;
@@ -2734,9 +2836,10 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArg
27342836
}
27352837
let mut events = $node.node.get_and_clear_pending_events();
27362838
assert_eq!(events.len(), 1);
2737-
expect_payment_forwarded(events.pop().unwrap(), *$node, $next_node, $prev_node,
2738-
Some(fee as u64), expected_extra_fee, false, false);
2739-
expected_total_fee_msat += fee as u64;
2839+
let actual_fee = expect_payment_forwarded(events.pop().unwrap(), *$node, $next_node, $prev_node,
2840+
Some(fee as u64), expected_extra_fee, false, false, allow_1_msat_fee_overpay);
2841+
expected_total_fee_msat += actual_fee.unwrap();
2842+
fwd_amt_msat += actual_fee.unwrap();
27402843
check_added_monitors!($node, 1);
27412844
let new_next_msgs = if $new_msgs {
27422845
let events = $node.node.get_and_clear_pending_msg_events();

lightning/src/ln/offers_tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ fn route_bolt12_payment<'a, 'b, 'c>(
145145
// invoice contains the payment_hash but it was encrypted inside an onion message.
146146
let amount_msats = invoice.amount_msats();
147147
let payment_hash = invoice.payment_hash();
148-
do_pass_along_path(
149-
node, path, amount_msats, payment_hash, None, ev, false, false, None, false
150-
);
148+
let args = PassAlongPathArgs::new(node, path, amount_msats, payment_hash, ev)
149+
.without_clearing_recipient_events();
150+
do_pass_along_path(args);
151151
}
152152

153153
fn claim_bolt12_payment<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>]) {

lightning/src/ln/reload_tests.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,12 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool) {
823823
assert_eq!(send_events.len(), 2);
824824
let node_1_msgs = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut send_events);
825825
let node_2_msgs = remove_first_msg_event_to_node(&nodes[2].node.get_our_node_id(), &mut send_events);
826-
do_pass_along_path(&nodes[0], &[&nodes[1], &nodes[3]], 15_000_000, payment_hash, Some(payment_secret), node_1_msgs, true, false, None, false);
827-
do_pass_along_path(&nodes[0], &[&nodes[2], &nodes[3]], 15_000_000, payment_hash, Some(payment_secret), node_2_msgs, true, false, None, false);
826+
do_pass_along_path(PassAlongPathArgs::new(&nodes[0],&[&nodes[1], &nodes[3]], 15_000_000, payment_hash, node_1_msgs)
827+
.with_payment_secret(payment_secret)
828+
.without_clearing_recipient_events());
829+
do_pass_along_path(PassAlongPathArgs::new(&nodes[0], &[&nodes[2], &nodes[3]], 15_000_000, payment_hash, node_2_msgs)
830+
.with_payment_secret(payment_secret)
831+
.without_clearing_recipient_events());
828832

829833
// Now that we have an MPP payment pending, get the latest encoded copies of nodes[3]'s
830834
// monitors and ChannelManager, for use later, if we don't want to persist both monitors.

lightning/src/ln/shutdown_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ fn do_htlc_fail_async_shutdown(blinded_recipient: bool) {
437437
let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None);
438438
let route_params = if blinded_recipient {
439439
crate::ln::blinded_payment_tests::get_blinded_route_parameters(
440-
amt_msat, our_payment_secret,
440+
amt_msat, our_payment_secret, 1, 100000000,
441441
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&chan_2.0.contents],
442442
&chanmon_cfgs[2].keys_manager)
443443
} else {

lightning/src/routing/router.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ impl Payee {
986986
_ => None,
987987
}
988988
}
989-
fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] {
989+
pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] {
990990
match self {
991991
Self::Blinded { route_hints, .. } => &route_hints[..],
992992
Self::Clear { .. } => &[]

0 commit comments

Comments
 (0)