From 876a66cdfd91a6c34892ca85854a4a0b48c02215 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 17 Jul 2023 19:02:18 +0200 Subject: [PATCH] core/state, core/vm: implement EIP 6780 (#27189) EIP-6780: SELFDESTRUCT only in same transaction > SELFDESTRUCT will recover all funds to the caller but not delete the account, except when called in the same transaction as creation --------- Co-authored-by: Martin Holst Swende --- 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 | 2 ++ 6 files changed, 50 insertions(+) diff --git a/core/state/state_object.go b/core/state/state_object.go index ed5f2b2945403..6fea47f05b0e6 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 4b17e70255e04..fdcc76310f4f0 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 0daa122ca0505..704c1ce127451 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 4b6514ec8c328..2105201fce428 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 05fb480f968c8..26814d3d2f0e6 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 a59fa8747323a..702b18661545b 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) }