mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
core/state, core/vm: define set destructible
This commit is contained in:
parent
d68fda5997
commit
2e079b3f03
7 changed files with 66 additions and 27 deletions
|
|
@ -128,6 +128,9 @@ type (
|
||||||
account *common.Address
|
account *common.Address
|
||||||
prevcode, prevhash []byte
|
prevcode, prevhash []byte
|
||||||
}
|
}
|
||||||
|
destructibleChange struct {
|
||||||
|
account common.Address
|
||||||
|
}
|
||||||
|
|
||||||
// Changes to other state values.
|
// Changes to other state values.
|
||||||
refundChange struct {
|
refundChange struct {
|
||||||
|
|
@ -254,6 +257,20 @@ func (ch codeChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ch destructibleChange) revert(s *StateDB) {
|
||||||
|
s.getStateObject(ch.account).destructible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch destructibleChange) dirtied() *common.Address {
|
||||||
|
return nil // destruct-eligible flag is not considered as dirty
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch destructibleChange) copy() journalEntry {
|
||||||
|
return destructibleChange{
|
||||||
|
account: ch.account,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ch storageChange) revert(s *StateDB) {
|
func (ch storageChange) revert(s *StateDB) {
|
||||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ type stateObject struct {
|
||||||
trie Trie // storage trie, which becomes non-nil on first access
|
trie Trie // storage trie, which becomes non-nil on first access
|
||||||
code []byte // contract bytecode, which gets set when code is loaded
|
code []byte // contract bytecode, which gets set when code is loaded
|
||||||
|
|
||||||
originStorage Storage // Storage cache of original entries to dedup rewrites
|
originStorage Storage // Storage cache of original entries to de-duplicate rewrites
|
||||||
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
|
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
|
||||||
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction
|
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction
|
||||||
|
|
||||||
|
|
@ -66,8 +66,11 @@ type stateObject struct {
|
||||||
// account is still accessible in the scope of same transaction.
|
// account is still accessible in the scope of same transaction.
|
||||||
selfDestructed bool
|
selfDestructed bool
|
||||||
|
|
||||||
// Flag whether the object was created in the current transaction
|
// This is an EIP-6780 flag indicating if the object is eligible for
|
||||||
created bool
|
// self-destruct. Potential scenarios as follows:
|
||||||
|
// - object is created in the current transaction
|
||||||
|
// - object was previously existent and is being deployed in current transaction
|
||||||
|
destructible bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty returns whether the account is considered empty.
|
// empty returns whether the account is considered empty.
|
||||||
|
|
@ -77,10 +80,6 @@ func (s *stateObject) empty() bool {
|
||||||
|
|
||||||
// newObject creates a state object.
|
// newObject creates a state object.
|
||||||
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
|
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
|
||||||
var (
|
|
||||||
origin = acct
|
|
||||||
created = acct == nil // true if the account was not existent
|
|
||||||
)
|
|
||||||
if acct == nil {
|
if acct == nil {
|
||||||
acct = types.NewEmptyStateAccount()
|
acct = types.NewEmptyStateAccount()
|
||||||
}
|
}
|
||||||
|
|
@ -88,12 +87,11 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
|
||||||
db: db,
|
db: db,
|
||||||
address: address,
|
address: address,
|
||||||
addrHash: crypto.Keccak256Hash(address[:]),
|
addrHash: crypto.Keccak256Hash(address[:]),
|
||||||
origin: origin,
|
origin: acct,
|
||||||
data: *acct,
|
data: *acct,
|
||||||
originStorage: make(Storage),
|
originStorage: make(Storage),
|
||||||
pendingStorage: make(Storage),
|
pendingStorage: make(Storage),
|
||||||
dirtyStorage: make(Storage),
|
dirtyStorage: make(Storage),
|
||||||
created: created,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,6 +244,7 @@ func (s *stateObject) finalise(prefetch bool) {
|
||||||
if len(s.dirtyStorage) > 0 {
|
if len(s.dirtyStorage) > 0 {
|
||||||
s.dirtyStorage = make(Storage)
|
s.dirtyStorage = make(Storage)
|
||||||
}
|
}
|
||||||
|
s.destructible = false // unset the flag at the end of transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateTrie is responsible for persisting cached storage changes into the
|
// updateTrie is responsible for persisting cached storage changes into the
|
||||||
|
|
@ -450,7 +449,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
||||||
obj.dirtyStorage = s.dirtyStorage.Copy()
|
obj.dirtyStorage = s.dirtyStorage.Copy()
|
||||||
obj.dirtyCode = s.dirtyCode
|
obj.dirtyCode = s.dirtyCode
|
||||||
obj.selfDestructed = s.selfDestructed
|
obj.selfDestructed = s.selfDestructed
|
||||||
obj.created = s.created
|
obj.destructible = s.destructible
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -530,6 +529,16 @@ func (s *stateObject) setNonce(nonce uint64) {
|
||||||
s.data.Nonce = nonce
|
s.data.Nonce = nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stateObject) SetDestructible() {
|
||||||
|
if s.destructible {
|
||||||
|
return // might be possible in fuzzing
|
||||||
|
}
|
||||||
|
s.db.journal.append(destructibleChange{
|
||||||
|
account: s.address,
|
||||||
|
})
|
||||||
|
s.destructible = true
|
||||||
|
}
|
||||||
|
|
||||||
func (s *stateObject) CodeHash() []byte {
|
func (s *stateObject) CodeHash() []byte {
|
||||||
return s.data.CodeHash
|
return s.data.CodeHash
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -497,7 +497,7 @@ func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if stateObject.created {
|
if stateObject.destructible {
|
||||||
s.SelfDestruct(addr)
|
s.SelfDestruct(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -659,7 +659,17 @@ func (s *StateDB) createObject(addr common.Address) *stateObject {
|
||||||
// exists, this function will silently overwrite it which might lead to a
|
// exists, this function will silently overwrite it which might lead to a
|
||||||
// consensus bug eventually.
|
// consensus bug eventually.
|
||||||
func (s *StateDB) CreateAccount(addr common.Address) {
|
func (s *StateDB) CreateAccount(addr common.Address) {
|
||||||
s.createObject(addr)
|
obj := s.createObject(addr)
|
||||||
|
obj.SetDestructible()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDestructible marks the object with specific address as destructible.
|
||||||
|
func (s *StateDB) SetDestructible(addr common.Address) {
|
||||||
|
obj := s.getStateObject(addr)
|
||||||
|
if obj == nil {
|
||||||
|
return // might be possible in fuzzing
|
||||||
|
}
|
||||||
|
obj.SetDestructible()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy creates a deep, independent copy of the state.
|
// Copy creates a deep, independent copy of the state.
|
||||||
|
|
@ -808,7 +818,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||||
delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect)
|
delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect)
|
||||||
delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect)
|
delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect)
|
||||||
} else {
|
} else {
|
||||||
obj.created = false
|
|
||||||
obj.finalise(true) // Prefetch slots in the background
|
obj.finalise(true) // Prefetch slots in the background
|
||||||
s.markUpdate(addr)
|
s.markUpdate(addr)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,18 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||||
s.SelfDestruct(addr)
|
s.SelfDestruct(addr)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "SelfDestruct6780",
|
||||||
|
fn: func(a testAction, s *StateDB) {
|
||||||
|
s.Selfdestruct6780(addr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SetDestructible",
|
||||||
|
fn: func(a testAction, s *StateDB) {
|
||||||
|
s.SetDestructible(addr)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "AddRefund",
|
name: "AddRefund",
|
||||||
fn: func(a testAction, s *StateDB) {
|
fn: func(a testAction, s *StateDB) {
|
||||||
|
|
|
||||||
|
|
@ -461,6 +461,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
snapshot := evm.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
if !evm.StateDB.Exist(address) {
|
if !evm.StateDB.Exist(address) {
|
||||||
evm.StateDB.CreateAccount(address)
|
evm.StateDB.CreateAccount(address)
|
||||||
|
} else {
|
||||||
|
// The account with the designated address previously existed but is
|
||||||
|
// still eligible for deployment. Explicitly set it as destructible
|
||||||
|
// to adhere to EIP-6780.
|
||||||
|
evm.StateDB.SetDestructible(address)
|
||||||
}
|
}
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
evm.StateDB.SetNonce(address, 1)
|
evm.StateDB.SetNonce(address, 1)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ type StateDB interface {
|
||||||
|
|
||||||
SelfDestruct(common.Address)
|
SelfDestruct(common.Address)
|
||||||
HasSelfDestructed(common.Address) bool
|
HasSelfDestructed(common.Address) bool
|
||||||
|
SetDestructible(addr common.Address)
|
||||||
|
|
||||||
Selfdestruct6780(common.Address)
|
Selfdestruct6780(common.Address)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,6 @@ func TestBlockchain(t *testing.T) {
|
||||||
// using 4.6 TGas
|
// using 4.6 TGas
|
||||||
bt.skipLoad(`.*randomStatetest94.json.*`)
|
bt.skipLoad(`.*randomStatetest94.json.*`)
|
||||||
|
|
||||||
// The tests under Pyspecs are the ones that are published as execution-spect tests.
|
|
||||||
// We run these tests separately, no need to _also_ run them as part of the
|
|
||||||
// reference tests.
|
|
||||||
bt.skipLoad(`^Pyspecs/`)
|
|
||||||
|
|
||||||
bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
|
bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
|
||||||
execBlockTest(t, bt, test)
|
execBlockTest(t, bt, test)
|
||||||
})
|
})
|
||||||
|
|
@ -68,15 +63,6 @@ func TestExecutionSpecBlocktests(t *testing.T) {
|
||||||
t.Skipf("directory %s does not exist", executionSpecBlockchainTestDir)
|
t.Skipf("directory %s does not exist", executionSpecBlockchainTestDir)
|
||||||
}
|
}
|
||||||
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)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue