Skip to content

manager: tell apart missing transactions from mempool transactions - #181

Merged
bennyhodl merged 1 commit into
masterfrom
fix/tx-confirmation-status
Aug 15, 2026
Merged

manager: tell apart missing transactions from mempool transactions#181
bennyhodl merged 1 commit into
masterfrom
fix/tx-confirmation-status

Conversation

@bennyhodl

Copy link
Copy Markdown
Owner

Summary

Redo of #169. Blockchain::get_transaction_confirmations returned Ok(0) both for a transaction in the mempool and for a transaction the network does not know. With NB_CONFIRMATIONS=0 the manager moved contracts through states on transactions that were evicted from the mempool or never broadcast. The trait now returns a ConfirmationStatus enum — NotFound / InMempool / Confirmed(n) — and the manager handles each case. There is no recovery scan over closed contracts: the state machine no longer enters Closed on a transaction that is not on-chain, so there is nothing to recover.

Changes

  • ddk-manager/src/lib.rs: new ConfirmationStatus enum with a confirmations() helper. Blockchain::get_transaction_confirmations returns it instead of a bare u32. This is a breaking change for trait implementers.
  • ddk/src/chain/esplora.rs: when the status endpoint reports a transaction unconfirmed, query the transaction itself to tell "in the mempool" apart from "not found" (esplora reports both as unconfirmed). Transport errors stay Err, so a flaky esplora is not mistaken for a dropped transaction. The tip-height call now only runs for confirmed transactions.
  • check_signed_contract: a missing funding transaction does not confirm the contract.
  • check_for_spliced_contract: a missing splice funding transaction does not pre-close the previous contract.
  • Pending close transactions that are missing are skipped instead of counted as zero confirmations.
  • check_preclosed_contract: a missing closing transaction is broadcast again (safe when the chain source lags — the network accepts a transaction it already knows). If it cannot enter the mempool and the pre-close has no attestations (splice or cooperative close), the funding output is unspent and the contract moves back to Confirmed.
  • Entering the terminal Closed state now requires at least one confirmation on-chain, also when NB_CONFIRMATIONS=0. No periodic check examines Closed contracts again, so a mempool-only transaction that later gets evicted must not put a contract there. This closes the exact incident path: with NB_CONFIRMATIONS=0 a splice contract now stays PreClosed until its funding transaction is mined, and reverts to Confirmed if that transaction is dropped.
  • New integration test ddk/tests/chain.rs asserts the esplora client reports NotFound, InMempool, and Confirmed correctly against a regtest backend.

Testing

  • cargo test -p ddk -p ddk-manager (full non-ignored suites) pass.
  • NB_CONFIRMATIONS=6 cargo test -p ddk-manager --test manager_execution_tests -- --ignored --exact splice_in_enum_single_oracle_test cooperative_close_single_oracle_test enum_single_oracle_refund_test pass.
  • Note: cooperative_close_single_oracle_test fails on master too when NB_CONFIRMATIONS is unset locally (CI sets it to 6); not related to this change.
  • cargo clippy clean for the changed code; cargo check --workspace passes.

Blockchain::get_transaction_confirmations returned Ok(0) both for a
transaction in the mempool and for a transaction the network does not
know. With NB_CONFIRMATIONS=0 the manager then moved contracts through
states on transactions that were evicted from the mempool or never
broadcast.

Return a ConfirmationStatus enum (NotFound / InMempool / Confirmed(n))
instead of a bare count. The esplora client queries the transaction
itself when the status endpoint reports it unconfirmed, because esplora
reports "unconfirmed" for both cases. Transport errors stay errors, so
a flaky esplora is not mistaken for a dropped transaction.

The manager handles NotFound explicitly:
- check_signed_contract does not confirm a contract whose funding
  transaction is missing.
- check_for_spliced_contract does not pre-close the previous contract
  when the splice funding transaction is missing.
- Pending close transactions that are missing are skipped.
- check_preclosed_contract broadcasts the closing transaction again;
  when it cannot enter the mempool and the pre-close has no
  attestations (splice or cooperative close), the contract moves back
  to Confirmed.
- Entering the terminal Closed state now requires at least one
  confirmation on-chain, also when NB_CONFIRMATIONS is zero, because no
  periodic check examines Closed contracts again.
@bennyhodl
bennyhodl merged commit f2d7844 into master Aug 15, 2026
134 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant