Skip to content

Commit 28a0d2c

Browse files
committed
Use onion amount amt_to_forward for MPP set calculation
If routing nodes take less fees and pay the final node more than `amt_to_forward`, the receiver may see that `total_msat` has been met before all of the sender's intended HTLCs have arrived. The receiver may then prematurely claim the payment and release the payment hash, allowing routing nodes to claim the remaining HTLCs. Using the onion value `amt_to_forward` to determine when `total_msat` has been met allows the sender to control the set total.
1 parent b7f05b3 commit 28a0d2c

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,7 @@ where
21592159
payment_hash,
21602160
incoming_shared_secret: shared_secret,
21612161
incoming_amt_msat: Some(amt_msat),
2162-
outgoing_amt_msat: amt_msat,
2162+
outgoing_amt_msat: hop_data.amt_to_forward,
21632163
outgoing_cltv_value: hop_data.outgoing_cltv_value,
21642164
})
21652165
}

lightning/src/ln/functional_tests.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7925,6 +7925,102 @@ fn test_can_not_accept_unknown_inbound_channel() {
79257925
}
79267926
}
79277927

7928+
#[test]
7929+
fn test_onion_value_mpp_set_calculation() {
7930+
// Test that we use the onion value `amt_to_forward` when
7931+
// calculating whether we've reached the `total_msat` of an MPP
7932+
// by having a routing node forward more than `amt_to_forward`
7933+
// and checking that the receiving node doesn't generate
7934+
// a PaymentClaimable event too early
7935+
let node_count = 4;
7936+
let chanmon_cfgs = create_chanmon_cfgs(node_count);
7937+
let node_cfgs = create_node_cfgs(node_count, &chanmon_cfgs);
7938+
let node_chanmgrs = create_node_chanmgrs(node_count, &node_cfgs, &vec![None; node_count]);
7939+
let mut nodes = create_network(node_count, &node_cfgs, &node_chanmgrs);
7940+
7941+
let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1).0.contents.short_channel_id;
7942+
let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2).0.contents.short_channel_id;
7943+
let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3).0.contents.short_channel_id;
7944+
let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3).0.contents.short_channel_id;
7945+
7946+
let total_msat = 100_000;
7947+
let expected_paths = vec![vec![&nodes[1], &nodes[3]], vec![&nodes[2], &nodes[3]]];
7948+
let expected_paths: Vec<&[&Node]> = expected_paths.iter().map(|v| v.as_slice()).collect();
7949+
let (mut route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[3], total_msat);
7950+
let sample_path = route.paths.pop().unwrap();
7951+
7952+
let mut path_1 = sample_path.clone();
7953+
path_1[0].pubkey = nodes[1].node.get_our_node_id();
7954+
path_1[0].short_channel_id = chan_1_id;
7955+
path_1[1].pubkey = nodes[3].node.get_our_node_id();
7956+
path_1[1].short_channel_id = chan_3_id;
7957+
path_1[1].fee_msat = 100_000;
7958+
route.paths.push(path_1);
7959+
7960+
let mut path_2 = sample_path.clone();
7961+
path_2[0].pubkey = nodes[2].node.get_our_node_id();
7962+
path_2[0].short_channel_id = chan_2_id;
7963+
path_2[1].pubkey = nodes[3].node.get_our_node_id();
7964+
path_2[1].short_channel_id = chan_4_id;
7965+
path_2[1].fee_msat = 1_000;
7966+
route.paths.push(path_2);
7967+
7968+
// Send payment
7969+
let payment_id = PaymentId(nodes[0].keys_manager.backing.get_secure_random_bytes());
7970+
let onion_session_privs = nodes[0].node.test_add_new_pending_payment(our_payment_hash, Some(our_payment_secret), payment_id, &route).unwrap();
7971+
nodes[0].node.test_send_payment_internal(&route, our_payment_hash, &Some(our_payment_secret), None, payment_id, Some(total_msat), onion_session_privs).unwrap();
7972+
check_added_monitors!(nodes[0], expected_paths.len());
7973+
7974+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
7975+
assert_eq!(events.len(), expected_paths.len());
7976+
7977+
// First path
7978+
let ev = remove_first_msg_event_to_node(&expected_paths[0][0].node.get_our_node_id(), &mut events);
7979+
let mut payment_event = SendEvent::from_event(ev);
7980+
let mut prev_node = &nodes[0];
7981+
7982+
for (idx, &node) in expected_paths[0].iter().enumerate() {
7983+
assert_eq!(node.node.get_our_node_id(), payment_event.node_id);
7984+
7985+
if idx == 0 { // routing node
7986+
let session_priv = [3; 32];
7987+
let height = nodes[0].best_block_info().1;
7988+
let session_priv = SecretKey::from_slice(&session_priv).unwrap();
7989+
let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
7990+
let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], 100_000, &Some(our_payment_secret), height + 1, &None).unwrap();
7991+
// Edit amt_to_forward to simulate the sender having set
7992+
// the final amount and the routing node taking less fee
7993+
onion_payloads[1].amt_to_forward = 99_000;
7994+
let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
7995+
payment_event.msgs[0].onion_routing_packet = new_onion_packet;
7996+
}
7997+
7998+
node.node.handle_update_add_htlc(&prev_node.node.get_our_node_id(), &payment_event.msgs[0]);
7999+
check_added_monitors!(node, 0);
8000+
commitment_signed_dance!(node, prev_node, payment_event.commitment_msg, false);
8001+
expect_pending_htlcs_forwardable!(node);
8002+
8003+
if idx == 0 {
8004+
let mut events_2 = node.node.get_and_clear_pending_msg_events();
8005+
assert_eq!(events_2.len(), 1);
8006+
check_added_monitors!(node, 1);
8007+
payment_event = SendEvent::from_event(events_2.remove(0));
8008+
assert_eq!(payment_event.msgs.len(), 1);
8009+
} else {
8010+
let events_2 = node.node.get_and_clear_pending_events();
8011+
assert!(events_2.is_empty());
8012+
}
8013+
8014+
prev_node = node;
8015+
}
8016+
8017+
// Second path
8018+
let ev = remove_first_msg_event_to_node(&expected_paths[1][0].node.get_our_node_id(), &mut events);
8019+
pass_along_path(&nodes[0], expected_paths[1], total_msat, our_payment_hash.clone(), Some(our_payment_secret), ev, true, None);
8020+
8021+
claim_payment_along_route(&nodes[0], expected_paths.as_slice(), false, our_payment_preimage);
8022+
}
8023+
79288024
fn do_test_overshoot_mpp(msat_amounts: &[u64], total_msat: u64) {
79298025

79308026
let routing_node_count = msat_amounts.len();

0 commit comments

Comments
 (0)