Skip to content

Commit

Permalink
core/state: only set created flag when CreateContract
Browse files Browse the repository at this point in the history
  • Loading branch information
buddh0 committed Sep 27, 2024
1 parent f6ca7a0 commit c5cc85f
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 6 deletions.
11 changes: 6 additions & 5 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,7 @@ func (s *stateObject) empty() bool {

// newObject creates a state object.
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
var (
origin = acct
created = acct == nil // true if the account was not existent
)
origin := acct
if acct == nil {
acct = types.NewEmptyStateAccount()
}
Expand All @@ -123,7 +120,6 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
originStorage: make(Storage),
pendingStorage: make(Storage),
dirtyStorage: make(Storage),
created: created,
}
}

Expand Down Expand Up @@ -300,6 +296,10 @@ func (s *stateObject) finalise(prefetch bool) {
if len(s.dirtyStorage) > 0 {
s.dirtyStorage = make(Storage)
}
// Revoke the flag at the end of the transaction. It finalizes the status
// of the newly-created object as it's no longer eligible for self-destruct
// by EIP-6780. For non-newly-created objects, it's a no-op.
s.created = false
}

// updateTrie is responsible for persisting cached storage changes into the
Expand Down Expand Up @@ -528,6 +528,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
obj.selfDestructed = s.selfDestructed
obj.dirtyCode = s.dirtyCode
obj.deleted = s.deleted
obj.created = s.created
return obj
}

Expand Down
13 changes: 12 additions & 1 deletion core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,18 @@ func (s *StateDB) CreateAccount(addr common.Address) {
}
}

// CreateContract is used whenever a contract is created. This may be preceded
// by CreateAccount, but that is not required if it already existed in the
// state due to funds sent beforehand.
// This operation sets the 'created'-flag, which is required in order to
// correctly handle EIP-6780 'delete-in-same-transaction' logic.
func (s *StateDB) CreateContract(addr common.Address) {
obj := s.getStateObject(addr)
if !obj.created {
obj.created = true
}
}

// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func (s *StateDB) Copy() *StateDB {
Expand Down Expand Up @@ -1073,7 +1085,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
} else {
obj.finalise(true) // Prefetch slots in the background
}
obj.created = false
s.stateObjectsPending[addr] = struct{}{}
s.stateObjectsDirty[addr] = struct{}{}

Expand Down
20 changes: 20 additions & 0 deletions core/state/statedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,26 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
s.CreateAccount(addr)
},
},
{
name: "CreateContract",
fn: func(a testAction, s *StateDB) {
if !s.Exist(addr) {
s.CreateAccount(addr)
}
contractHash := s.GetCodeHash(addr)
emptyCode := contractHash == (common.Hash{}) || contractHash == types.EmptyCodeHash
storageRoot := s.GetStorageRoot(addr)
emptyStorage := storageRoot == (common.Hash{}) || storageRoot == types.EmptyRootHash
if s.GetNonce(addr) == 0 && emptyCode && emptyStorage {
s.CreateContract(addr)
// We also set some code here, to prevent the
// CreateContract action from being performed twice in a row,
// which would cause a difference in state when unrolling
// the journal.
s.SetCode(addr, []byte{1})
}
},
},
{
name: "SelfDestruct",
fn: func(a testAction, s *StateDB) {
Expand Down
5 changes: 5 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// Create a new account on the state
snapshot := evm.StateDB.Snapshot()
evm.StateDB.CreateAccount(address)
// CreateContract means that regardless of whether the account previously existed
// in the state trie or not, it _now_ becomes created as a _contract_ account.
// This is performed _prior_ to executing the initcode, since the initcode
// acts inside that account.
evm.StateDB.CreateContract(address)
if evm.chainRules.IsEIP158 {
evm.StateDB.SetNonce(address, 1)
}
Expand Down
1 change: 1 addition & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
// StateDB is an EVM database for full state querying.
type StateDB interface {
CreateAccount(common.Address)
CreateContract(common.Address)

SubBalance(common.Address, *uint256.Int)
AddBalance(common.Address, *uint256.Int)
Expand Down

0 comments on commit c5cc85f

Please sign in to comment.