execution/vm: preserve EIP-4788 no-op-when-not-deployed syscall semantics#20691
Merged
execution/vm: preserve EIP-4788 no-op-when-not-deployed syscall semantics#20691
Conversation
…tics #19277 added `&& !syscall` to the Spurious Dragon zero-value short-circuit in evm.call, so system calls to a non-deployed target now run CreateAccount(addr, false) instead of returning a no-op. That breaks EIP-4788's rule that the beacon-root syscall is a no-op when the contract code is empty — specifically at the fork-transition block, where the beacon-root contract is deployed later in the same block by a CREATE tx. The pre-tx CreateAccount diverts state enough that a later verifier tx underuses gas and the block is rejected with a gas mismatch. Surfaced once #20606 (bal-devnet-4) flipped ExperimentalBAL + Exec3Parallel on by default: eest_blockchain's cancun/eip4788_beacon_root/test_beacon_root_contract_deploy[deploy_on_cancun] goes red with "gas used by execution: 52529, in header: 116552" on block 2. Dropping the `!syscall` clause restores the no-op short-circuit. The rest of #19277 (skip CanTransfer on zero-value calls, TouchAccount(caller) instead of Transfer for syscalls, intra_block_state refactor) is preserved. TestSystemCallZeroValueSkipsTransferChecks still passes (its target already exists, so this path isn't exercised). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR restores the “no-op when target is not deployed and value is zero” behavior for system calls (notably EIP-4788) by removing the && !syscall restriction from the Spurious Dragon short-circuit in EVM.call, preventing unintended account creation during fork-transition blocks.
Changes:
- Re-enable the Spurious Dragon zero-value short-circuit for system calls to non-deployed targets.
- Add an explanatory comment describing the fork-transition/system-call motivation for the short-circuit.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The previous comment framed the Spurious Dragon zero-value short-circuit as EIP-4788/6110/7002/7251 syscall-specific, but: - the condition is not gated on `syscall` — it fires for any zero-value CALL to a non-existent non-precompile account (standard EIP-161); - EIP-6110 parses deposit logs and does not issue a system call; - EIP-7002 and EIP-7251 guard the syscall with a codeSize==0 pre-check in misc/eip7002.go and misc/eip7251.go, so they error out before reaching this branch. Only EIP-4788 relies on this short-circuit today (it has no pre-check and depends on the VM returning a no-op when the beacon-root contract has not yet been deployed at the fork-transition block). Describe the general condition first, then the EIP-4788 motivation for preserving it. Addresses Copilot review feedback on #20691. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
taratorio
approved these changes
Apr 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
#19277 added
&& !syscallto the Spurious Dragon zero-value short-circuit inevm.call, causing system calls to a non-deployed target to runCreateAccount(addr, false)instead of returning a no-op. That violates EIP-4788's rule that "if the contract code is empty, the system call is a no-op", specifically at the fork-transition block where the beacon-root contract is deployed later in the same block by a CREATE tx.Repro
On #20606 (
bal-devnet-4), which flipsExperimentalBAL + Exec3Parallelon by default, the eest_blockchain suite fails:Block 1 is the first Cancun block (timestamp=15000, fork point). The EIP-4788 pre-block syscall fires before the beacon-root contract is deployed later in block 1's tx 0. Post-#19277, the syscall calls
CreateAccount(0x000f3df6…, false)at the beacon-root address, diverting state so block 2's verifier tx underuses gas by ~64k.Reverting only the
!syscallclause from the short-circuit — while keeping the rest of #19277 — makes the test green without regressingTestSystemCallZeroValueSkipsTransferChecks(its target already exists, so this branch isn't exercised).Change
execution/vm/evm.go, one hunk:if !exist { - if !isPrecompile && evm.chainRules.IsSpuriousDragon && value.IsZero() && !syscall { + // EIP-4788/6110/7002/7251 system calls to a non-deployed target are + // no-ops ... short-circuit to preserve that at the fork-transition block. + if !isPrecompile && evm.chainRules.IsSpuriousDragon && value.IsZero() { return nil, gas, nil } evm.intraBlockState.CreateAccount(addr, false) }Everything else from #19277 is preserved: the zero-value
CanTransferskip,TouchAccount(caller)instead ofTransferfor syscalls, and theintra_block_state.gorefactor.Validation
Local:
cancun/eip4788_beacon_root/*— all pass (8.5s)cancuneest_blockchain suite — pass (167s)pragueeest_blockchain suite — pass (85s)TestSystemCallZeroValueSkipsTransferChecks— pass (still green)execution/state+execution/stagedsyncunit tests — passmake lint— cleanTest plan
race-tests / execution-eest-blockchainturns green thereRelated
🤖 Generated with Claude Code