core: replace suicide with selfdestruct to improve code consistency (#27716)

This commit is contained in:
Daniel Liu 2025-01-14 10:56:15 +08:00
parent 80967d52f6
commit 0f737b4725
12 changed files with 55 additions and 51 deletions

View file

@ -89,7 +89,7 @@ func (t *TradingStateDB) Error() error {
} }
// Exist reports whether the given orderId address exists in the state. // Exist reports whether the given orderId address exists in the state.
// Notably this also returns true for suicided exchanges. // Notably this also returns true for self-destructed exchanges.
func (t *TradingStateDB) Exist(addr common.Hash) bool { func (t *TradingStateDB) Exist(addr common.Hash) bool {
return t.getStateExchangeObject(addr) != nil return t.getStateExchangeObject(addr) != nil
} }

View file

@ -84,7 +84,7 @@ func (ls *LendingStateDB) Error() error {
} }
// Exist reports whether the given tradeId address exists in the state. // Exist reports whether the given tradeId address exists in the state.
// Notably this also returns true for suicided lenddinges. // Notably this also returns true for self-destructed lenddinges.
func (ls *LendingStateDB) Exist(addr common.Hash) bool { func (ls *LendingStateDB) Exist(addr common.Hash) bool {
return ls.getLendingExchange(addr) != nil return ls.getLendingExchange(addr) != nil
} }

View file

