Skip to content

Commit 9a6a884

Browse files
committed
fix selfdestruct hooks
1 parent 7c107c2 commit 9a6a884

File tree

5 files changed

+54
-11
lines changed

5 files changed

+54
-11
lines changed

core/state/statedb.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,13 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
419419
return false
420420
}
421421

422+
// ExistBeforeCurTx returns true if a contract exists and was not created
423+
// in the current transaction.
424+
func (s *StateDB) ExistBeforeCurTx(addr common.Address) bool {
425+
obj := s.getStateObject(addr)
426+
return obj != nil && !obj.newContract
427+
}
428+
422429
/*
423430
* SETTERS
424431
*/

core/state/statedb_hooked.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,32 @@ func (s *hookedStateDB) AddLog(log *types.Log) {
277277

278278
func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) {
279279
defer s.inner.Finalise(deleteEmptyObjects)
280-
if s.hooks.OnBalanceChange == nil {
281-
return
282-
}
283-
for addr := range s.inner.journal.dirties {
284-
obj := s.inner.stateObjects[addr]
285-
if obj != nil && obj.selfDestructed {
286-
// If ether was sent to account post-selfdestruct it is burnt.
287-
if bal := obj.Balance(); bal.Sign() != 0 {
288-
s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
280+
if s.hooks.OnBalanceChange != nil || s.hooks.OnNonceChangeV2 != nil || s.hooks.OnCodeChangeV2 != nil || s.hooks.OnCodeChange != nil {
281+
for addr := range s.inner.journal.dirties {
282+
obj := s.inner.stateObjects[addr]
283+
if obj != nil && obj.selfDestructed {
284+
// If ether was sent to account post-selfdestruct it is burnt.
285+
if s.hooks.OnBalanceChange != nil {
286+
if bal := obj.Balance(); bal.Sign() != 0 {
287+
s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
288+
}
289+
}
290+
if s.hooks.OnNonceChangeV2 != nil {
291+
prevNonce := obj.Nonce()
292+
s.hooks.OnNonceChangeV2(addr, prevNonce, 0, tracing.NonceChangeSelfdestruct)
293+
}
294+
prevCodeHash := s.inner.GetCodeHash(addr)
295+
prevCode := s.inner.GetCode(addr)
296+
297+
// if an initcode invokes selfdestruct, do not emit a code change.
298+
if prevCodeHash == types.EmptyCodeHash {
299+
continue
300+
}
301+
if s.hooks.OnCodeChangeV2 != nil {
302+
s.hooks.OnCodeChangeV2(addr, prevCodeHash, prevCode, types.EmptyCodeHash, nil, tracing.CodeChangeSelfDestruct)
303+
} else if s.hooks.OnCodeChange != nil {
304+
s.hooks.OnCodeChange(addr, prevCodeHash, prevCode, types.EmptyCodeHash, nil)
305+
}
289306
}
290307
}
291308
}

core/tracing/hooks.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ const (
375375
// NonceChangeRevert is emitted when the nonce is reverted back to a previous value due to call failure.
376376
// It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
377377
NonceChangeRevert NonceChangeReason = 6
378+
379+
// NonceChangeSelfdestruct is emitted when the nonce is reset to zero due to a self-destruct
380+
NonceChangeSelfdestruct NonceChangeReason = 7
378381
)
379382

380383
// CodeChangeReason is used to indicate the reason for a code change.

core/vm/instructions.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -906,8 +906,21 @@ func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, erro
906906
}
907907
beneficiary := scope.Stack.pop()
908908
balance := evm.StateDB.GetBalance(scope.Contract.Address())
909-
evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
910-
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
909+
createdInTx := !evm.StateDB.ExistBeforeCurTx(scope.Contract.Address())
910+
911+
if createdInTx {
912+
// if the contract is not preexisting, the balance is immediately burned on selfdestruct-to-self
913+
evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
914+
if scope.Contract.Address() != common.BytesToAddress(beneficiary.Bytes()) {
915+
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
916+
}
917+
} else {
918+
// if the contract is preexisting, the balance isn't burned on selfdestruct-to-self
919+
if scope.Contract.Address() != common.BytesToAddress(beneficiary.Bytes()) {
920+
evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
921+
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
922+
}
923+
}
911924
evm.StateDB.SelfDestruct6780(scope.Contract.Address())
912925
if tracer := evm.Config.Tracer; tracer != nil {
913926
if tracer.OnEnter != nil {

core/vm/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ type StateDB interface {
7171
// Exist reports whether the given account exists in state.
7272
// Notably this also returns true for self-destructed accounts within the current transaction.
7373
Exist(common.Address) bool
74+
// ExistBeforeCurTx returns true if a contract exists and was not created
75+
// in the current transaction.
76+
ExistBeforeCurTx(addr common.Address) bool
7477
// Empty returns whether the given account is empty. Empty
7578
// is defined according to EIP161 (balance = nonce = code = 0).
7679
Empty(common.Address) bool

0 commit comments

Comments
 (0)