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 <martin@swende.se>
This commit is contained in:
jwasinger 2023-07-17 19:02:18 +02:00 committed by GitHub
parent b058cf454b
commit 988d84aa7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 0 deletions

View File

@ -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.

View File

@ -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{}{}

View File

@ -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),
}
}

View File

@ -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

View File

@ -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

View File

@ -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)
}