Skip to content

Commit c32ff14

Browse files
committed
f explicitly handle and test dust
1 parent fba2f2d commit c32ff14

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
@@ -2989,32 +2989,21 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29892989
pub(crate) fn get_onchain_failed_outbound_htlcs(
29902990
&self,
29912991
) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
2992-
let us = self.inner.lock().unwrap();
2993-
// We're only concerned with the confirmation count of HTLC transactions, and don't
2994-
// actually care how many confirmations a commitment transaction may or may not have. Thus,
2995-
// we look for either a FundingSpendConfirmation event or a funding_spend_confirmed.
2996-
let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
2997-
us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
2998-
if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
2999-
Some(event.txid)
3000-
} else {
3001-
None
3002-
}
3003-
})
3004-
});
3005-
3006-
if confirmed_txid.is_none() {
3007-
return new_hash_map();
3008-
}
3009-
30102992
let mut res = new_hash_map();
2993+
let us = self.inner.lock().unwrap();
30112994
macro_rules! walk_htlcs {
30122995
($holder_commitment: expr, $htlc_iter: expr) => {
30132996
for (htlc, source) in $htlc_iter {
30142997
let filter = |v: &&IrrevocablyResolvedHTLC| {
30152998
v.commitment_tx_output_idx == htlc.transaction_output_index
30162999
};
3017-
if let Some(state) = us.htlcs_resolved_on_chain.iter().filter(filter).next() {
3000+
if htlc.transaction_output_index.is_none() {
3001+
if let Some(source) = source {
3002+
// Dust HTLCs are always implicitly failed once the commitment
3003+
// transaction reaches ANTI_REORG_DELAY confirmations.
3004+
res.insert(source.clone(), htlc.clone());
3005+
}
3006+
} else if let Some(state) = us.htlcs_resolved_on_chain.iter().filter(filter).next() {
30183007
if let Some(source) = source {
30193008
if state.payment_preimage.is_none() {
30203009
res.insert(source.clone(), htlc.clone());
@@ -3025,7 +3014,30 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
30253014
};
30263015
}
30273016

3028-
let txid = confirmed_txid.unwrap();
3017+
3018+
// We only want HTLCs with ANTI_REORG_DELAY confirmations, which implies the commitment
3019+
// transaction has least ANTI_REORG_DELAY confirmations for any dependent HTLC transactions
3020+
// to have been confirmed.
3021+
let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
3022+
us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
3023+
if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
3024+
if event.height <= us.best_block.height - ANTI_REORG_DELAY + 1 {
3025+
Some(event.txid)
3026+
} else {
3027+
None
3028+
}
3029+
} else {
3030+
None
3031+
}
3032+
})
3033+
});
3034+
3035+
let txid = if let Some(txid) = confirmed_txid {
3036+
txid
3037+
} else {
3038+
return res;
3039+
};
3040+
30293041
if Some(txid) == us.funding.current_counterparty_commitment_txid
30303042
|| Some(txid) == us.funding.prev_counterparty_commitment_txid
30313043
{

lightning/src/ln/monitor_tests.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3464,7 +3464,7 @@ fn test_lost_preimage_monitor_events() {
34643464
do_test_lost_preimage_monitor_events(false);
34653465
}
34663466

3467-
fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
3467+
fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool, dust_htlcs: bool) {
34683468
// `MonitorEvent`s aren't delivered to the `ChannelManager` in a durable fasion - if the
34693469
// `ChannelManager` fetches the pending `MonitorEvent`s, then the `ChannelMonitor` gets
34703470
// persisted (i.e. due to a block update) then the node crashes, prior to persisting the
@@ -3509,8 +3509,11 @@ fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
35093509
connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
35103510
connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
35113511

3512-
let (_, hash_a, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5_000_000);
3513-
let (_, hash_b, ..) = route_payment(&nodes[1], &[&nodes[2]], 5_000_000);
3512+
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 25_000_000);
3513+
3514+
let amt = if dust_htlcs { 1_000 } else { 10_000_000 };
3515+
let (_, hash_a, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], amt);
3516+
let (_, hash_b, ..) = route_payment(&nodes[1], &[&nodes[2]], amt);
35143517

35153518
nodes[1].node.peer_disconnected(nodes[2].node.get_our_node_id());
35163519
nodes[2].node.peer_disconnected(nodes[1].node.get_our_node_id());
@@ -3568,23 +3571,22 @@ fn do_test_lost_timeout_monitor_events(on_counterparty_tx: bool) {
35683571

35693572
connect_blocks(&nodes[1], TEST_FINAL_CLTV - ANTI_REORG_DELAY + 1);
35703573
if !on_counterparty_tx {
3571-
let mut events = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
3572-
assert_eq!(events.len(), 1, "{events:?}");
3573-
match events.pop().unwrap() {
3574-
Event::BumpTransaction(bump_event) => {
3575-
nodes[1].bump_tx_handler.handle_event(&bump_event);
3576-
},
3577-
_ => panic!("Unexpected event"),
3574+
if !dust_htlcs {
3575+
handle_bump_events(&nodes[1], false, 1);
35783576
}
35793577
}
35803578
let bs_htlc_timeouts =
35813579
nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
3582-
assert_eq!(bs_htlc_timeouts.len(), 1);
3580+
if dust_htlcs {
3581+
assert_eq!(bs_htlc_timeouts.len(), 0);
3582+
} else {
3583+
assert_eq!(bs_htlc_timeouts.len(), 1);
35833584

3584-
// Now replay the timeouts on node B, which after 6 confirmations should fail the HTLCs via
3585-
// `MonitorUpdate`s
3586-
mine_transactions(&nodes[1], &bs_htlc_timeouts.iter().collect::<Vec<_>>());
3587-
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
3585+
// Now replay the timeouts on node B, which after 6 confirmations should fail the HTLCs via
3586+
// `MonitorUpdate`s
3587+
mine_transactions(&nodes[1], &bs_htlc_timeouts.iter().collect::<Vec<_>>());
3588+
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
3589+
}
35883590

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

36383640
#[test]
36393641
fn test_lost_timeout_monitor_events() {
3640-
do_test_lost_timeout_monitor_events(true);
3641-
do_test_lost_timeout_monitor_events(false);
3642+
do_test_lost_timeout_monitor_events(true, false);
3643+
do_test_lost_timeout_monitor_events(false, false);
3644+
do_test_lost_timeout_monitor_events(true, true);
3645+
do_test_lost_timeout_monitor_events(false, true);
36423646
}

0 commit comments

Comments
 (0)