Skip to content

fuzz: model chanmon mempool mining#4657

Merged
joostjager merged 1 commit into
lightningdevkit:mainfrom
joostjager:chanmon-mempool-mining
Jun 15, 2026
Merged

fuzz: model chanmon mempool mining#4657
joostjager merged 1 commit into
lightningdevkit:mainfrom
joostjager:chanmon-mempool-mining

Conversation

@joostjager

Copy link
Copy Markdown
Contributor

This prepares chanmon_consistency for force-close fuzzing by making its chain model closer to the environment LDK sees in normal operation.

Force-close scenarios depend heavily on transaction timing: claims may be broadcast, replaced, confirmed, followed by additional claims, and later become spendable only after more blocks. The previous harness mostly folded transaction confirmation into sync-style actions, which made it harder to express those flows accurately and made future force-close coverage depend on shortcuts in the test harness.

The updated model gives the harness an explicit mempool and block-mining path. Broadcast transactions can be relayed into the modeled mempool, mined into harness blocks, and then replayed to both monitors and managers through chain callbacks. The harness also tracks confirmed UTXOs and wallet change so later splice, anchor, and claim transactions have a realistic view of what can be spent.

This should make upcoming force-close fuzzing changes easier to review: first establish a more faithful chain environment, then add the force-close-specific scenarios and invariants on top of it.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@joostjager

Copy link
Copy Markdown
Contributor Author

@wpaulino FYI, this may intersect with the existing splice fuzzing failures you’re looking at.

This PR makes splice transaction mining in chanmon_consistency more realistic: negotiated splice transactions no longer get implicitly confirmed through the old sync-style path. Instead, broadcasts have to pass through the harness’s modeled mempool and are confirmed only when the fuzz input mines blocks.

@joostjager joostjager force-pushed the chanmon-mempool-mining branch 4 times, most recently from 4e6f262 to d02194d Compare June 4, 2026 05:19
@joostjager

Copy link
Copy Markdown
Contributor Author

Fuzz failure is pre-existing

