Skip to content

bug(anvil): transaction-hash forks mishandle protocol system transactions #15878

Description

@haythemsellami

Component

Anvil

Describe the bug

anvil --fork-transaction-hash reconstructs the selected block prefix by converting source envelopes into PoolTransactions and feeding them through ordinary pool validation and mining. That model is incorrect for networks with protocol-level system envelopes.

On Monad, canonical staking reward, snapshot, and epoch envelopes have protocol semantics that ordinary pool transactions do not: they bypass normal fee admission, validate and increment the system nonce, mint reward value when applicable, execute a dedicated staking system call, retain logs, and account zero receipt/block gas. Today these envelopes can be rejected before execution with errors such as GasTooLow or a base-fee validation failure.

The same forced-transaction path validates historical typed transactions against the configured local execution chain ID. Consequently, a source transaction from Monad chain ID 143 can be rejected when the fork is run with a different local --chain-id. Forced source transactions can also be coalesced with live local pool transactions even though they require different execution context and provenance.

Reproduction

Choose a Monad transaction whose preceding block prefix contains a canonical protocol envelope, then start Anvil with that transaction hash:

anvil --fork-url <MONAD_RPC_URL> --fork-transaction-hash <TRANSACTION_HASH>

The protocol envelope is routed through ordinary transaction validation instead of being replayed with its source-chain semantics, so the reconstructed prefix is rejected or produces incorrect state.

Expected behavior

The source block prefix should be replayed as a dedicated historical batch using the exact target block environment, source chain ID, and active source hardfork. Canonical protocol envelopes should use the network factory protocol replay semantics and produce zero-gas receipts where required. The batch should commit atomically, remain isolated from live local pool transactions, and restore the configured local chain ID afterward.

Suggested direction

Preserve explicit historical provenance rather than converting every source envelope to PoolTransaction; isolate the replay batch from the live pool; and stage, commit, or revert the entire prefix atomically. Ordinary source transactions should execute under source context, while protocol envelopes should use the same network replay hook already used by vm.transact.

This was exposed while integrating Monad in #15343. Related historical reports include #8940 and #13630.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status
Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions