Skip to content

Commit 1d44945

Browse files
Test htlc forwarding over substitute channels
1 parent ef4107a commit 1d44945

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

lightning/src/ln/functional_test_utils.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,12 +1561,18 @@ pub fn send_along_route_with_secret<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
15611561
payment_id
15621562
}
15631563

1564-
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_received_expected: bool, clear_recipient_events: bool, expected_preimage: Option<PaymentPreimage>) {
1564+
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_received_expected: bool, clear_recipient_events: bool, expected_preimage: Option<PaymentPreimage>, expected_channels: Option<&Vec<[u8; 32]>>) {
15651565
let mut payment_event = SendEvent::from_event(ev);
15661566
let mut prev_node = origin_node;
1567+
if let Some(channel_ids) = expected_channels {
1568+
assert_eq!(expected_path.len(), channel_ids.len());
1569+
}
15671570

15681571
for (idx, &node) in expected_path.iter().enumerate() {
15691572
assert_eq!(node.node.get_our_node_id(), payment_event.node_id);
1573+
if let Some(channel_ids) = expected_channels {
1574+
assert_eq!(payment_event.msgs[0].channel_id, channel_ids[idx]);
1575+
}
15701576

15711577
node.node.handle_update_add_htlc(&prev_node.node.get_our_node_id(), &payment_event.msgs[0]);
15721578
check_added_monitors!(node, 0);
@@ -1611,7 +1617,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p
16111617
}
16121618

16131619
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_received_expected: bool, expected_preimage: Option<PaymentPreimage>) {
1614-
do_pass_along_path(origin_node, expected_path, recv_value, our_payment_hash, our_payment_secret, ev, payment_received_expected, true, expected_preimage);
1620+
do_pass_along_path(origin_node, expected_path, recv_value, our_payment_hash, our_payment_secret, ev, payment_received_expected, true, expected_preimage, None);
16151621
}
16161622

16171623
pub fn pass_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&[&Node<'a, 'b, 'c>]], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: PaymentSecret) {

lightning/src/ln/functional_tests.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,63 @@ fn fake_network_test() {
11001100
check_closed_event!(nodes[3], 1, ClosureReason::CooperativeClosure);
11011101
}
11021102

1103+
#[test]
1104+
fn test_forward_through_substitute_channel() {
1105+
// Test that we forward htlcs over substitute channels if we receive an onion payload that
1106+
// specifies that we should forward an htlc over a channel where we have insufficient
1107+
// liquidity, but an alternative channel to the same node with enough liquidity exists.
1108+
let chanmon_cfgs = create_chanmon_cfgs(3);
1109+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1110+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
1111+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1112+
let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
1113+
let chan_1_2a = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10000, 1001, InitFeatures::known(), InitFeatures::known());
1114+
let chan_1_2b = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1000000, 100001, InitFeatures::known(), InitFeatures::known());
1115+
1116+
let mut hops = Vec::with_capacity(2);
1117+
hops.push(RouteHop {
1118+
pubkey: nodes[1].node.get_our_node_id(),
1119+
node_features: NodeFeatures::known(),
1120+
short_channel_id: chan_0_1.0.contents.short_channel_id,
1121+
channel_features: ChannelFeatures::known(),
1122+
fee_msat: 1000,
1123+
cltv_expiry_delta: chan_1_2a.0.contents.cltv_expiry_delta as u32
1124+
});
1125+
hops.push(RouteHop {
1126+
pubkey: nodes[2].node.get_our_node_id(),
1127+
node_features: NodeFeatures::known(),
1128+
short_channel_id: chan_1_2a.0.contents.short_channel_id,
1129+
channel_features: ChannelFeatures::known(),
1130+
fee_msat: 2000000,
1131+
cltv_expiry_delta: TEST_FINAL_CLTV
1132+
});
1133+
1134+
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 2000000);
1135+
// Explicity specify that is `chan_1_2a` is the last hop in the `route`, which doesn't have
1136+
// enough liquidity forward 2000000 msat from `nodes[1]` to `nodes[2]`.
1137+
route = Route { paths: vec![hops], payment_params: None };
1138+
1139+
nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
1140+
check_added_monitors!(nodes[0], 1);
1141+
1142+
let mut send_events = nodes[0].node.get_and_clear_pending_msg_events();
1143+
assert_eq!(send_events.len(), 1);
1144+
1145+
// Ensure that `chan_1_2b` is used instead of `chan_1_2a` when the htlc is actaully forwarded.
1146+
let expected_channels = vec![chan_0_1.2, chan_1_2b.2];
1147+
do_pass_along_path(&nodes[0], &[&nodes[1], &nodes[2]], 2000000, payment_hash, Some(payment_secret), send_events[0].clone(), true, false, None, Some(&expected_channels));
1148+
1149+
expect_payment_received!(nodes[2], payment_hash, payment_secret, 2000000);
1150+
1151+
nodes[2].node.claim_funds(payment_preimage);
1152+
check_added_monitors!(nodes[2], 1);
1153+
expect_payment_claimed!(nodes[2], payment_hash, 2000000);
1154+
1155+
// Clear `nodes[2]`'s pending `UpdateFulfillHTLC` msg, as handling it isn't relevant for this
1156+
// test.
1157+
nodes[2].node.get_and_clear_pending_msg_events();
1158+
}
1159+
11031160
#[test]
11041161
fn holding_cell_htlc_counting() {
11051162
// Tests that HTLCs in the holding cell count towards the pending HTLC limits on outbound HTLCs
@@ -10080,8 +10137,8 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool) {
1008010137
// Send the payment through to nodes[3] *without* clearing the PaymentReceived event
1008110138
let mut send_events = nodes[0].node.get_and_clear_pending_msg_events();
1008210139
assert_eq!(send_events.len(), 2);
10083-
do_pass_along_path(&nodes[0], &[&nodes[1], &nodes[3]], 15_000_000, payment_hash, Some(payment_secret), send_events[0].clone(), true, false, None);
10084-
do_pass_along_path(&nodes[0], &[&nodes[2], &nodes[3]], 15_000_000, payment_hash, Some(payment_secret), send_events[1].clone(), true, false, None);
10140+
do_pass_along_path(&nodes[0], &[&nodes[1], &nodes[3]], 15_000_000, payment_hash, Some(payment_secret), send_events[0].clone(), true, false, None, None);
10141+
do_pass_along_path(&nodes[0], &[&nodes[2], &nodes[3]], 15_000_000, payment_hash, Some(payment_secret), send_events[1].clone(), true, false, None, None);
1008510142

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

0 commit comments

Comments
 (0)