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:
parent
3c75c64e6b
commit
c170cc0ab0
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue