forked from cerc-io/plugeth
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
This commit is contained in:
parent
fdd61b83ff
commit
bb3651abc8
@ -370,6 +370,27 @@ func (s *StateDB) IntermediateRoot() common.Hash {
|
|||||||
return s.trie.Hash()
|
return s.trie.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSuicides flags the suicided objects for deletion so that it
|
||||||
|
// won't be referenced again when called / queried up on.
|
||||||
|
//
|
||||||
|
// DeleteSuicides should not be used for consensus related updates
|
||||||
|
// under any circumstances.
|
||||||
|
func (s *StateDB) DeleteSuicides() {
|
||||||
|
// Reset refund so that any used-gas calculations can use
|
||||||
|
// this method.
|
||||||
|
s.refund = new(big.Int)
|
||||||
|
for _, stateObject := range s.stateObjects {
|
||||||
|
if stateObject.dirty {
|
||||||
|
// If the object has been removed by a suicide
|
||||||
|
// flag the object as deleted.
|
||||||
|
if stateObject.remove {
|
||||||
|
stateObject.deleted = true
|
||||||
|
}
|
||||||
|
stateObject.dirty = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Commit commits all state changes to the database.
|
// Commit commits all state changes to the database.
|
||||||
func (s *StateDB) Commit() (root common.Hash, err error) {
|
func (s *StateDB) Commit() (root common.Hash, err error) {
|
||||||
root, batch := s.CommitBatch()
|
root, batch := s.CommitBatch()
|
||||||
|
@ -1876,6 +1876,7 @@ func (api *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogC
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("mutation failed: %v", err)
|
return nil, fmt.Errorf("mutation failed: %v", err)
|
||||||
}
|
}
|
||||||
|
stateDb.DeleteSuicides()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Otherwise trace the transaction and return
|
// Otherwise trace the transaction and return
|
||||||
|
Loading…
Reference in New Issue
Block a user