core, consensus: update irregular state transition

This commit is contained in:
Gary Rong 2026-07-02 14:19:57 +08:00
parent 5fecc3facb
commit 867efad997
2 changed files with 27 additions and 9 deletions

View file

@ -17,10 +17,9 @@
package misc
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
@ -29,12 +28,10 @@ import (
// CREATE2 factory that, once present at the canonical address on every EVM chain,
// allows contracts to be deployed at identical addresses across chains.
func ApplyEIP7997(statedb vm.StateDB) {
contractHash := statedb.GetCodeHash(params.DeterministicFactoryAddress)
nonce := statedb.GetNonce(params.DeterministicFactoryAddress)
// Reject the irregular state transition if the destination doesn't
// satisfy the deployment condition.
if nonce != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
// The account must hold the canonical factory runtime code. If its code hash
// already matches, the chain satisfies EIP-7997 and nothing needs to change.
wantHash := crypto.Keccak256Hash(params.DeterministicFactoryCode)
if statedb.GetCodeHash(params.DeterministicFactoryAddress) == wantHash {
return
}
if !statedb.Exist(params.DeterministicFactoryAddress) {
@ -42,5 +39,9 @@ func ApplyEIP7997(statedb vm.StateDB) {
}
statedb.CreateContract(params.DeterministicFactoryAddress)
statedb.SetCode(params.DeterministicFactoryAddress, params.DeterministicFactoryCode, tracing.CodeChangeUnspecified)
statedb.SetNonce(params.DeterministicFactoryAddress, 1, tracing.NonceChangeNewContract)
// Preserve a pre-existing nonce; only bump the default zero nonce to 1.
if statedb.GetNonce(params.DeterministicFactoryAddress) == 0 {
statedb.SetNonce(params.DeterministicFactoryAddress, 1, tracing.NonceChangeNewContract)
}
}

View file

@ -60,6 +60,23 @@ func TestApplyEIP7997Existing(t *testing.T) {
}
}
// TestApplyEIP7997WrongCode checks that an account occupying the factory address
// with the wrong code is force-overwritten with the canonical runtime code, while
// a pre-existing non-zero nonce is preserved.
func TestApplyEIP7997WrongCode(t *testing.T) {
sdb := mkState(types.GenesisAlloc{
params.DeterministicFactoryAddress: {Code: []byte{0x60, 0x00}, Nonce: 7},
})
misc.ApplyEIP7997(sdb)
if got := sdb.GetCode(params.DeterministicFactoryAddress); !bytes.Equal(got, params.DeterministicFactoryCode) {
t.Fatalf("factory code not overwritten:\n got %x\nwant %x", got, params.DeterministicFactoryCode)
}
if got := sdb.GetNonce(params.DeterministicFactoryAddress); got != 7 {
t.Fatalf("factory nonce = %d, want %d (existing nonce must be preserved)", got, 7)
}
}
// TestEIP7997FactoryDeploys exercises the inserted factory bytecode: calling it
// with a salt followed by init code must CREATE2-deploy the contract at the
// canonical deterministic address and return that address (20 bytes, unpadded).