From c08d4ff4a6b7aeff9341b6bfe51eb7d08b874dcf Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Fri, 7 Feb 2025 14:52:29 +0800 Subject: [PATCH] core/state, core/vm: implement EIP 6780 (#27189) --- core/state/state_object.go | 3 +++ core/state/statedb.go | 15 +++++++++++++++ core/vm/eips.go | 12 ++++++++++++ core/vm/instructions.go | 16 ++++++++++++++++ core/vm/interface.go | 2 ++ core/vm/jump_table.go | 1 + 6 files changed, 49 insertions(+) diff --git a/core/state/state_object.go b/core/state/state_object.go index 2d28af7edec2..9e8fe8f86912 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -93,6 +93,9 @@ type stateObject struct { // the end of transaction and no longer accessible anymore. deleted bool + // Flag whether the object was created in the current transaction + created bool + touched bool onDirty func(addr common.Address) // Callback method to mark a state object newly dirty diff --git a/core/state/statedb.go b/core/state/statedb.go index 9003f58fdeca..4c2a2cd3ec19 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -420,6 +420,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. @@ -547,6 +558,9 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) } else { s.journal = append(s.journal, resetObjectChange{prev: prev}) } + + newobj.created = true + s.setStateObject(newobj) return newobj, prev } @@ -683,6 +697,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { stateObject.updateRoot(s.db) s.updateStateObject(stateObject) } + stateObject.created = false } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() diff --git a/core/vm/eips.go b/core/vm/eips.go index 55552c2a7364..99b25c52526d 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -26,6 +26,7 @@ import ( var activators = map[int]func(*JumpTable){ 5656: enable5656, + 6780: enable6780, 3855: enable3855, 3860: enable3860, 3529: enable3529, @@ -254,3 +255,14 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by scope.Memory.Copy(dst.Uint64(), src.Uint64(), length.Uint64()) return nil, nil } + +// 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 a67b8b657172..79f191307859 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -843,6 +843,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 105be10b71c6..a89d33c34d72 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 4966181053fd..3797b01cac80 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -84,6 +84,7 @@ func newCancunInstructionSet() JumpTable { instructionSet := newEip1559InstructionSet() enable1153(&instructionSet) // EIP-1153 "Transient Storage" enable5656(&instructionSet) // EIP-5656 (MCOPY opcode) + enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction return validate(instructionSet) }