core/vm: reject contract creation if the storage is non-empty (#28912)

This change implements EIP-7610, which rejects the contract deployment if the destination has non-empty storage.
This commit is contained in:
rjl493456442 2024-04-08 21:48:37 +08:00 committed by GitHub
parent 3c75c64e6b
commit c170cc0ab0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 3 deletions

View File

@ -439,13 +439,19 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if evm.chainRules.IsBerlin { if evm.chainRules.IsBerlin {
evm.StateDB.AddAddressToAccessList(address) evm.StateDB.AddAddressToAccessList(address)
} }
// Ensure there's no existing contract already at the designated address // Ensure there's no existing contract already at the designated address.
// Account is regarded as existent if any of these three conditions is met:
// - the nonce is nonzero
// - the code is non-empty
// - the storage is non-empty
contractHash := evm.StateDB.GetCodeHash(address) contractHash := evm.StateDB.GetCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { storageRoot := evm.StateDB.GetStorageRoot(address)
if evm.StateDB.GetNonce(address) != 0 ||
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
(storageRoot != (common.Hash{}) && storageRoot != types.EmptyRootHash) { // non-empty storage
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
} }
return nil, common.Address{}, 0, ErrContractAddressCollision return nil, common.Address{}, 0, ErrContractAddressCollision
} }
// Create a new account on the state // Create a new account on the state

View File

@ -49,6 +49,7 @@ type StateDB interface {
GetCommittedState(common.Address, common.Hash) common.Hash GetCommittedState(common.Address, common.Hash) common.Hash
GetState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash) SetState(common.Address, common.Hash, common.Hash)
GetStorageRoot(addr common.Address) common.Hash
GetTransientState(addr common.Address, key common.Hash) common.Hash GetTransientState(addr common.Address, key common.Hash) common.Hash
SetTransientState(addr common.Address, key, value common.Hash) SetTransientState(addr common.Address, key, value common.Hash)

View File

@ -64,6 +64,14 @@ func TestExecutionSpecBlocktests(t *testing.T) {
} }
bt := new(testMatcher) bt := new(testMatcher)
// These tests fail as of https://github.com/ethereum/go-ethereum/pull/28666, since we
// no longer delete "leftover storage" when deploying a contract.
bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/self_destructing_initcode_create_tx.json`)
bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/self_destructing_initcode.json`)
bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/recreate_self_destructed_contract_different_txs.json`)
bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/delegatecall_from_new_contract_to_pre_existing_contract.json`)
bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/create_selfdestruct_same_tx.json`)
bt.walk(t, executionSpecBlockchainTestDir, func(t *testing.T, name string, test *BlockTest) { bt.walk(t, executionSpecBlockchainTestDir, func(t *testing.T, name string, test *BlockTest) {
execBlockTest(t, bt, test) execBlockTest(t, bt, test)
}) })

View File

@ -54,9 +54,22 @@ func initMatcher(st *testMatcher) {
// Uses 1GB RAM per tested fork // Uses 1GB RAM per tested fork
st.skipLoad(`^stStaticCall/static_Call1MB`) st.skipLoad(`^stStaticCall/static_Call1MB`)
// These tests fail as of https://github.com/ethereum/go-ethereum/pull/28666, since we
// no longer delete "leftover storage" when deploying a contract.
st.skipLoad(`^stSStoreTest/InitCollision\.json`)
st.skipLoad(`^stRevertTest/RevertInCreateInInit\.json`)
st.skipLoad(`^stExtCodeHash/dynamicAccountOverwriteEmpty\.json`)
st.skipLoad(`^stCreate2/create2collisionStorage\.json`)
st.skipLoad(`^stCreate2/RevertInCreateInInitCreate2\.json`)
// Broken tests: // Broken tests:
// EOF is not part of cancun // EOF is not part of cancun
st.skipLoad(`^stEOF/`) st.skipLoad(`^stEOF/`)
// The tests under Pyspecs are the ones that are published as execution-spec tests.
// We run these tests separately, no need to _also_ run them as part of the
// reference tests.
st.skipLoad(`^Pyspecs/`)
} }
func TestState(t *testing.T) { func TestState(t *testing.T) {