From 3f562b4bfd93655e8d58e978f896de0251aca4b9 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 15 Feb 2024 13:38:08 -0300 Subject: [PATCH] fix SELFDESTRUCT witness recording Signed-off-by: Ignacio Hagopian --- core/state/statedb.go | 8 ++++++++ core/vm/instructions.go | 16 ++++++++++++++++ core/vm/interface.go | 2 ++ trie/verkle.go | 21 --------------------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 8c395fae2b6b..1b47746458b5 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -530,6 +530,14 @@ func (s *StateDB) Selfdestruct6780(addr common.Address) { } } +func (s *StateDB) WasCreatedInCurrentTx(addr common.Address) bool { + stateObject := s.getStateObject(addr) + if stateObject == nil { + return false + } + return stateObject.created +} + // 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. diff --git a/core/vm/instructions.go b/core/vm/instructions.go index a78ce26c25d5..6c40ff83a272 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -943,6 +943,22 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureExit([]byte{}, 0, nil) } + if interpreter.evm.chainRules.IsPrague { + contractAddr := scope.Contract.Address() + beneficiaryAddr := beneficiary.Bytes20() + // If the beneficiary isn't the contract, we need to touch the beneficiary's balance. + // If the beneficiary is the contract itself, there're two possibilities: + // 1. The contract was created in the same transaction: the balance is already touched (no need to touch again) + // 2. The contract wasn't created in the same transaction: there's no net change in balance, + // and SELFDESTRUCT will perform no action on the account header. (we touch since we did SubBalance+AddBalance above) + if contractAddr != beneficiaryAddr || interpreter.evm.StateDB.WasCreatedInCurrentTx(contractAddr) { + statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(beneficiaryAddr[:], uint256.Int{}, trieUtils.BalanceLeafKey) + if !scope.Contract.UseGas(statelessGas) { + scope.Contract.Gas = 0 + return nil, ErrOutOfGas + } + } + } return nil, errStopToken } diff --git a/core/vm/interface.go b/core/vm/interface.go index 0a02a0181c05..4241b1d45a77 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -57,6 +57,8 @@ type StateDB interface { Selfdestruct6780(common.Address) + WasCreatedInCurrentTx(common.Address) bool + // 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/trie/verkle.go b/trie/verkle.go index 3a402bebe5b6..760e30c8cdaa 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -213,27 +213,6 @@ func (trie *VerkleTrie) UpdateStorage(address common.Address, key, value []byte) } func (t *VerkleTrie) DeleteAccount(addr common.Address) error { - var ( - err error - values = make([][]byte, verkle.NodeWidth) - stem = t.pointCache.GetTreeKeyVersionCached(addr[:]) - ) - - for i := 0; i < verkle.NodeWidth; i++ { - values[i] = zero[:] - } - - switch root := t.root.(type) { - case *verkle.InternalNode: - err = root.InsertValuesAtStem(stem, values, t.FlatdbNodeResolver) - default: - return errInvalidRootType - } - if err != nil { - return fmt.Errorf("DeleteAccount (%x) error: %v", addr, err) - } - // TODO figure out if the code size needs to be updated, too - return nil }