diff --git a/core/state/state_object.go b/core/state/state_object.go index ed5f2b294540..6fea47f05b0e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -86,6 +86,9 @@ type stateObject struct { // 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 + + // Flag whether the object was created in the current transaction + created bool } // empty returns whether the account is considered empty. diff --git a/core/state/statedb.go b/core/state/statedb.go index 4b17e70255e0..fdcc76310f4f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -493,6 +493,17 @@ func (s *StateDB) SelfDestruct(addr common.Address) { stateObject.data.Balance = new(big.Int) } +func (s *StateDB) Selfdestruct6780(addr common.Address) { + stateObject := s.getStateObject(addr) + if stateObject == nil { + return + } + + if stateObject.created { + s.SelfDestruct(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. @@ -681,6 +692,9 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) delete(s.accountsOrigin, prev.addrHash) delete(s.storagesOrigin, prev.addrHash) } + + newobj.created = true + s.setStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev @@ -910,6 +924,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 0daa122ca050..704c1ce12745 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -27,6 +27,7 @@ import ( var activators = map[int]func(*JumpTable){ 5656: enable5656, + 6780: enable6780, 3855: enable3855, 3860: enable3860, 3529: enable3529, @@ -291,3 +292,14 @@ func enable4844(jt *JumpTable) { maxStack: maxStack(1, 1), } } + +// enable6780 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 4b6514ec8c32..2105201fce42 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 05fb480f968c..26814d3d2f0e 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -54,6 +54,8 @@ type StateDB interface { SelfDestruct(common.Address) HasSelfDestructed(common.Address) bool + Selfdestruct6780(common.Address) + // Exist reports whether the given account exists in state. // Notably this should also return true for self-destructed accounts. Exist(common.Address) bool diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index a59fa8747323..702b18661545 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -85,6 +85,7 @@ func newCancunInstructionSet() JumpTable { enable4844(&instructionSet) // EIP-4844 (DATAHASH opcode) enable1153(&instructionSet) // EIP-1153 "Transient Storage" enable5656(&instructionSet) // EIP-5656 (MCOPY opcode) + enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction return validate(instructionSet) } @@ -92,6 +93,7 @@ func newShanghaiInstructionSet() JumpTable { instructionSet := newMergeInstructionSet() enable3855(&instructionSet) // PUSH0 instruction enable3860(&instructionSet) // Limit and meter initcode + return validate(instructionSet) }