@ -29,7 +29,7 @@ import (
var ( var (
// ErrNoCode is returned by call and transact operations for which the requested // ErrNoCode is returned by call and transact operations for which the requested
// recipient contract to operate on does not exist in the state db or does not // recipient contract to operate on does not exist in the state db or does not
// have any code associated with it (i.e. suicided). // have any code associated with it (i.e. self-destructed).
ErrNoCode = errors.New("no contract code at given address") ErrNoCode = errors.New("no contract code at given address")
// ErrNoPendingState is raised when attempting to perform a pending state action // ErrNoPendingState is raised when attempting to perform a pending state action

View file

@ -41,9 +41,9 @@ type (
resetObjectChange struct { resetObjectChange struct {
prev *stateObject prev *stateObject
} }
suicideChange struct { selfDestructChange struct {
account *common.Address account *common.Address
prev bool // whether account had already suicided prev bool // whether account had already self-destructed
prevbalance *big.Int prevbalance *big.Int
} }
@ -104,10 +104,10 @@ func (ch resetObjectChange) undo(s *StateDB) {
s.setStateObject(ch.prev) s.setStateObject(ch.prev)
} }
func (ch suicideChange) undo(s *StateDB) { func (ch selfDestructChange) undo(s *StateDB) {
obj := s.getStateObject(*ch.account) obj := s.getStateObject(*ch.account)
if obj != nil { if obj != nil {
obj.suicided = ch.prev obj.selfDestructed = ch.prev
obj.setBalance(ch.prevbalance) obj.setBalance(ch.prevbalance)
} }
} }

View file

@ -61,10 +61,10 @@ func (s Storage) Copy() Storage {
// Account values can be accessed and modified through the object. // Account values can be accessed and modified through the object.
// Finally, call CommitTrie to write the modified storage trie into a database. // Finally, call CommitTrie to write the modified storage trie into a database.
type stateObject struct { type stateObject struct {
address common.Address
addrHash common.Hash // hash of ethereum address of the account
data Account
db *StateDB db *StateDB
address common.Address // address of ethereum account
addrHash common.Hash // hash of ethereum address of the account
data Account // Account data with all mutations applied in the scope of block
// DB error. // DB error.
// State objects are used by the consensus core and VM which are // State objects are used by the consensus core and VM which are
@ -82,13 +82,20 @@ type stateObject struct {
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose. fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
// Cache flags. // Cache flags.
// When an object is marked suicided it will be delete from the trie
// during the "update" phase of the state transition.
dirtyCode bool // true if the code was updated dirtyCode bool // true if the code was updated
suicided bool
touched bool // Flag whether the account was marked as self-destructed. The self-destructed
deleted bool // account is still accessible in the scope of same transaction.
onDirty func(addr common.Address) // Callback method to mark a state object newly dirty selfDestructed bool
// Flag whether the account was marked as deleted. A self-destructed account
// or an account that is considered as empty will be marked as deleted at
// the end of transaction and no longer accessible anymore.
deleted bool
touched bool
onDirty func(addr common.Address) // Callback method to mark a state object newly dirty
} }
// empty returns whether the account is considered empty. // empty returns whether the account is considered empty.
@ -136,8 +143,8 @@ func (s *stateObject) setError(err error) {
} }
} }
func (s *stateObject) markSuicided() { func (s *stateObject) markSelfdestructed() {
s.suicided = true s.selfDestructed = true
if s.onDirty != nil { if s.onDirty != nil {
s.onDirty(s.Address()) s.onDirty(s.Address())
s.onDirty = nil s.onDirty = nil
@ -363,7 +370,7 @@ func (s *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *
stateObject.code = s.code stateObject.code = s.code
stateObject.dirtyStorage = s.dirtyStorage.Copy() stateObject.dirtyStorage = s.dirtyStorage.Copy()
stateObject.cachedStorage = s.dirtyStorage.Copy() stateObject.cachedStorage = s.dirtyStorage.Copy()
stateObject.suicided = s.suicided stateObject.selfDestructed = s.selfDestructed
stateObject.dirtyCode = s.dirtyCode stateObject.dirtyCode = s.dirtyCode
stateObject.deleted = s.deleted stateObject.deleted = s.deleted
return stateObject return stateObject

View file

@ -18,11 +18,11 @@ package state
import ( import (
"bytes" "bytes"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big" "math/big"
"testing" "testing"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
checker "gopkg.in/check.v1" checker "gopkg.in/check.v1"
@ -152,7 +152,7 @@ func TestSnapshot2(t *testing.T) {
so0.SetBalance(big.NewInt(42)) so0.SetBalance(big.NewInt(42))
so0.SetNonce(43) so0.SetNonce(43)
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
so0.suicided = false so0.selfDestructed = false
so0.deleted = false so0.deleted = false
state.setStateObject(so0) state.setStateObject(so0)
@ -164,7 +164,7 @@ func TestSnapshot2(t *testing.T) {
so1.SetBalance(big.NewInt(52)) so1.SetBalance(big.NewInt(52))
so1.SetNonce(53) so1.SetNonce(53)
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
so1.suicided = true so1.selfDestructed = true
so1.deleted = true so1.deleted = true
state.setStateObject(so1) state.setStateObject(so1)
@ -224,8 +224,8 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
} }
} }
if so0.suicided != so1.suicided { if so0.selfDestructed != so1.selfDestructed {
t.Fatalf("suicided mismatch: have %v, want %v", so0.suicided, so1.suicided) t.Fatalf("self-destructed mismatch: have %v, want %v", so0.selfDestructed, so1.selfDestructed)
} }
if so0.deleted != so1.deleted { if so0.deleted != so1.deleted {
t.Fatalf("Deleted mismatch: have %v, want %v", so0.deleted, so1.deleted) t.Fatalf("Deleted mismatch: have %v, want %v", so0.deleted, so1.deleted)

View file

@ -214,7 +214,7 @@ func (s *StateDB) AddRefund(gas uint64) {
} }
// Exist reports whether the given account address exists in the state. // Exist reports whether the given account address exists in the state.
// Notably this also returns true for suicided accounts. // Notably this also returns true for self-destructed accounts.
func (s *StateDB) Exist(addr common.Address) bool { func (s *StateDB) Exist(addr common.Address) bool {
return s.getStateObject(addr) != nil return s.getStateObject(addr) != nil
} }
@ -336,10 +336,10 @@ func (s *StateDB) StorageTrie(addr common.Address) Trie {
return cpy.updateTrie(s.db) return cpy.updateTrie(s.db)
} }
func (s *StateDB) HasSuicided(addr common.Address) bool { func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.suicided return stateObject.selfDestructed
} }
return false return false
} }
@ -401,25 +401,23 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
} }
} }
// Suicide marks the given account as suicided. // SelfDestruct marks the given account as selfdestructed.
// This clears the account balance. // This clears the account balance.
// //
// The account's state object is still available until the state is committed, // The account's state object is still available until the state is committed,
// getStateObject will return a non-nil account after Suicide. // getStateObject will return a non-nil account after SelfDestruct.
func (s *StateDB) Suicide(addr common.Address) bool { func (s *StateDB) SelfDestruct(addr common.Address) {
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
return false return
} }
s.journal = append(s.journal, suicideChange{ s.journal = append(s.journal, selfDestructChange{
account: &addr, account: &addr,
prev: stateObject.suicided, prev: stateObject.selfDestructed,
prevbalance: new(big.Int).Set(stateObject.Balance()), prevbalance: new(big.Int).Set(stateObject.Balance()),
}) })
stateObject.markSuicided() stateObject.markSelfdestructed()
stateObject.data.Balance = new(big.Int) stateObject.data.Balance = new(big.Int)
return true
} }
// SetTransientState sets transient storage for a given account. It // SetTransientState sets transient storage for a given account. It
@ -679,7 +677,7 @@ func (s *StateDB) GetRefund() uint64 {
func (s *StateDB) Finalise(deleteEmptyObjects bool) { func (s *StateDB) Finalise(deleteEmptyObjects bool) {
for addr := range s.stateObjectsDirty { for addr := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr] stateObject := s.stateObjects[addr]
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { if stateObject.selfDestructed || (deleteEmptyObjects && stateObject.empty()) {
s.deleteStateObject(stateObject) s.deleteStateObject(stateObject)
} else { } else {
stateObject.updateRoot(s.db) stateObject.updateRoot(s.db)
@ -710,7 +708,7 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
s.txIndex = ti s.txIndex = ti
} }
// DeleteSuicides flags the suicided objects for deletion so that it // DeleteSuicides flags the self-destructed objects for deletion so that it
// won't be referenced again when called / queried up on. // won't be referenced again when called / queried up on.
// //
// DeleteSuicides should not be used for consensus related updates // DeleteSuicides should not be used for consensus related updates
@ -724,7 +722,7 @@ func (s *StateDB) DeleteSuicides() {
// If the object has been removed by a suicide // If the object has been removed by a suicide
// flag the object as deleted. // flag the object as deleted.
if stateObject.suicided { if stateObject.selfDestructed {
stateObject.deleted = true stateObject.deleted = true
} }
delete(s.stateObjectsDirty, addr) delete(s.stateObjectsDirty, addr)
@ -745,7 +743,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
for addr, stateObject := range s.stateObjects { for addr, stateObject := range s.stateObjects {
_, isDirty := s.stateObjectsDirty[addr] _, isDirty := s.stateObjectsDirty[addr]
switch { switch {
case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()): case stateObject.selfDestructed || (isDirty && deleteEmptyObjects && stateObject.empty()):
// If the object has been removed, don't bother syncing it // If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie. // and just mark it for deletion in the trie.
s.deleteStateObject(stateObject) s.deleteStateObject(stateObject)

View file

@ -29,7 +29,6 @@ import (
"testing/quick" "testing/quick"
check "gopkg.in/check.v1" check "gopkg.in/check.v1"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
@ -261,9 +260,9 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
}, },
}, },
{ {
name: "Suicide", name: "SelfDestruct",
fn: func(a testAction, s *StateDB) { fn: func(a testAction, s *StateDB) {
s.Suicide(addr) s.SelfDestruct(addr)
}, },
}, },
{ {
@ -405,7 +404,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
} }
// Check basic accessor methods. // Check basic accessor methods.
checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) checkeq("HasSelfDestructed", state.HasSelfDestructed(addr), checkstate.HasSelfDestructed(addr))
checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))

View file

@ -469,7 +469,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
} }
} }
if !evm.StateDB.HasSuicided(contract.Address()) { if !evm.StateDB.HasSelfDestructed(contract.Address()) {
evm.StateDB.AddRefund(params.SelfdestructRefundGas) evm.StateDB.AddRefund(params.SelfdestructRefundGas)
} }
return gas, nil return gas, nil

