diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 8e37ceb02b..1f016e8fde 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -241,33 +241,7 @@ func (s *hookedStateDB) SelfDestruct(address common.Address) uint256.Int { } func (s *hookedStateDB) SelfDestruct6780(address common.Address) (uint256.Int, bool) { - var prevCode []byte - var prevCodeHash common.Hash - - if s.hooks.OnCodeChange != nil { - prevCodeHash = s.inner.GetCodeHash(address) - prevCode = s.inner.GetCode(address) - } - - prev, changed := s.inner.SelfDestruct6780(address) - - /* - // TODO: figure out if this can be removed (it's redundant with the tracing invocations in core/vm/instructions.go already) - // it's also incorrect if the target/source are the same account - if s.hooks.OnBalanceChange != nil && !prev.IsZero() { - s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct) - } - */ - - if changed && len(prevCode) > 0 { - if s.hooks.OnCodeChangeV2 != nil { - s.hooks.OnCodeChangeV2(address, prevCodeHash, prevCode, types.EmptyCodeHash, nil, tracing.CodeChangeSelfDestruct) - } else if s.hooks.OnCodeChange != nil { - s.hooks.OnCodeChange(address, prevCodeHash, prevCode, types.EmptyCodeHash, nil) - } - } - - return prev, changed + return s.inner.SelfDestruct6780(address) } func (s *hookedStateDB) AddLog(log *types.Log) { @@ -280,13 +254,26 @@ func (s *hookedStateDB) AddLog(log *types.Log) { func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) { defer s.inner.Finalise(deleteEmptyObjects) - if s.hooks.OnBalanceChange != nil { + if s.hooks.OnBalanceChange != nil || s.hooks.OnNonceChangeV2 != nil || s.hooks.OnCodeChangeV2 != nil || s.hooks.OnCodeChange != nil { for addr := range s.inner.journal.dirties { obj := s.inner.stateObjects[addr] if obj != nil && obj.selfDestructed { // If ether was sent to account post-selfdestruct it is burnt. - if bal := obj.Balance(); bal.Sign() != 0 { - s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn) + if s.hooks.OnBalanceChange != nil { + if bal := obj.Balance(); bal.Sign() != 0 { + s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn) + } + } + if s.hooks.OnNonceChangeV2 != nil { + prevNonce := obj.Nonce() + s.hooks.OnNonceChangeV2(addr, prevNonce, 0, tracing.NonceChangeSelfdestruct) + } + prevCodeHash := s.inner.GetCodeHash(addr) + prevCode := s.inner.GetCode(addr) + if s.hooks.OnCodeChangeV2 != nil { + s.hooks.OnCodeChangeV2(addr, prevCodeHash, prevCode, types.EmptyCodeHash, nil, tracing.CodeChangeSelfDestruct) + } else if s.hooks.OnCodeChange != nil { + s.hooks.OnCodeChange(addr, prevCodeHash, prevCode, types.EmptyCodeHash, nil) } } } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 04be780a77..f6bba9965d 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -385,6 +385,9 @@ const ( // NonceChangeRevert is emitted when the nonce is reverted back to a previous value due to call failure. // It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal). NonceChangeRevert NonceChangeReason = 6 + + // NonceChangeSelfdestruct is emitted when the nonce is reset to zero due to a self-destruct + NonceChangeSelfdestruct NonceChangeReason = 7 ) // CodeChangeReason is used to indicate the reason for a code change. diff --git a/core/types/bal/bal.go b/core/types/bal/bal.go index 217231a03f..dbb7b506f7 100644 --- a/core/types/bal/bal.go +++ b/core/types/bal/bal.go @@ -187,7 +187,7 @@ func (a *AccessListBuilder) FinaliseIdxChanges() (*StateDiff, StateAccesses) { access.balance = nil } if access.code != nil && bytes.Equal(access.code, a.prestates[addr].Code) { - if a.prestates[addr].Code != nil { + if a.prestates[addr].Code == nil { createdInTx = true } access.code = nil @@ -207,7 +207,7 @@ func (a *AccessListBuilder) FinaliseIdxChanges() (*StateDiff, StateAccesses) { // two scenarios where an account can become non-existent: // account was created/deleted in the same transaction // account only had balance set (prefunded), was target of create2 initcode which called SENDALL leaving the account empty - if createdInTx && access.code == nil && access.nonce == nil && access.balance == nil { + if createdInTx && access.code == nil { // account was created and self-destructed in the same transaction. // account should be reported as a read in the BAL. Any storage // slots that were read/written are reported as reads.