Skip to content

Fix miner forced-tx deadlock (foundry-rs#14453)#502

Merged
Dargon789 merged 10 commits into
Dargon789:masterfrom
foundry-rs:master
Apr 29, 2026
Merged

Fix miner forced-tx deadlock (foundry-rs#14453)#502
Dargon789 merged 10 commits into
Dargon789:masterfrom
foundry-rs:master

Conversation

@Dargon789

@Dargon789 Dargon789 commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Motivation

Solution

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

Summary by Sourcery

Fix miner forced transaction polling deadlock and improve Tempo AA transaction validity handling while updating release, Docker, CI, and linting workflows.

Bug Fixes:

  • Ensure forced transactions are consumed without blocking miner mode polling, preventing deadlocks.
  • Treat Tempo AA transactions with future valid_after timestamps as not-yet-valid and retry them instead of misclassifying execution errors.
  • Allow unknown FOUNDRY_PROFILE selections to fall back to the default profile with a warning instead of failing configuration loading.
  • Accept inclusive maximum values in uint mutation validation to avoid incorrectly rejecting boundary values in fuzzing mutators.

Enhancements:

  • Refine release workflow to create draft releases upfront, derive changelog ranges from previous tags, and auto-publish nightlies while respecting immutable releases.
  • Simplify cross compilation setup by installing cross directly via cargo in release workflows.
  • Revise Docker tag derivation to standardize stable, nightly, and custom tags from the provided tag_name.
  • Update Tempo dependencies to a newer revision and add tests ensuring Tempo fork schedules from configured RPCs parse into known hardforks.
  • Add a new lint detecting missing zero-address checks before using address parameters in state writes or value transfers, with associated Solidity test coverage.
  • Emit a structured UnknownProfile warning for non-existent profiles selected via configuration and surface it in tests.
  • Adjust lint test severities and register the MissingZeroCheck info-level lint.
  • Add Tempo-related common crate tests and dev-dependency wiring for hardfork definitions.

Build:

  • Restrict release tagging triggers to semantic version tags and compute changelog ranges from prior nightly/stable tags.
  • Change docker-publish workflow defaults and tagging logic to align Docker tags with semantic versions and nightly identifiers.

CI:

  • Extend Tempo CI workflow to run fork schedule compatibility tests on configured RPCs and adjust Tempo network test gating.
  • Remove nightly tag move/prune scripts in favor of immutable nightly publishing semantics.

Documentation:

  • Clarify foundryup usage by distinguishing latest, nightly, and specific version installs in the README.

Chores:

  • Make tag creation idempotent by ignoring already-existing tag errors in the tag creation script.
  • Remove obsolete nightly tag maintenance scripts now that releases are immutable.

cuiweixie and others added 9 commits April 28, 2026 11:07
* ci(tempo): re-enable devnet steps and run testnet on PRs

Amp-Thread-ID: https://ampcode.com/threads/T-019dd305-c099-7742-8682-0d22798eaac7
Co-authored-by: Amp <amp@ampcode.com>

* disable devnet again, down as part of migration

* leave note

---------

Co-authored-by: Amp <amp@ampcode.com>
* feat: immutable releases

- Remove mutable tag triggers (stable, rc, rc-*) from release workflow;
  only v*.*.* semver tags trigger releases now
- Remove mutable 'nightly' GitHub release overwrite; each nightly gets
  its own immutable nightly-{SHA} release only
- Delete move-tag.js; stop force-moving the nightly tag to HEAD
- Docker: stop tagging :nightly and :latest; use immutable
  :nightly-{short-sha} and :v*.*.* tags instead
- foundryup: resolve 'latest' and 'nightly' channels via GitHub API
  to find the actual immutable release tags
- foundryup: 'stable' is a silent alias for 'latest'
- Simplify prune-prereleases.js filter (no mutable nightly to protect)
- Bump foundryup installer version to 1.8.0

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>

* fix: address immutable release gaps

- Docker: derive tags from inputs.tag_name directly, fixing
  workflow_call nightly mis-tagging
- Remove release pruning entirely (immutable means permanent)
- Delete prune-prereleases.js and cleanup job from release.yml
- Remove force: true from create-tag.js (invalid for createRef)

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>

* fix: use /releases/latest endpoint for stable channel resolution

Avoids pagination issue where 50+ nightlies could push the latest
stable release off the first page of results.

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>

* fix: use /releases/latest for latest channel, per_page=10 for nightly

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>

* fix: fail on unexpected tag creation errors, exclude drafts from nightly resolution

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>

* refactor: remove local variables and temp file from resolve_latest_release

Amp-Thread-ID: https://ampcode.com/threads/T-019dce16-13eb-7218-a42c-ce91ed473f36
Co-authored-by: Amp <amp@ampcode.com>

* refactor: inline release resolution, add fetch helper, improve logging

Amp-Thread-ID: https://ampcode.com/threads/T-019dce16-13eb-7218-a42c-ce91ed473f36
Co-authored-by: Amp <amp@ampcode.com>

* fix: handle pipefail in fetch pipelines for cross-platform compatibility

Amp-Thread-ID: https://ampcode.com/threads/T-019dce16-13eb-7218-a42c-ce91ed473f36
Co-authored-by: Amp <amp@ampcode.com>

* fix: use previous stable tag as changelog fromTag for stable releases

Amp-Thread-ID: https://ampcode.com/threads/T-019dce16-13eb-7218-a42c-ce91ed473f36
Co-authored-by: Amp <amp@ampcode.com>

* fix(docker): keep mutable :latest and :nightly tags following Docker convention

Amp-Thread-ID: https://ampcode.com/threads/T-019dce16-13eb-7218-a42c-ce91ed473f36
Co-authored-by: Amp <amp@ampcode.com>

* fix: use previous nightly tag as changelog fromTag for nightly releases

Amp-Thread-ID: https://ampcode.com/threads/T-019dce16-13eb-7218-a42c-ce91ed473f36
Co-authored-by: Amp <amp@ampcode.com>

* ci(release): adopt draft-first flow for GitHub immutable releases

- prepare creates the GitHub release as a draft up-front (with --verify-tag)
  so all matrix jobs upload assets to an existing draft.
- release matrix replaces softprops/action-gh-release with gh release upload
  --clobber against the draft.
- nightly releases are auto-published by a new publish-nightly job once all
  assets have been uploaded; stable releases are left as drafts for a
  maintainer to publish manually.
- prepare distinguishes existing draft (reuse) from already-published release
  (fail loudly), so a same-SHA nightly rerun after publication can't try to
  upload to an immutable release.

Amp-Thread-ID: https://ampcode.com/threads/T-019dced2-6c4a-76fb-af86-79fd948a0157
Co-authored-by: Amp <amp@ampcode.com>

* remove limit for safety

* fix(ci): use github context in publish-nightly job if condition

env context is not available in job-level if expressions

Amp-Thread-ID: https://ampcode.com/threads/T-019dd37e-7210-77da-bf0e-1d77ccecb19e
Co-authored-by: Amp <amp@ampcode.com>

---------

Co-authored-by: Amp <amp@ampcode.com>
)

* fix(config): warn instead of erroring on unknown FOUNDRY_PROFILE

When the selected profile (via `FOUNDRY_PROFILE` or otherwise) does
not exist in `foundry.toml`, fall back to the default profile and
emit a `Warning::UnknownProfile` instead of returning a hard error.

This matches the lenient behaviour used for nested lib configs and
keeps commands like `FOUNDRY_PROFILE=ci forge build` working when
`[profile.ci]` happens to be missing.

Amp-Thread-ID: https://ampcode.com/threads/T-019dd43e-e2d0-723e-bc03-03b0467dc68e
Co-authored-by: Amp <amp@ampcode.com>

* fix fmt

---------

Co-authored-by: Amp <amp@ampcode.com>
* feat(lint): add missing-zero-check

* rm Staticcall, guard ordering

* fix

* handle guards in branches

---------

Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com>
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
* chore: bump tempo and validate fork schedule

Amp-Thread-ID: https://ampcode.com/threads/T-019dd36a-7d77-772b-8cba-13f2147c9e5c

* test: cleanup + isolate on tempo mod

* style: fmt

* style: clippy

* fix: clippy
@codesandbox

codesandbox Bot commented Apr 29, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@vercel

vercel Bot commented Apr 29, 2026

Copy link
Copy Markdown

@isagi-y22 is attempting to deploy a commit to the Foundry development Team on Vercel.

A member of the Team first needs to authorize it.

@sourcery-ai

sourcery-ai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

Fixes a miner deadlock caused by forced transactions, improves Tempo AA handling and profile config UX, and overhauls release, Docker, and lint tooling around nightly/stable tags and zero-address checks.

Sequence diagram for miner poll handling of forced transactions

sequenceDiagram
    actor NodeOperator
    participant Miner
    participant MiningMode
    participant TxPool

    NodeOperator->>Miner: poll(pool, cx)
    Miner->>Miner: register(cx)
    alt forced_transactions is Some(vec)
        Miner->>MiningMode: poll(pool, cx)
        alt MiningMode returns Ready(transactions)
            MiningMode-->>Miner: Poll::Ready(next)
            Miner->>Miner: extend(forced_transactions, next)
        else MiningMode returns Pending
            MiningMode-->>Miner: Poll::Pending
            Miner->>Miner: keep only forced_transactions
        end
        Miner-->>NodeOperator: Poll::Ready(forced_transactions)
    else forced_transactions is None
        Miner->>MiningMode: poll(pool, cx)
        MiningMode-->>Miner: Poll::Ready or Poll::Pending
        Miner-->>NodeOperator: same Poll
    end
Loading

Sequence diagram for execute_pool_transactions handling Tempo AA valid_after

sequenceDiagram
    participant Executor as BlockExecutor
    participant Evm
    participant DB
    participant PoolTx as PoolTransaction

    loop for each pool_tx in pool_transactions
        Executor->>PoolTx: pending_transaction
        PoolTx-->>Executor: pending
        Executor->>Evm: evm()
        Evm-->>Executor: evm_ref
        Executor->>Evm: block().timestamp()
        Evm-->>Executor: block_timestamp
        Executor->>Executor: inspect pending.transaction
        alt FoundryTxEnvelope::Tempo with valid_after
            Executor->>Executor: compare valid_after to block_timestamp
            alt valid_after > block_timestamp
                Executor->>Executor: push pool_tx to not_yet_valid
                Note right of Executor: Skip execution, will retry later
            else valid_after <= block_timestamp
                Executor->>Evm: execute_transaction(pending)
                Evm-->>Executor: Ok or Err
                alt Ok
                    Executor->>Executor: record transaction and receipt
                else Err is validation error
                    Executor->>Executor: push pool_tx to invalid
                else other Err
                    Executor->>Executor: push pool_tx to failed
                end
            end
        else non-Tempo or no valid_after
            Executor->>Evm: execute_transaction(pending)
            Evm-->>Executor: Ok or Err
            alt Ok
                Executor->>Executor: record transaction and receipt
            else Err is validation error
                Executor->>Executor: push pool_tx to invalid
            else other Err
                Executor->>Executor: push pool_tx to failed
            end
        end
    end
Loading

Class diagram for MissingZeroCheck lint and config warnings

classDiagram
    class MissingZeroCheck {
        +check_function(ctx~LintContext~, hir~Hir~, func~Function~) void
    }

    class Analyzer {
        -hir Hir
        -taint HashMap_VariableId_HashSet_VariableId__
        -sinks HashSet_VariableId_
        -guarded HashSet_VariableId_
        -guard_depth u32
        -sink_depth u32
        +new(hir~Hir~, params~HashSet_VariableId_~) Analyzer
        +taint_sources(expr~Expr~) HashSet_VariableId_
        +visit_stmt(stmt~Stmt~) ControlFlow
        +visit_expr(expr~Expr~) ControlFlow
    }

    class LintContext {
        +emit(lint~SolLint~, span~Span~) void
    }

    class Warning {
        <<enum>>
        +DeprecatedKey
        +UnknownKey
        +UnknownProfile
    }

    class UnknownProfileVariant {
        +profile String
    }

    class Config {
        +profile String
        +warnings Vec_Warning_
        +DEFAULT_PROFILE String
        +load() Result_Config_ExtractConfigError_
    }

    class MissingZeroCheckLint {
        <<lint>>
        +MISSING_ZERO_CHECK
        +Severity Low
        +code missing-zero-check
        +message address parameter is used in a state write or value transfer without a zero-address check
    }

    MissingZeroCheck ..> Analyzer : uses
    MissingZeroCheck ..> LintContext : emits_warnings_via
    MissingZeroCheck ..> MissingZeroCheckLint : defines

    Config "1" o-- "*" Warning : collects
    Warning <|-- UnknownProfileVariant : variant
Loading

File-Level Changes

Change Details Files
Prevent miner deadlock when forced transactions are present and add regression coverage.
  • Change Miner::poll to always drain and return forced transactions first, only polling the mining mode if needed, and avoid holding the write lock longer than necessary.
  • Add a targeted unit test that constructs a forced transaction, polls the miner, asserts it is immediately returned once, and verifies subsequent polls behave correctly.
crates/anvil/src/eth/miner.rs
Handle Tempo AA "valid_after" at the executor level and tighten tests.
  • Specialize execute_pool_transactions for FoundryTxEnvelope and short-circuit AA transactions whose valid_after exceeds the current block timestamp, re-queueing them without relying on stringly-typed error inspection.
  • Remove the previous string "not valid yet" check in the error path and treat only validation errors as invalid transactions.
  • Extend the Tempo AA integration test to assert the transaction is not mined before valid_after, and that the token balance only changes once the timestamp passes valid_after.
crates/anvil/src/eth/backend/executor.rs
crates/anvil/tests/it/tempo.rs
Relax unknown-profile handling while surfacing explicit warnings.
  • Change Config loading to fall back to the default profile when an unknown profile is selected, emitting a Warning::UnknownProfile in strict mode instead of failing.
  • Add the UnknownProfile warning variant, with a user-facing Display message explaining the fallback.
  • Update the regression test for FOUNDRY_PROFILE=nonexistent to assert a warning and default-profile fallback instead of an error.
crates/config/src/lib.rs
crates/config/src/warning.rs
Add a MissingZeroCheck Solidity lint to detect missing zero-address guards on address parameters.
  • Implement the MissingZeroCheck late lint pass using a lightweight taint analysis that tracks address parameters through local aliases, guards (require/assert, modifiers), and sinks (state writes and value transfers/calls).
  • Handle modifiers, conditionals, loops, try/catch, and various call forms (call, delegatecall, transfer, send, payable casts) to avoid both false negatives and obvious false positives.
  • Add comprehensive Solidity test cases and expected diagnostics to validate the lint behaviour across guarded/unguarded patterns and edge cases, and wire the lint into the info lint registry.
  • Adjust existing lint test inputs’ compile flags to reflect severity expectations.
crates/lint/src/sol/info/missing_zero_check.rs
crates/lint/src/sol/info/mod.rs
crates/lint/testdata/MissingZeroCheck.sol
crates/lint/testdata/MissingZeroCheck.stderr
crates/lint/testdata/UncheckedCall.sol
crates/lint/testdata/UncheckedTransferERC20.sol
Tighten fuzz uint mutation bounds and add regression tests.
  • Change validate_uint_mutation to accept mutated values up to and including the computed max (2^size - 1) instead of strictly less than max.
  • Add a regression unit test that verifies inclusive handling of max for several bit widths and for the 256-bit max value.
crates/evm/fuzz/src/strategies/mutators.rs
Align Tempo dependencies and add a fork-schedule compatibility test used in CI.
  • Bump all tempo-* git dependencies to a new shared revision across workspace manifests to keep Tempo components in sync.
  • Add a Tempo fork-schedule test that hits tempo_forkSchedule on configured RPC URLs and parses the reported forks against TempoHardfork, skipping when no env vars are configured.
  • Wire the Tempo fork-schedule test into the ci-tempo workflow, and gate devnet-specific steps until the devnet is stable; ensure testnet checks run on PRs.
Cargo.toml
crates/common/Cargo.toml
crates/common/src/tempo/mod.rs
crates/common/src/tempo/tests.rs
.github/workflows/ci-tempo.yml
Rework release workflow to support immutable releases, proper changelog diffs, and nightly publishing, and adjust Docker tagging and foundryup docs accordingly.
  • Simplify release tag triggers to v*.. tags, remove LAST_STABLE_VERSION, and compute from_tag dynamically for both nightly and stable releases using git tag queries.
  • Replace softprops-based release creation with an explicit gh-based flow that pre-creates a draft release (or reuses an existing draft), uploads assets from matrix jobs to that draft, and introduces a publish-nightly job that publishes nightly drafts once all assets are attached.
  • Adjust the nightly tag management scripts by removing move-tag/prune-prereleases and making create-tag idempotent when tags already exist.
  • Update docker-publish to derive Docker tags from the provided tag_name (version tags, nightly-SHA, or arbitrary tags) and set the default tag_name to nightly-dev.
  • Clarify foundryup README usage around installing latest, nightly, and explicit versions, consistent with the new tagging scheme, and ensure the release workflow uses the changelog builder’s fromTag output instead of hard-coded tag names.
  • Switch musl cross builds in the release workflow from the cache-cargo-install action to a direct cargo install of cross with a pinned revision.
.github/workflows/release.yml
.github/workflows/docker-publish.yml
.github/scripts/create-tag.js
.github/scripts/move-tag.js
.github/scripts/prune-prereleases.js
foundryup/README.md
foundryup/foundryup

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@snyk-io

snyk-io Bot commented Apr 29, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a variety of enhancements and bug fixes, most notably a new Solidity lint for detecting missing zero-address checks, a fix for an off-by-one error in fuzzing mutators, and a significant update to foundryup for better release resolution. Anvil's transaction execution was also updated to support Tempo's valid_after field. Feedback focuses on refining the new lint's analysis—specifically improving taint propagation for local variables, handling chained call options, and extending coverage to complex state writes like mappings and structs. Additionally, a more robust parsing strategy for GitHub API responses in foundryup was suggested to avoid fragility.

Comment thread crates/lint/src/sol/low/missing_zero_check.rs
Comment thread foundryup/foundryup
Comment thread crates/lint/src/sol/low/missing_zero_check.rs
Comment thread crates/lint/src/sol/low/missing_zero_check.rs
@vercel

vercel Bot commented Apr 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
next Ready Ready Preview, Comment Apr 29, 2026 8:31am
react Ready Ready Preview, Comment Apr 29, 2026 8:31am

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.

Sequence diagram for miner poll handling of forced transactions Sequence diagram for parsing repo specs and running forge with extra args

8 participants