View file

@ -415,7 +415,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
// If the precompile account is not transferred any amount on a private or // If the precompile account is not transferred any amount on a private or
// customized chain, the return value will be zero. // customized chain, the return value will be zero.
// //
// (5) Caller tries to get the code hash for an account which is marked as suicided // (5) Caller tries to get the code hash for an account which is marked as self-destructed
// //
// in the current transaction, the code hash of this account should be returned. // in the current transaction, the code hash of this account should be returned.
// //
@ -837,7 +837,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
beneficiary := scope.Stack.pop() beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
interpreter.evm.StateDB.Suicide(scope.Contract.Address()) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
if interpreter.evm.Config.Debug { if interpreter.evm.Config.Debug {
interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil) interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil)

View file

@ -51,11 +51,11 @@ type StateDB interface {
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)
Suicide(common.Address) bool SelfDestruct(common.Address)
HasSuicided(common.Address) bool HasSelfDestructed(common.Address) bool
// Exist reports whether the given account exists in state. // Exist reports whether the given account exists in state.
// Notably this should also return true for suicided accounts. // Notably this should also return true for self-destructed accounts.
Exist(common.Address) bool Exist(common.Address) bool
// Empty returns whether the given account is empty. Empty // Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0). // is defined according to EIP161 (balance = nonce = code = 0).

View file

@ -235,7 +235,7 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
gas += params.CreateBySelfdestructGas gas += params.CreateBySelfdestructGas
} }
if refundsEnabled && !evm.StateDB.HasSuicided(contract.Address()) { if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) {
evm.StateDB.AddRefund(params.SelfdestructRefundGas) evm.StateDB.AddRefund(params.SelfdestructRefundGas)
} }
return gas, nil return gas, nil