Skip to content

Commit f0317b8

Browse files
Don't double-forward HTLCs in rebuilt update_adds map
We recently began reconstructing ChannelManager::decode_update_add_htlcs on startup, using data present in the Channels. However, we failed to prune HTLCs from this rebuilt map if a given HTLC was already forwarded to the outbound edge (we pruned correctly if the outbound edge was a closed channel, but not otherwise). Here we fix this bug that would have caused us to double-forward inbound HTLC forwards.
1 parent 8204e0a commit f0317b8

2 files changed

Lines changed: 68 additions & 6 deletions

File tree

lightning/src/ln/channelmanager.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18016,6 +18016,16 @@ where
1801618016
info.prev_funding_outpoint == prev_hop_data.outpoint
1801718017
&& info.prev_htlc_id == prev_hop_data.htlc_id
1801818018
};
18019+
// We always add all inbound committed HTLCs to `decode_update_add_htlcs` in the above
18020+
// loop, but we need to prune from those added HTLCs if they were already forwarded to
18021+
// the outbound edge. Otherwise, we'll double-forward.
18022+
dedup_decode_update_add_htlcs(
18023+
&mut decode_update_add_htlcs,
18024+
&prev_hop_data,
18025+
"HTLC was forwarded to the closed channel",
18026+
&args.logger,
18027+
);
18028+
1801918029
if !is_channel_closed {
1802018030
continue;
1802118031
}
@@ -18024,12 +18034,6 @@ where
1802418034
// still have an entry for this HTLC in `forward_htlcs`,
1802518035
// `pending_intercepted_htlcs`, or `decode_update_add_htlcs`, we were apparently not
1802618036
// persisted after the monitor was when forwarding the payment.
18027-
dedup_decode_update_add_htlcs(
18028-
&mut decode_update_add_htlcs,
18029-
&prev_hop_data,
18030-
"HTLC was forwarded to the closed channel",
18031-
&args.logger,
18032-
);
1803318037
dedup_decode_update_add_htlcs(
1803418038
&mut decode_update_add_htlcs_legacy,
1803518039
&prev_hop_data,

lightning/src/ln/reload_tests.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,64 @@ fn do_manager_persisted_pre_outbound_edge_forward(intercept_htlc: bool) {
12581258
expect_payment_sent(&nodes[0], payment_preimage, None, true, true);
12591259
}
12601260

1261+
#[test]
1262+
fn test_manager_persisted_post_outbound_edge_forward() {
1263+
// Test that we will not double-forward an HTLC after restart if it has already been forwarded to
1264+
// the outbound edge, which was previously broken.
1265+
let chanmon_cfgs = create_chanmon_cfgs(3);
1266+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1267+
let persister;
1268+
let new_chain_monitor;
1269+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
1270+
let nodes_1_deserialized;
1271+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1272+
1273+
let chan_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1).2;
1274+
let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2).2;
1275+
1276+
// Lock in the HTLC from node_a <> node_b.
1277+
let amt_msat = 5000;
1278+
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], amt_msat);
1279+
nodes[0].node.send_payment_with_route(route, payment_hash, RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
1280+
check_added_monitors(&nodes[0], 1);
1281+
let updates = get_htlc_update_msgs(&nodes[0], &nodes[1].node.get_our_node_id());
1282+
nodes[1].node.handle_update_add_htlc(nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
1283+
do_commitment_signed_dance(&nodes[1], &nodes[0], &updates.commitment_signed, false, false);
1284+
1285+
// Add the HTLC to the outbound edge, node_b <> node_c.
1286+
nodes[1].node.process_pending_htlc_forwards();
1287+
check_added_monitors(&nodes[1], 1);
1288+
1289+
// Disconnect peers and reload the forwarding node_b.
1290+
nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id());
1291+
nodes[2].node.peer_disconnected(nodes[1].node.get_our_node_id());
1292+
1293+
let node_b_encoded = nodes[1].node.encode();
1294+
let chan_0_monitor_serialized = get_monitor!(nodes[1], chan_id_1).encode();
1295+
let chan_1_monitor_serialized = get_monitor!(nodes[1], chan_id_2).encode();
1296+
reload_node!(nodes[1], node_b_encoded, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], persister, new_chain_monitor, nodes_1_deserialized);
1297+
1298+
reconnect_nodes(ReconnectArgs::new(&nodes[1], &nodes[0]));
1299+
let mut args_b_c = ReconnectArgs::new(&nodes[1], &nodes[2]);
1300+
args_b_c.send_channel_ready = (true, true);
1301+
args_b_c.send_announcement_sigs = (true, true);
1302+
args_b_c.pending_htlc_adds = (0, 1);
1303+
// While reconnecting, we re-send node_b's outbound update_add and commit the HTLC to the b<>c
1304+
// channel.
1305+
reconnect_nodes(args_b_c);
1306+
1307+
// Ensure node_b won't double-forward the outbound HTLC (this was previously broken).
1308+
nodes[1].node.process_pending_htlc_forwards();
1309+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
1310+
1311+
// Claim the HTLC backwards to node_a.
1312+
expect_and_process_pending_htlcs(&nodes[2], false);
1313+
expect_payment_claimable!(nodes[2], payment_hash, payment_secret, amt_msat, None, nodes[2].node.get_our_node_id());
1314+
let path: &[&[_]] = &[&[&nodes[1], &nodes[2]]];
1315+
do_claim_payment_along_route(ClaimAlongRouteArgs::new(&nodes[0], path, payment_preimage));
1316+
expect_payment_sent(&nodes[0], payment_preimage, None, true, true);
1317+
}
1318+
12611319
#[test]
12621320
fn test_reload_partial_funding_batch() {
12631321
let chanmon_cfgs = create_chanmon_cfgs(3);

0 commit comments

Comments
 (0)