Skip to content

Commit de7d756

Browse files
authored
Merge pull request #3538 from morehouse/fix_package_splitting
Fix package splitting logic
2 parents ad462bd + a1d6356 commit de7d756

File tree

2 files changed

+259
-1
lines changed

2 files changed

+259
-1
lines changed

lightning/src/chain/onchaintx.rs

-1
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,6 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
964964
self.pending_claim_events.retain(|entry| entry.0 != *claim_id);
965965
}
966966
}
967-
break; //No need to iterate further, either tx is our or their
968967
} else {
969968
panic!("Inconsistencies between pending_claim_requests map and claimable_outpoints map");
970969
}

lightning/src/ln/functional_tests.rs

+259
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::chain::channelmonitor;
1818
use crate::chain::channelmonitor::{Balance, ChannelMonitorUpdateStep, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
1919
use crate::chain::transaction::OutPoint;
2020
use crate::sign::{ecdsa::EcdsaChannelSigner, EntropySource, OutputSpender, SignerProvider};
21+
use crate::events::bump_transaction::WalletSource;
2122
use crate::events::{Event, FundingInfo, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason};
2223
use crate::ln::types::ChannelId;
2324
use crate::types::payment::{PaymentPreimage, PaymentSecret, PaymentHash};
@@ -2762,6 +2763,264 @@ fn claim_htlc_outputs() {
27622763
assert_eq!(nodes[1].node.list_channels().len(), 0);
27632764
}
27642765

2766+
// Test that the HTLC package logic removes HTLCs from the package when they are claimed by the
2767+
// counterparty, even when the counterparty claims HTLCs from multiple packages in a single
2768+
// transaction.
2769+
//
2770+
// This is a regression test for https://github.com/lightningdevkit/rust-lightning/issues/3537.
2771+
#[test]
2772+
fn test_multiple_package_conflicts() {
2773+
let chanmon_cfgs = create_chanmon_cfgs(3);
2774+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
2775+
let mut user_cfg = test_default_channel_config();
2776+
2777+
// Anchor channels are required so that multiple HTLC-Successes can be aggregated into a single
2778+
// transaction.
2779+
user_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
2780+
user_cfg.manually_accept_inbound_channels = true;
2781+
2782+
let node_chanmgrs =
2783+
create_node_chanmgrs(3, &node_cfgs, &[Some(user_cfg), Some(user_cfg), Some(user_cfg)]);
2784+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
2785+
2786+
// Since we're using anchor channels, make sure each node has a UTXO for paying fees.
2787+
let coinbase_tx = Transaction {
2788+
version: Version::TWO,
2789+
lock_time: LockTime::ZERO,
2790+
input: vec![TxIn { ..Default::default() }],
2791+
output: vec![
2792+
TxOut {
2793+
value: Amount::ONE_BTC,
2794+
script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
2795+
},
2796+
TxOut {
2797+
value: Amount::ONE_BTC,
2798+
script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(),
2799+
},
2800+
TxOut {
2801+
value: Amount::ONE_BTC,
2802+
script_pubkey: nodes[2].wallet_source.get_change_script().unwrap(),
2803+
},
2804+
],
2805+
};
2806+
nodes[0].wallet_source.add_utxo(
2807+
bitcoin::OutPoint { txid: coinbase_tx.compute_txid(), vout: 0 },
2808+
coinbase_tx.output[0].value,
2809+
);
2810+
nodes[1].wallet_source.add_utxo(
2811+
bitcoin::OutPoint { txid: coinbase_tx.compute_txid(), vout: 1 },
2812+
coinbase_tx.output[1].value,
2813+
);
2814+
nodes[2].wallet_source.add_utxo(
2815+
bitcoin::OutPoint { txid: coinbase_tx.compute_txid(), vout: 2 },
2816+
coinbase_tx.output[2].value,
2817+
);
2818+
2819+
// Create the network.
2820+
// 0 -- 1 -- 2
2821+
//
2822+
// Payments will be routed from node 0 to node 2. Node 2 will force close and spend HTLCs from
2823+
// two of node 1's packages. We will then verify that node 1 correctly removes the conflicting
2824+
// HTLC spends from its packages.
2825+
const CHAN_CAPACITY: u64 = 10_000_000;
2826+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, CHAN_CAPACITY, 0);
2827+
let (_, _, cid_1_2, funding_tx_1_2) =
2828+
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, CHAN_CAPACITY, 0);
2829+
2830+
// Ensure all nodes are at the same initial height.
2831+
let node_max_height = nodes.iter().map(|node| node.best_block_info().1).max().unwrap();
2832+
for node in &nodes {
2833+
let blocks_to_mine = node_max_height - node.best_block_info().1;
2834+
if blocks_to_mine > 0 {
2835+
connect_blocks(node, blocks_to_mine);
2836+
}
2837+
}
2838+
2839+
// Route HTLC 1.
2840+
let (preimage_1, payment_hash_1, ..) =
2841+
route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
2842+
2843+
// Route HTLCs 2 and 3, with CLTVs 1 higher than HTLC 1. The higher CLTVs will cause these
2844+
// HTLCs to be included in a different package than HTLC 1.
2845+
connect_blocks(&nodes[0], 1);
2846+
connect_blocks(&nodes[1], 1);
2847+
connect_blocks(&nodes[2], 1);
2848+
let (preimage_2, payment_hash_2, ..) =
2849+
route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
2850+
route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 900_000_000);
2851+
2852+
// Mine blocks until HTLC 1 times out in 1 block and HTLCs 2 and 3 time out in 2 blocks.
2853+
connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1);
2854+
2855+
// Node 2 force closes, causing node 1 to group the HTLCs into the following packages:
2856+
// Package 1: HTLC 1
2857+
// Package 2: HTLCs 2 and 3
2858+
let node2_commit_tx = get_local_commitment_txn!(nodes[2], cid_1_2);
2859+
assert_eq!(node2_commit_tx.len(), 1);
2860+
let node2_commit_tx = &node2_commit_tx[0];
2861+
check_spends!(node2_commit_tx, funding_tx_1_2);
2862+
mine_transaction(&nodes[1], node2_commit_tx);
2863+
check_closed_event(
2864+
&nodes[1],
2865+
1,
2866+
ClosureReason::CommitmentTxConfirmed,
2867+
false,
2868+
&[nodes[2].node.get_our_node_id()],
2869+
CHAN_CAPACITY,
2870+
);
2871+
check_closed_broadcast!(nodes[1], true);
2872+
check_added_monitors(&nodes[1], 1);
2873+
2874+
// Node 1 should immediately claim package 1 but has to wait a block to claim package 2.
2875+
let timeout_tx = nodes[1].tx_broadcaster.txn_broadcast();
2876+
assert_eq!(timeout_tx.len(), 1);
2877+
check_spends!(timeout_tx[0], node2_commit_tx);
2878+
assert_eq!(timeout_tx[0].input.len(), 1);
2879+
2880+
// After one block, node 1 should also attempt to claim package 2.
2881+
connect_blocks(&nodes[1], 1);
2882+
let timeout_tx = nodes[1].tx_broadcaster.txn_broadcast();
2883+
assert_eq!(timeout_tx.len(), 1);
2884+
check_spends!(timeout_tx[0], node2_commit_tx);
2885+
assert_eq!(timeout_tx[0].input.len(), 2);
2886+
2887+
// Force node 2 to broadcast an aggregated HTLC-Success transaction spending HTLCs 1 and 2.
2888+
// This will conflict with both of node 1's HTLC packages.
2889+
{
2890+
let broadcaster = &node_cfgs[2].tx_broadcaster;
2891+
let fee_estimator = &LowerBoundedFeeEstimator::new(node_cfgs[2].fee_estimator);
2892+
let logger = &node_cfgs[2].logger;
2893+
let monitor = get_monitor!(nodes[2], cid_1_2);
2894+
monitor.provide_payment_preimage_unsafe_legacy(
2895+
&payment_hash_1,
2896+
&preimage_1,
2897+
broadcaster,
2898+
fee_estimator,
2899+
logger,
2900+
);
2901+
monitor.provide_payment_preimage_unsafe_legacy(
2902+
&payment_hash_2,
2903+
&preimage_2,
2904+
broadcaster,
2905+
fee_estimator,
2906+
logger,
2907+
);
2908+
}
2909+
mine_transaction(&nodes[2], node2_commit_tx);
2910+
check_closed_event(
2911+
&nodes[2],
2912+
1,
2913+
ClosureReason::CommitmentTxConfirmed,
2914+
false,
2915+
&[nodes[1].node.get_our_node_id()],
2916+
CHAN_CAPACITY,
2917+
);
2918+
check_closed_broadcast!(nodes[2], true);
2919+
check_added_monitors(&nodes[2], 1);
2920+
2921+
let process_bump_event = |node: &Node| {
2922+
let events = node.chain_monitor.chain_monitor.get_and_clear_pending_events();
2923+
assert_eq!(events.len(), 1);
2924+
let bump_event = match &events[0] {
2925+
Event::BumpTransaction(bump_event) => bump_event,
2926+
_ => panic!("Unexepected event"),
2927+
};
2928+
node.bump_tx_handler.handle_event(bump_event);
2929+
2930+
let mut tx = node.tx_broadcaster.txn_broadcast();
2931+
assert_eq!(tx.len(), 1);
2932+
tx.pop().unwrap()
2933+
};
2934+
2935+
let conflict_tx = process_bump_event(&nodes[2]);
2936+
assert_eq!(conflict_tx.input.len(), 3);
2937+
assert_eq!(conflict_tx.input[0].previous_output.txid, node2_commit_tx.compute_txid());
2938+
assert_eq!(conflict_tx.input[1].previous_output.txid, node2_commit_tx.compute_txid());
2939+
assert_eq!(conflict_tx.input[2].previous_output.txid, coinbase_tx.compute_txid());
2940+
2941+
// Mine node 2's aggregated HTLC-Success transaction on node 1, causing the package splitting
2942+
// logic to run. Package 2 should get split so that only HTLC 3 gets claimed.
2943+
mine_transaction(&nodes[1], &conflict_tx);
2944+
2945+
// Check that node 1 only attempts to claim HTLC 3 now. There should be no conflicting spends
2946+
// in the newly broadcasted transaction.
2947+
let broadcasted_txs = nodes[1].tx_broadcaster.txn_broadcast();
2948+
assert_eq!(broadcasted_txs.len(), 1);
2949+
let txins = &broadcasted_txs[0].input;
2950+
assert_eq!(txins.len(), 1);
2951+
assert_eq!(txins[0].previous_output.txid, node2_commit_tx.compute_txid());
2952+
for conflict_in in &conflict_tx.input {
2953+
assert_ne!(txins[0].previous_output, conflict_in.previous_output);
2954+
}
2955+
2956+
// Node 1 should also extract the preimages from the mined transaction and claim them upstream.
2957+
//
2958+
// Because two update_fulfill_htlc messages are created at once, the commitment_signed_dance
2959+
// macro doesn't work properly and we must process the first update_fulfill_htlc manually.
2960+
let updates = get_htlc_update_msgs(&nodes[1], &nodes[0].node.get_our_node_id());
2961+
assert_eq!(updates.update_fulfill_htlcs.len(), 1);
2962+
nodes[0].node.handle_update_fulfill_htlc(
2963+
nodes[1].node.get_our_node_id(),
2964+
&updates.update_fulfill_htlcs[0],
2965+
);
2966+
nodes[0]
2967+
.node
2968+
.handle_commitment_signed(nodes[1].node.get_our_node_id(), &updates.commitment_signed);
2969+
check_added_monitors(&nodes[0], 1);
2970+
2971+
let (revoke_ack, commit_signed) =
2972+
get_revoke_commit_msgs(&nodes[0], &nodes[1].node.get_our_node_id());
2973+
nodes[1].node.handle_revoke_and_ack(nodes[0].node.get_our_node_id(), &revoke_ack);
2974+
nodes[1].node.handle_commitment_signed(nodes[0].node.get_our_node_id(), &commit_signed);
2975+
check_added_monitors(&nodes[1], 4);
2976+
2977+
let events = nodes[1].node.get_and_clear_pending_msg_events();
2978+
assert_eq!(events.len(), 2);
2979+
let revoke_ack = match &events[1] {
2980+
MessageSendEvent::SendRevokeAndACK { node_id: _, msg } => msg,
2981+
_ => panic!("Unexpected event"),
2982+
};
2983+
nodes[0].node.handle_revoke_and_ack(nodes[1].node.get_our_node_id(), revoke_ack);
2984+
expect_payment_sent!(nodes[0], preimage_1);
2985+
2986+
let updates = match &events[0] {
2987+
MessageSendEvent::UpdateHTLCs { node_id: _, updates } => updates,
2988+
_ => panic!("Unexpected event"),
2989+
};
2990+
assert_eq!(updates.update_fulfill_htlcs.len(), 1);
2991+
nodes[0].node.handle_update_fulfill_htlc(
2992+
nodes[1].node.get_our_node_id(),
2993+
&updates.update_fulfill_htlcs[0],
2994+
);
2995+
commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false);
2996+
expect_payment_sent!(nodes[0], preimage_2);
2997+
2998+
let mut events = nodes[1].node.get_and_clear_pending_events();
2999+
assert_eq!(events.len(), 2);
3000+
expect_payment_forwarded(
3001+
events.pop().unwrap(),
3002+
&nodes[1],
3003+
&nodes[0],
3004+
&nodes[2],
3005+
Some(1000),
3006+
None,
3007+
false,
3008+
true,
3009+
false,
3010+
);
3011+
expect_payment_forwarded(
3012+
events.pop().unwrap(),
3013+
&nodes[1],
3014+
&nodes[0],
3015+
&nodes[2],
3016+
Some(1000),
3017+
None,
3018+
false,
3019+
true,
3020+
false,
3021+
);
3022+
}
3023+
27653024
#[test]
27663025
fn test_htlc_on_chain_success() {
27673026
// Test that in case of a unilateral close onchain, we detect the state of output and pass

0 commit comments

Comments
 (0)