Skip to content

fix(script): match resume receipts by hash - #16619

Closed
figtracer wants to merge 1 commit into
masterfrom
fig/fix-resume-receipt-holes
Closed

fix(script): match resume receipts by hash#16619
figtracer wants to merge 1 commit into
masterfrom
fig/fix-resume-receipt-holes

Conversation

@figtracer

Copy link
Copy Markdown
Member

Motivation

forge script --resume used the number of receipts as a positional cursor. If a transaction in the middle of a concurrently broadcast sequence reverted while a later transaction mined, the reverted transaction left no receipt and shifted that cursor onto the already-mined transaction. Resume could then resend the wrong transaction and fail with nonce too low.

Closes #16566.

Solution

Match stamped transactions to receipts by transaction hash, while retaining the positional fallback for older sequence files without hashes. Reverted transactions now retain their mined receipt, and concurrent send results carry their original sequence index when stamping hashes.

I reproduced the estimate-versus-mine state race against Anvil: two same-sender transactions passed preflight, the first reverted after the state changed, and the second mined successfully in the same block. The saved sequence retained both receipts, and a subsequent resume completed without sending another transaction.

This PR was written with Codex assistance for issue investigation, code generation, and validation. I reviewed and tested the resulting change.

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

Record reverted receipts as completed and preserve each transaction index while concurrent sends resolve. This prevents resume from treating receipt count as a positional cursor while retaining the legacy fallback for unstamped sequence files.
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

✅ Changelog found

The deterministic check will validate the changed entry.

@figtracer
figtracer marked this pull request as ready for review September 4, 2026 13:25
.iter()
.enumerate()
.filter(|(index, tx)| match tx.hash {
Some(hash) => !receipt_hashes.contains(&hash),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Legacy sequence compatibility

Before this PR, concurrent broadcasts associated returned hashes with sequence entries in FuturesUnordered completion order rather than transaction order. A legacy same-sender sequence can therefore contain swapped hashes.

If only nonce 0’s receipt is recorded while nonce 1 is dropped, the new lookup selects nonce 0 for rebroadcast and omits nonce 1; the positional base behavior selects nonce 1.

Consider adding a format marker and using hash matching only for newly corrected sequences, while retaining positional behavior for legacy files.

@figtracer

Copy link
Copy Markdown
Member Author

we dont need this

@figtracer figtracer closed this Sep 4, 2026
@github-project-automation github-project-automation Bot moved this to Done in Foundry Sep 4, 2026
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.

forge script --resume: positional receipt cursor can treat a reverted tx as complete and skip an already-mined later one

2 participants