Skip to content

Commit 87ae44d

Browse files
committed
f explicitly handle and test dust
1 parent 49cc671 commit 87ae44d

File tree

2 files changed

+53
-37
lines changed

2 files changed

+53
-37
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,32 +2963,21 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29632963
pub(crate) fn get_onchain_failed_outbound_htlcs(
29642964
&self,
29652965
) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
2966-
let us = self.inner.lock().unwrap();
2967-
// We're only concerned with the confirmation count of HTLC transactions, and don't
2968-
// actually care how many confirmations a commitment transaction may or may not have. Thus,
2969-
// we look for either a FundingSpendConfirmation event or a funding_spend_confirmed.
2970-
let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
2971-
us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
2972-
if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
2973-
Some(event.txid)
2974-
} else {
2975-
None
2976-
}
2977-
})
2978-
});
2979-
2980-
if confirmed_txid.is_none() {
2981-
return new_hash_map();
2982-
}
2983-
29842966
let mut res = new_hash_map();
2967+
let us = self.inner.lock().unwrap();
29852968
macro_rules! walk_htlcs {
29862969
($holder_commitment: expr, $htlc_iter: expr) => {
29872970
for (htlc, source) in $htlc_iter {
29882971
let filter = |v: &&IrrevocablyResolvedHTLC| {
29892972
v.commitment_tx_output_idx == htlc.transaction_output_index
29902973
};
2991-
if let Some(state) = us.htlcs_resolved_on_chain.iter().filter(filter).next() {
2974+
if htlc.transaction_output_index.is_none() {
2975+
if let Some(source) = source {
2976+
// Dust HTLCs are always implicitly failed once the commitment
2977+
// transaction reaches ANTI_REORG_DELAY confirmations.
2978+
res.insert(source.clone(), htlc.clone());
2979+
}
2980+
} else if let Some(state) = us.htlcs_resolved_on_chain.iter().filter(filter).next() {
29922981
if let Some(source) = source {
29932982
if state.payment_preimage.is_none() {
29942983
res.insert(source.clone(), htlc.clone());
@@ -2999,7 +2988,30 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29992988
};
30002989
}
30012990

3002-
let txid = confirmed_txid.unwrap();
2991+
2992+
// We only want HTLCs with ANTI_REORG_DELAY confirmations, which implies the commitment
2993+
// transaction has least ANTI_REORG_DELAY confirmations for any dependent HTLC transactions
2994+
// to have been confirmed.
2995+
let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
2996+
us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
2997+
if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
2998+
if event.height <= us.best_block.height - ANTI_REORG_DELAY + 1 {
2999+
Some(event.txid)
3000+
} else {
3001+
None
3002+
}
3003+
} else {
3004+
None
3005+
}
3006+
})
3007+
});
3008+
3009+
let txid = if let Some(txid) = confirmed_txid {
3010+
txid
3011+
} else {
3012+
return res;
3013+
};
3014+
30033015
if Some(txid) == us.funding.current_counterparty_commitment_txid
30043016
|| Some(txid) == us.funding.prev_counterparty_commitment_txid
30053017
{

lightning/src/ln/monitor_tests.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3456,7 +3456,7 @@ fn test_lost_preimage_monitor_events() {
34563456
do_test_lost_preimage_monitor_events(false);
34573457
}
34583458

3459-
fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
3459+
fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool, dust_htlcs: bool) {
34603460
// `MonitorEvent`s aren't delivered to the `ChannelManager` in a durable fasion - if the
34613461
// `ChannelManager` fetches the pending `MonitorEvent`s, then the `ChannelMonitor` gets
34623462
// persisted (i.e. due to a block update) then the node crashes, prior to persisting the
@@ -3501,8 +3501,11 @@ fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
35013501
connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
35023502
connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
35033503

3504-
let (_, hash_a, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5_000_000);
3505-
let (_, hash_b, ..) = route_payment(&nodes[1], &[&nodes[2]], 5_000_000);
3504+
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 25_000_000);
3505+
3506+
let amt = if dust_htlcs { 1_000 } else { 10_000_000 };
3507+
let (_, hash_a, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], amt);
3508+
let (_, hash_b, ..) = route_payment(&nodes[1], &[&nodes[2]], amt);
35063509

35073510
nodes[1].node.peer_disconnected(nodes[2].node.get_our_node_id());
35083511
nodes[2].node.peer_disconnected(nodes[1].node.get_our_node_id());
@@ -3560,23 +3563,22 @@ fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
35603563

35613564
connect_blocks(&nodes[1], TEST_FINAL_CLTV - ANTI_REORG_DELAY + 1);
35623565
if !on_counterparty_tx {
3563-
let mut events = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
3564-
assert_eq!(events.len(), 1, "{events:?}");
3565-
match events.pop().unwrap() {
3566-
Event::BumpTransaction(bump_event) => {
3567-
nodes[1].bump_tx_handler.handle_event(&bump_event);
3568-
},
3569-
_ => panic!("Unexpected event"),
3566+
if !dust_htlcs {
3567+
handle_bump_events(&nodes[1], false, 1);
35703568
}
35713569
}
35723570
let bs_htlc_timeouts =
35733571
nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
3574-
assert_eq!(bs_htlc_timeouts.len(), 1);
3572+
if dust_htlcs {
3573+
assert_eq!(bs_htlc_timeouts.len(), 0);
3574+
} else {
3575+
assert_eq!(bs_htlc_timeouts.len(), 1);
35753576

3576-
// Now replay the timeouts on node B, which after 6 confirmations should fail the HTLCs via
3577-
// `MonitorUpdate`s
3578-
mine_transactions(&nodes[1], &bs_htlc_timeouts.iter().collect::<Vec<_>>());
3579-
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
3577+
// Now replay the timeouts on node B, which after 6 confirmations should fail the HTLCs via
3578+
// `MonitorUpdate`s
3579+
mine_transactions(&nodes[1], &bs_htlc_timeouts.iter().collect::<Vec<_>>());
3580+
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
3581+
}
35803582

35813583
// Now simulate a restart where the B<->C ChannelMonitor has been persisted (i.e. because we
35823584
// just processed a new block) but the ChannelManager was not. This should be exceedingly rare
@@ -3629,6 +3631,8 @@ fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
36293631

36303632
#[test]
36313633
fn test_lost_timeout_monitor_events() {
3632-
do_test_lost_timeout_monitor_events(true);
3633-
do_test_lost_timeout_monitor_events(false);
3634+
do_test_lost_timeout_monitor_events(true, false);
3635+
do_test_lost_timeout_monitor_events(false, false);
3636+
do_test_lost_timeout_monitor_events(true, true);
3637+
do_test_lost_timeout_monitor_events(false, true);
36343638
}

0 commit comments

Comments
 (0)