Skip to content

Commit f7fdfa4

Browse files
obscurenkaralabe
authored andcommitted
[release/1.4.7] core/state, eth: Updated suicides objects when tracing transactions
Consensus rules dictate that objects can only be removed during the finalisation of the transaction (i.e. after all calls have finished). Thus calling a suicided contract twice from the same transaction: A->B(S)->ret(A)->B(S) results in 2 suicides. Calling the suicided object twice from two transactions: A->B(S), A->B, results in only one suicide and a call to an empty object. Our current debug tracing functionality replays all transaction that were executed prior to the targetted transaction in order to provide the user with an accurate trace. As a side effect to calling StateDB.IntermediateRoot it also deletes any suicides objects. Our tracing code never calls this function because it isn't interested in the intermediate root. Becasue of this it caused a bug in the tracing code where transactions that were send to priviously deleted objects resulted in two suicides rather than one suicide and a call to an empty object. Fixes #2542 (cherry picked from commit bb3651a)
1 parent 0405f72 commit f7fdfa4

File tree

2 files changed

+22
-0
lines changed

2 files changed

+22
-0
lines changed

core/state/statedb.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,27 @@ func (s *StateDB) IntermediateRoot() common.Hash {
370370
return s.trie.Hash()
371371
}
372372

373+
// DeleteSuicides flags the suicided objects for deletion so that it
374+
// won't be referenced again when called / queried up on.
375+
//
376+
// DeleteSuicides should not be used for consensus related updates
377+
// under any circumstances.
378+
func (s *StateDB) DeleteSuicides() {
379+
// Reset refund so that any used-gas calculations can use
380+
// this method.
381+
s.refund = new(big.Int)
382+
for _, stateObject := range s.stateObjects {
383+
if stateObject.dirty {
384+
// If the object has been removed by a suicide
385+
// flag the object as deleted.
386+
if stateObject.remove {
387+
stateObject.deleted = true
388+
}
389+
stateObject.dirty = false
390+
}
391+
}
392+
}
393+
373394
// Commit commits all state changes to the database.
374395
func (s *StateDB) Commit() (root common.Hash, err error) {
375396
root, batch := s.CommitBatch()

eth/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,6 +1876,7 @@ func (api *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogC
18761876
if err != nil {
18771877
return nil, fmt.Errorf("mutation failed: %v", err)
18781878
}
1879+
stateDb.DeleteSuicides()
18791880
continue
18801881
}
18811882
// Otherwise trace the transaction and return

0 commit comments

Comments
 (0)