Skip to content

Commit baa2540

Browse files
joostjagerclaude
andcommitted
chanmon_consistency: handle BumpTransaction events for anchor channels
For anchor channels, the ChannelMonitor does not broadcast commitment or HTLC-timeout transactions directly. Instead, it emits BumpTransaction events via ChainMonitor::process_pending_events(), which are separate from the ChannelManager events that process_events\! handles. Add chain monitor event processing to the process_all_events\! macro so that ChannelClose events broadcast the commitment tx and HTLCResolution events construct HTLC-timeout transactions via BumpTransactionEventHandler. For ChannelClose, the commitment tx is broadcast directly rather than going through the full anchor-bumping flow, since fuzz crypto produces non-standard signature sizes that trigger weight estimation assertions in the bump handler. Also change the force-close settlement loop from two fixed height advances to four iterations of advance+process_all_events, giving enough rounds for commitment tx confirmation, HTLC-timeout broadcast and confirmation, second-stage tx resolution, and final cleanup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1bf995a commit baa2540

1 file changed

Lines changed: 82 additions & 51 deletions

File tree

fuzz/src/chanmon_consistency.rs

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use lightning::chain::transaction::OutPoint;
4646
use lightning::chain::{
4747
chainmonitor, channelmonitor, BestBlock, ChannelMonitorUpdateStatus, Confirm, Watch,
4848
};
49-
use lightning::events;
49+
use lightning::events::{self, EventsProvider};
5050
use lightning::ln::channel::{
5151
FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS,
5252
};
@@ -84,6 +84,8 @@ use lightning::util::test_channel_signer::{EnforcementState, SignerOp, TestChann
8484
use lightning::util::test_utils::TestWalletSource;
8585
use lightning::util::wallet_utils::{WalletSourceSync, WalletSync};
8686

87+
use lightning::events::bump_transaction::sync::BumpTransactionEventHandlerSync;
88+
8789
use lightning_invoice::RawBolt11Invoice;
8890

8991
use crate::utils::test_logger::{self, Output};
@@ -2849,6 +2851,57 @@ pub fn do_test<Out: Output + MaybeSend + MaybeSync>(
28492851
last_pass_no_updates = false;
28502852
continue;
28512853
}
2854+
// Process chain monitor events (BumpTransaction, SpendableOutputs)
2855+
// which are separate from ChannelManager events.
2856+
{
2857+
let monitors = [&monitor_a, &monitor_b, &monitor_c];
2858+
let broadcasters: [&Arc<TestBroadcaster>; 3] = [&broadcast_a, &broadcast_b, &broadcast_c];
2859+
let keys_managers = [&keys_manager_a, &keys_manager_b, &keys_manager_c];
2860+
for (idx, monitor) in monitors.iter().enumerate() {
2861+
let wallet = WalletSync::new(
2862+
&wallets[idx],
2863+
Arc::clone(&loggers[idx]),
2864+
);
2865+
let handler = BumpTransactionEventHandlerSync::new(
2866+
broadcasters[idx].as_ref(),
2867+
&wallet,
2868+
keys_managers[idx].as_ref(),
2869+
Arc::clone(&loggers[idx]),
2870+
);
2871+
let broadcaster = broadcasters[idx];
2872+
monitor.chain_monitor.process_pending_events(
2873+
&|event: events::Event| {
2874+
if let events::Event::BumpTransaction(ref bump) = event {
2875+
match bump {
2876+
events::bump_transaction::BumpTransactionEvent::ChannelClose {
2877+
commitment_tx,
2878+
channel_id,
2879+
counterparty_node_id,
2880+
..
2881+
} => {
2882+
// Broadcast the commitment tx directly.
2883+
// Skip the full anchor-bumping flow
2884+
// since fuzz crypto causes weight
2885+
// assertion failures in the bump
2886+
// handler.
2887+
broadcaster.broadcast_transactions(&[(
2888+
commitment_tx,
2889+
lightning::chain::chaininterface::TransactionType::UnilateralClose {
2890+
counterparty_node_id: *counterparty_node_id,
2891+
channel_id: *channel_id,
2892+
},
2893+
)]);
2894+
},
2895+
events::bump_transaction::BumpTransactionEvent::HTLCResolution { .. } => {
2896+
handler.handle_event(bump);
2897+
},
2898+
}
2899+
}
2900+
Ok(())
2901+
},
2902+
);
2903+
}
2904+
}
28522905
// Then, make sure any current forwards make their way to their destination
28532906
if process_msg_events!(0, false, ProcessMessages::AllMessages) {
28542907
last_pass_no_updates = false;
@@ -2902,57 +2955,35 @@ pub fn do_test<Out: Output + MaybeSend + MaybeSync>(
29022955

29032956
// If any channels were force-closed, advance chain height past HTLC
29042957
// timelocks so HTLC-timeout transactions can be broadcast, confirmed,
2905-
// and fully resolved. We advance in two phases:
2906-
// 1) Past cltv_expiry so HTLC-timeout txs are released
2907-
// 2) Past the CSV delay so SpendableOutputs events fire
2958+
// and fully resolved. We iterate multiple times to cover: (1) confirm
2959+
// commitment txs, (2) confirm HTLC-timeout txs after bump handling,
2960+
// (3) confirm second-stage txs past CSV, (4) final cleanup.
29082961
if !closed_channels.borrow().is_empty() {
2909-
chain_state.advance_height(250);
2910-
sync_with_chain_state(
2911-
&chain_state,
2912-
&nodes[0],
2913-
&monitor_a,
2914-
&mut node_height_a,
2915-
None,
2916-
);
2917-
sync_with_chain_state(
2918-
&chain_state,
2919-
&nodes[1],
2920-
&monitor_b,
2921-
&mut node_height_b,
2922-
None,
2923-
);
2924-
sync_with_chain_state(
2925-
&chain_state,
2926-
&nodes[2],
2927-
&monitor_c,
2928-
&mut node_height_c,
2929-
None,
2930-
);
2931-
process_all_events!();
2932-
2933-
chain_state.advance_height(250);
2934-
sync_with_chain_state(
2935-
&chain_state,
2936-
&nodes[0],
2937-
&monitor_a,
2938-
&mut node_height_a,
2939-
None,
2940-
);
2941-
sync_with_chain_state(
2942-
&chain_state,
2943-
&nodes[1],
2944-
&monitor_b,
2945-
&mut node_height_b,
2946-
None,
2947-
);
2948-
sync_with_chain_state(
2949-
&chain_state,
2950-
&nodes[2],
2951-
&monitor_c,
2952-
&mut node_height_c,
2953-
None,
2954-
);
2955-
process_all_events!();
2962+
for _ in 0..4 {
2963+
chain_state.advance_height(250);
2964+
sync_with_chain_state(
2965+
&chain_state,
2966+
&nodes[0],
2967+
&monitor_a,
2968+
&mut node_height_a,
2969+
None,
2970+
);
2971+
sync_with_chain_state(
2972+
&chain_state,
2973+
&nodes[1],
2974+
&monitor_b,
2975+
&mut node_height_b,
2976+
None,
2977+
);
2978+
sync_with_chain_state(
2979+
&chain_state,
2980+
&nodes[2],
2981+
&monitor_c,
2982+
&mut node_height_c,
2983+
None,
2984+
);
2985+
process_all_events!();
2986+
}
29562987
}
29572988

29582989
// Verify no payments are stuck - all should have resolved

0 commit comments

Comments
 (0)