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 package misc
import ( import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing" "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/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -29,12 +28,10 @@ import (
// CREATE2 factory that, once present at the canonical address on every EVM chain, // CREATE2 factory that, once present at the canonical address on every EVM chain,
// allows contracts to be deployed at identical addresses across chains. // allows contracts to be deployed at identical addresses across chains.
func ApplyEIP7997(statedb vm.StateDB) { func ApplyEIP7997(statedb vm.StateDB) {
contractHash := statedb.GetCodeHash(params.DeterministicFactoryAddress) // The account must hold the canonical factory runtime code. If its code hash
nonce := statedb.GetNonce(params.DeterministicFactoryAddress) // already matches, the chain satisfies EIP-7997 and nothing needs to change.
wantHash := crypto.Keccak256Hash(params.DeterministicFactoryCode)
// Reject the irregular state transition if the destination doesn't if statedb.GetCodeHash(params.DeterministicFactoryAddress) == wantHash {
// satisfy the deployment condition.
if nonce != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
return return
} }
if !statedb.Exist(params.DeterministicFactoryAddress) { if !statedb.Exist(params.DeterministicFactoryAddress) {
@ -42,5 +39,9 @@ func ApplyEIP7997(statedb vm.StateDB) {
} }
statedb.CreateContract(params.DeterministicFactoryAddress) statedb.CreateContract(params.DeterministicFactoryAddress)
statedb.SetCode(params.DeterministicFactoryAddress, params.DeterministicFactoryCode, tracing.CodeChangeUnspecified) statedb.SetCode(params.DeterministicFactoryAddress, params.DeterministicFactoryCode, tracing.CodeChangeUnspecified)
// 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) 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 // TestEIP7997FactoryDeploys exercises the inserted factory bytecode: calling it
// with a salt followed by init code must CREATE2-deploy the contract at the // with a salt followed by init code must CREATE2-deploy the contract at the
// canonical deterministic address and return that address (20 bytes, unpadded). // canonical deterministic address and return that address (20 bytes, unpadded).