@joostjager joostjager force-pushed the chanmon-mempool-mining branch 2 times, most recently from 0ab5882 to ef0be5b Compare June 4, 2026 09:24
@joostjager joostjager marked this pull request as ready for review June 4, 2026 10:04
@joostjager joostjager removed the request for review from valentinewallace June 4, 2026 10:04
Comment thread fuzz/src/chanmon_consistency.rs
Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines +1184 to +1236
// Connects this node from its tracked height to target_height, delivering
// each relevant chain callback to both ChainMonitor and ChannelManager.
fn connect_chain_range(&mut self, chain_state: &ChainState, target_height: u32) {
// Mining commands can advance the harness chain by more than one block.
// Transaction blocks must be connected explicitly so LDK learns about
// on-chain spends, while empty depth blocks still need best-block
// updates so CSV/CLTV-sensitive logic can run. This is the normal sync
// path, so both the raw ChainMonitor and the ChannelManager receive the
// callbacks and the node's tracked height advances to the target.
let mut height = self.height;
while height < target_height {
let mut next_height = height + 1;
while next_height <= target_height && chain_state.block_at(next_height).1.is_empty() {
next_height += 1;
}
if next_height > target_height {
// The rest of the range is empty. One best-block update to the
// final height is enough because LDK's Confirm API explicitly
// allows best_block_updated to skip intermediary blocks, and
// empty blocks have no transactions_confirmed calls whose chain
// order must be preserved.
height = target_height;
let (header, _) = chain_state.block_at(height);
self.monitor.best_block_updated(header, height);
self.node.best_block_updated(header, height);
break;
}
if next_height > height + 1 {
// Advance across the empty prefix before the next transaction
// block. Confirm::best_block_updated may skip intermediary
// blocks, so this compressed update still lets height-triggered
// LDK work run at the correct tip before the transaction
// confirmations are connected.
height = next_height - 1;
let (header, _) = chain_state.block_at(height);
self.monitor.best_block_updated(header, height);
self.node.best_block_updated(header, height);
}
height = next_height;
let (header, txn) = chain_state.block_at(height);
let txdata: Vec<_> = txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect();
if !txdata.is_empty() {
// Transaction blocks need the explicit confirmation callback
// before the best-block update so watched spends are delivered
// in chain order before the node advances to that tip.
self.monitor.transactions_confirmed(header, &txdata, height);
self.node.transactions_confirmed(header, &txdata, height);
}
self.monitor.best_block_updated(header, height);
self.node.best_block_updated(header, height);
}
self.height = target_height;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good improvement: the old sync_with_chain_state only notified self.node (ChannelManager), never self.monitor (ChainMonitor). This means ChannelMonitors weren't receiving transactions_confirmed / best_block_updated callbacks during normal fuzz-loop sync, which would have hidden any bugs in monitor chain-tracking logic. The new connect_chain_range fixing this is an important correctness improvement.

One behavioral change worth noting: the old code called best_block_updated for every individual block height. The new code batches consecutive empty blocks into a single best_block_updated call at the last empty height before the next tx block (or at the target). This is allowed by the Confirm trait ("May be skipped for intermediary blocks"), but it means height-triggered logic inside ChainMonitor/ChannelManager runs at fewer checkpoints than before. For a fuzzer seeking maximum coverage of height-sensitive paths (e.g., HTLC timeout detection), individual block delivery would exercise more code paths.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also argue that skipping exercises different paths. I think in practice, we'll get a bit from both.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
@ldk-claude-review-bot

ldk-claude-review-bot commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

I've re-reviewed the PR against my prior review notes and re-examined the areas not previously covered in depth: the asymmetric connect_chain_range (monitor vs. manager start heights), oldest_monitor_height_for_node, the reload startup-sync in restart_node, the new FundingTransactionReadyForSigning RBF-race handling, the mempool admission/RBF eviction logic in admit_tx_to_mempool, harness mine_blocks wallet UTXO reconciliation, and settle_all's new pre-sync.

No new issues found.

I verified:

  • connect_chain_range correctly handles the monitor-lags-manager case (delivers transactions_confirmed/best_block_updated to monitors for blocks below manager_start_height while skipping the manager), and the empty-block batching only ever skips intermediary heights as permitted by the Confirm API. Index/underflow paths in safe_mine_block_count, MINE_BLOCK_COUNTS[v - 0xd9], and block_at are all in-bounds.
  • The mempool ordering invariant in admit_tx_to_mempool (append-last + descendant eviction preserving order) is consistent with the mining-time has_invalid_inputs assertion, so that assert should not false-fire.
  • claimed_payment_hashes.insert is present at chanmon_consistency.rs:2160 — confirming the carried-forward correction that the original first-pass "insert removed" claim was wrong. The prior inline comment at :2159 should be disregarded; assert_claims_reported() is not a no-op.

The following previously-flagged issues remain present in the current code and were intentionally not re-posted per the no-duplicate rule:

  • fuzz/src/chanmon_consistency.rs:323 — off-by-one in mempool locktime validation (tip < lock_time vs tip + 1 < lock_time); will cause false assertion failures on HTLC-timeout txs once force-close fuzzing lands.
  • fuzz/src/chanmon_consistency.rs:2610mine_blocks(ANTI_REORG_DELAY) == 0 finish path / :2619 quiescence assert can false-positive when a relayed mempool tx coexists with a near-deadline HTLC (safe_mine_block_count clamps to 0).
  • fuzz/src/chanmon_consistency.rs:2600finish relay/mine loop never processes events between rounds and never drains final-round broadcasts; both become reachable false-positives once anchor/force-close broadcasts are modeled.
  • fuzz/src/chanmon_consistency.rs:3612 (splice command) — break 'fuzz_loop discards remainder of input when !cfg!(splicing) instead of continue.
  • fuzz/src/chanmon_consistency.rs:1146connect_chain_range empty-block batching reduces height-trigger coverage vs. block-by-block delivery.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
@jkczyz jkczyz self-requested a review June 4, 2026 14:06
@joostjager joostjager force-pushed the chanmon-mempool-mining branch from 4036d6a to 57960f1 Compare June 4, 2026 14:42
@joostjager joostjager self-assigned this Jun 4, 2026
@joostjager

Copy link
Copy Markdown
Contributor Author

When we are good with the changes, I can tack on one more commit that moves the chain/mempool code into fuzz/src/chanmon_consistency/chain_mempool.rs. With force close fuzzing, we are moving towards a 5000 line file, so no harm in already splitting things out if we are make changes anyway.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
const DEFAULT_TX_CONFIRMATION_BLOCKS: u32 = 6;
// Single fuzz bytes can mine more than one block so a corpus entry does not
// need long runs of identical "mine one block" commands to reach CSV or CLTV
// boundaries. Mining is clipped below if unresolved HTLCs are near expiry.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is meant by "clipped below"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That mining stops before anything would expire. Changed it to 'capped'

Comment thread fuzz/src/chanmon_consistency.rs Outdated
// A mined transaction is considered deeply confirmed after this many blocks.
// This confirms the transaction in one block and then mines five empty depth
// blocks.
const DEFAULT_TX_CONFIRMATION_BLOCKS: u32 = 6;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ANTI_REORG_DELAY?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines +3110 to +3114
events::Event::PaymentClaimed { payment_hash, .. } => {
if payments.payment_preimages.contains_key(&payment_hash) {
payments.claimed_payment_hashes.insert(payment_hash);
}
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this (moved from line 1943) be a separate commit?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm yes, that is already living in #4635. Removed code from this PR.

Comment on lines +3381 to +3387
assert!(
current_tip < timeout_deadline,
"pending HTLC with expiry {} and timeout deadline {} is already unsafe at tip {}",
expiry,
timeout_deadline,
current_tip
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails with the following input:

printf '\x20\xdf\xdf\xb0\x0e\x10\x18\x10\x18\x10\x18\x30\xd8' | ./target/release/chanmon_consistency_target

Claude's succinct summary:

The persisted view can drift arbitrarily behind chain_state.tip because Harness::mine_blocks never re-checkpoints, so after a deferred reload the node builds an HTLC against a stale view with a deadline already below the tip. Fix it by either soft-capping the past-deadline branch in safe_mine_block_count to return 0, or — better — also capping mining against the lowest persisted-manager view so a future reload-then-send can't produce an immediately-unsafe HTLC.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this was the missing startup-sync piece from the FC branch that I forgot to cherry-pick. Reload now catches ChainMonitor up from the oldest monitor height and ChannelManager from its own best block before returning to the fuzz loop.

The repro passes now

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines +2676 to +2679
assert!(
self.mine_blocks(DEFAULT_TX_CONFIRMATION_BLOCKS) > 0,
"finish cannot mine pending mempool transactions without crossing an unresolved HTLC timeout deadline"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be reached using:

printf '\xc9\xa6\xff\xde\xdf' | ./target/release/chanmon_consistency_target

@joostjager joostjager Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one the the ones below contain splice opcodes. As that is currently not yet stable, I don't want to go into debugging that preferably 😬 Without the splicing cfg flag, those strings pass.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
@@ -2818,13 +3128,7 @@
.funding_transaction_signed(&channel_id, &counterparty_node_id, signed_tx)
.unwrap();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now reachable:

printf '\xa7\xa0\xff\xd5\xd8\xa0\xff' | ./target/release/chanmon_consistency_target

Comment on lines 3162 to 3164
panic!(
"It may take may iterations to settle the state, but it should not take forever"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Able to hit this now but looks like it was preexisting, too.

printf '\xa7\xa0\xff\xd5\xd8\xa0\xff' | ./target/release/chanmon_consistency_target

let is_quiescent_msg = msg.data.contains("already sent splice_locked, cannot RBF");
if !msg.data.contains("Disconnecting due to timeout awaiting response") && !is_quiescent_msg
{
panic!("Unexpected disconnect case: {}", msg.data);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this can be hit prior to your change.

printf '\xc7\x3a\xa2\x32\x3a\xff\xff\xa7\x35\x33\x45\xff' | ./target/release/chanmon_consistency_target

We may need to expand the allowed reason.

@joostjager joostjager force-pushed the chanmon-mempool-mining branch from 57960f1 to 771e8a5 Compare June 8, 2026 09:24
Comment thread fuzz/src/chanmon_consistency.rs Outdated
@joostjager joostjager force-pushed the chanmon-mempool-mining branch from 771e8a5 to 534bb75 Compare June 8, 2026 09:36
@joostjager

joostjager commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Review comments addressed: https://github.com/lightningdevkit/rust-lightning/compare/57960f1..3b8a78e1d9c61e184e4ccb7ea9279b9f832df580

  • Use ANTI_REORG_DELAY for setup confirmations.
  • Derive node height from ChannelManager instead of cached state.
  • Sync restarted monitors and managers from their own persisted heights.
  • Restore claimed-payment tracking for the final PaymentSent invariant.
  • Move relay/mining opcodes to start at 0xd6, leaving 0xd3..0xd5 free for fuzz: add chanmon holder signer fuzz ops #4660

@joostjager joostjager force-pushed the chanmon-mempool-mining branch 2 times, most recently from 9458dc7 to 3b8a78e Compare June 8, 2026 10:11
@joostjager joostjager requested a review from jkczyz June 8, 2026 10:36
Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment thread fuzz/src/chanmon_consistency.rs Outdated
confirmed_txids: HashSet<Txid>,
/// Unconfirmed transactions (e.g., splice txs). Conflicting RBF candidates may coexist;
/// `confirm_pending_txs` determines which one confirms.
/// Unconfirmed transactions admitted by the harness mempool. Admission keeps

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"by" or "into"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it 'admitted to'

Comment thread fuzz/src/chanmon_consistency.rs Outdated
/// created by an earlier transaction in this vector.
pending_txs: Vec<(Txid, Transaction)>,
/// Tracks unspent outputs created by confirmed transactions. Admission builds
/// a temporary package view from this set plus earlier mempool transactions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is meant by "earlier mempool transactions" here? Do you mean the state of pending_txs at time of insertion into utxos?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified

Comment on lines -240 to -242
/// Confirm pending transactions in a single block, selecting deterministically among
/// conflicting RBF candidates. Sorting by txid ensures the winner is determined by fuzz input
/// content. Transactions that double-spend an already-confirmed outpoint are skipped.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to retain this behavior for splicing at least. Otherwise, we won't exercise code confirming an RBF that isn't the most recent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which candidate confirms is still fuzz-chosen, just via relay order instead of txid sort: admission keeps whichever conflicting tx was relayed last (no fee-rate policy), and mining confirms whatever is in the mempool at that point. So an input can confirm a non-latest candidate either by mining before the replacement is relayed, or by relaying an older copy from another node's queue after the newer one.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines +382 to +384
// that conflicting transaction itself signals RBF. The harness does not
// model fee-rate policy, so fuzz-controlled relay order chooses between
// otherwise valid RBF candidates.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what is meant by "fuzz-controlled relay order chooses between otherwise valid RBF candidates". How can an "order" choose? What criteria is it using for choosing? Is saying "does not model fee-rate policy" supposed to indicate that the fee rate isn't considered during replacement?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fuzz-controlled relay order is what I try to explain here: #4657 (comment)

Indeed, replacement is based on relay order, with fee being ignored.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
// need this to keep double-spends and unknown-prevout spends from producing
// impossible on-chain state.
fn has_invalid_inputs(tx: &Transaction, utxos: &HashSet<BitcoinOutPoint>) -> bool {
// The tiny UTXO set protects the chain model from two false positives:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is "The tiny UTXO set"?

@joostjager joostjager Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI weirdness. It's just a dupe-checking set.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines +265 to +268
// Coinbase transactions have a null input, and synthetic funding
// transactions have no inputs, but neither consumes a modeled UTXO.
// Normal transactions consume their inputs before exposing outputs to
// later transactions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I find the AI-generated comments like this and others jarring to read. I need to parse it multiple times to determine what it's trying to say and why it's worth saying. i.e. Why a "modeled" UTXO and not just a UTXO? What value does the last sentence provide?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this whole section.

@joostjager

Copy link
Copy Markdown
Contributor Author

Ouch, so much AI weirdness. Been experimenting with this extensive comment style. It is extra info, but it also needs to be right, which increases the review burden for author and reviewer to get there. Been looking over all kinds of change sets so often, and I did think I reviewed this one thoroughly, but clearly not.

I found the insights obtained via AI-added comments quite useful, to avoid asking it to explain things repeatedly, but perhaps it is better reserved for the dev stage and removed before review.

Will address this and clean up.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment thread fuzz/src/chanmon_consistency.rs
@joostjager joostjager force-pushed the chanmon-mempool-mining branch 3 times, most recently from f012c8f to 9c64644 Compare June 10, 2026 19:57
@joostjager joostjager requested a review from wpaulino June 10, 2026 20:03
@joostjager joostjager force-pushed the chanmon-mempool-mining branch 5 times, most recently from 95b628a to cc04e72 Compare June 12, 2026 13:39
@joostjager

joostjager commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Working on getting this to pass with splicing. Opened a reference branch to see changes since last review excluding rebases: https://github.com/joostjager/rust-lightning/compare/chanmon-mempool-mining-ref..chanmon-mempool-mining

  • Persist WalletSync per harness node so splice coin-selection locks survive across attempts.
  • Track confirmed outputs in ChainState to classify spent inputs as wallet-owned, shared/channel-owned, or unmodeled.
  • Cancel stale funding signing only for spent local wallet inputs; continue signing when the spent input is the shared funding input.
  • Treat confirmed-splice RBF rejection and splice reserve-breach rejection as recoverable quiescence disconnects.
  • Reject splice RBF in LDK once any pending splice candidate has confirmed, before splice_locked exchange completes.

@joostjager joostjager force-pushed the chanmon-mempool-mining branch from cc04e72 to c04cef6 Compare June 12, 2026 14:26
Comment thread lightning/src/ln/channel.rs Outdated
.iter()
.any(|funding| funding.funding_tx_confirmation_height != 0)
{
return Err(ChannelError::WarnAndDisconnect(format!(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should respond with tx_abort, there's no need to disconnect.

// A queued RBF signing request can lose the race against a
// transaction confirming with one of its wallet inputs.
match nodes[node_idx]
.cancel_funding_contributed(&channel_id, &counterparty_node_id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like something end users would need to handle as well, which doesn't seem ideal. We could instead cancel an ongoing negotiation if we see a splice confirm (even if not locked). If the confirmation is reorged out, then the user could re-attempt their negotiation, though there isn't any way currently for the user to detect that case.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines +944 to +945
|| msg.data.contains("smaller than their selected v2 reserve")
|| msg.data.contains("smaller than our selected v2 reserve");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are resulting from processing a counterparty's splice_init/ack/tx_init/ack_rbf, then we should be responding with tx_abort instead.

Comment thread fuzz/src/chanmon_consistency.rs Outdated
// breach the channel reserve. Like the RBF case, this leaves the channel
// quiescent, so both sides must exit quiescence afterwards.
let is_quiescent_msg = msg.data.contains("already sent splice_locked, cannot RBF")
|| msg.data.contains("has a confirmed pending splice, cannot RBF")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this happening in can_initiate_rbf as the sender, validate_tx_init_rbf as the receiver, or both?

Route chanmon broadcasts through an explicit harness mempool so relay,
mining, wallet updates, and chain delivery share one path. This lets
broadcast transactions enter the mempool before a modeled block confirms
them.

On restart, sync loaded monitors and managers from their own persisted
best blocks so raw monitors catch up without rewinding ChannelManager
state. Cap modeled mining before unresolved HTLC timeout deadlines
and use the LDK anti-reorg depth for setup confirmations.
@joostjager joostjager force-pushed the chanmon-mempool-mining branch from c04cef6 to 5c83835 Compare June 15, 2026 11:54
@joostjager

joostjager commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@wpaulino it seems that the changes go beyond a quick fix. Also let codex do its thing, which seems to confirm this: https://github.com/joostjager/rust-lightning/compare/chanmon-mempool-mining..chanmon-mempool-mining-splicing

I'd like to unblock force close fuzzing and not make it dependent on splicing. Reverted the (ldk) splicing changes in this PR so we can proceed independently.

@joostjager joostjager requested a review from wpaulino June 15, 2026 12:02
@joostjager joostjager merged commit f731548 into lightningdevkit:main Jun 15, 2026
1 check passed
@joostjager

Copy link
Copy Markdown
Contributor Author

Ran fuzzer for a day (splicing disabled) before merging, no crashes found.

@joostjager

joostjager commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Documented unresolved splice issues in #4696

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants