diff --git a/core/state/state_object.go b/core/state/state_object.go index 606441d2a68ba..1539db14b9468 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -80,6 +80,7 @@ type stateObject struct { dirtyCode bool // true if the code was updated suicided bool deleted bool + created bool // true if the object was created in the current transaction } // empty returns whether the account is considered empty. diff --git a/core/state/statedb.go b/core/state/statedb.go index b1b52cd7f11a1..77babb2d8bc29 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -474,6 +474,17 @@ func (s *StateDB) Suicide(addr common.Address) bool { return true } +func (s *StateDB) Selfdestruct6780(addr common.Address) { + stateObject := s.getStateObject(addr) + if stateObject == nil { + return + } + + if stateObject.created { + s.Suicide(addr) + } +} + // SetTransientState sets transient storage for a given account. It // adds the change to the journal so that it can be rolled back // to its previous value if there is a revert. @@ -656,6 +667,9 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) prevStorage: storage, }) } + + newobj.created = true + s.setStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev @@ -882,6 +896,7 @@ 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{}{} diff --git a/core/vm/eips.go b/core/vm/eips.go index ff1f132cb3551..575b8c2f5a1a1 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -26,6 +26,7 @@ import ( ) var activators = map[int]func(*JumpTable){ + 6780: enable6780, 3855: enable3855, 3860: enable3860, 3529: enable3529, @@ -264,3 +265,14 @@ func enable4844(jt *JumpTable) { maxStack: maxStack(1, 1), } } + +// enable4844 applies EIP-6780 (deactivate SELFDESTRUCT) +func enable6780(jt *JumpTable) { + jt[SELFDESTRUCT] = &operation{ + execute: opSelfdestruct6780, + dynamicGas: gasSelfdestructEIP3529, + constantGas: params.SelfdestructGasEIP150, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + } +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 505aef4127754..ebea3057117f5 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -829,6 +829,22 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext return nil, errStopToken } +func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } + beneficiary := scope.Stack.pop() + balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) + interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) + interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) + if tracer := interpreter.evm.Config.Tracer; tracer != nil { + tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureExit([]byte{}, 0, nil) + } + return nil, errStopToken +} + // following functions are used by the instruction jump table // make log instruction function diff --git a/core/vm/interface.go b/core/vm/interface.go index b83f78307eb79..97442786092d8 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -54,6 +54,8 @@ type StateDB interface { Suicide(common.Address) bool HasSuicided(common.Address) bool + Selfdestruct6780(common.Address) + // Exist reports whether the given account exists in state. // Notably this should also return true for suicided accounts. Exist(common.Address) bool diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 41a89ec6b6790..60509c505edfd 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -83,6 +83,7 @@ func validate(jt JumpTable) JumpTable { func newCancunInstructionSet() JumpTable { instructionSet := newShanghaiInstructionSet() enable4844(&instructionSet) // BLOBHASH opcode + enable6780(&instructionSet) // deactivate SELFDESTRUCT return validate(instructionSet) } @@ -90,6 +91,7 @@ func newShanghaiInstructionSet() JumpTable { instructionSet := newMergeInstructionSet() enable3855(&instructionSet) // PUSH0 instruction enable3860(&instructionSet) // Limit and meter initcode + return validate(instructionSet) } diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go index 0d61b00ede098..2ceb75e732735 100644 --- a/core/vm/jump_table_export.go +++ b/core/vm/jump_table_export.go @@ -29,7 +29,7 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) { case rules.IsPrague: return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet") case rules.IsCancun: - return newShanghaiInstructionSet(), errors.New("cancun-fork not defined yet") + return newCancunInstructionSet(), nil case rules.IsShanghai: return newShanghaiInstructionSet(), nil case rules.IsMerge: