eth: fix single transaction tracing (run prev mutations)

This commit is contained in:
Péter Szilágyi 2016-04-14 14:29:47 +03:00
parent e50e3bea49
commit bbc77f488e

View File

@ -1772,55 +1772,61 @@ func formatError(err error) string {
// TraceTransaction returns the structured logs created during the execution of EVM // TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object. // and returns them as a JSON object.
func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger vm.LogConfig) (*ExecutionResult, error) { func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger vm.LogConfig) (*ExecutionResult, error) {
// Retrieve the tx from the chain // Retrieve the tx from the chain and the containing block
tx, _, blockIndex, _ := core.GetTransaction(s.eth.ChainDb(), txHash) tx, blockHash, _, txIndex := core.GetTransaction(s.eth.ChainDb(), txHash)
if tx == nil { if tx == nil {
return nil, fmt.Errorf("Transaction not found") return nil, fmt.Errorf("transaction %x not found", txHash)
} }
block := s.eth.BlockChain().GetBlock(blockHash)
block := s.eth.BlockChain().GetBlockByNumber(blockIndex - 1)
if block == nil { if block == nil {
return nil, fmt.Errorf("Unable to retrieve prior block") return nil, fmt.Errorf("block %x not found", blockHash)
} }
// Create the state database to mutate and eventually trace
// Create the state database parent := s.eth.BlockChain().GetBlock(block.ParentHash())
stateDb, err := state.New(block.Root(), s.eth.ChainDb()) if parent == nil {
return nil, fmt.Errorf("block parent %x not found", block.ParentHash())
}
stateDb, err := state.New(parent.Root(), s.eth.ChainDb())
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Mutate the state and trace the selected transaction
txFrom, err := tx.FromFrontier() for idx, tx := range block.Transactions() {
// Assemble the transaction call message
from, err := tx.FromFrontier()
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to create transaction sender") return nil, fmt.Errorf("sender retrieval failed: %v", err)
} }
from := stateDb.GetOrNewStateObject(txFrom)
msg := callmsg{ msg := callmsg{
from: from, from: stateDb.GetOrNewStateObject(from),
to: tx.To(), to: tx.To(),
gas: tx.Gas(), gas: tx.Gas(),
gasPrice: tx.GasPrice(), gasPrice: tx.GasPrice(),
value: tx.Value(), value: tx.Value(),
data: tx.Data(), data: tx.Data(),
} }
// Mutate the state if we haven't reached the tracing transaction yet
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, block.Header(), vm.Config{ if uint64(idx) < txIndex {
Debug: true, vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{})
Logger: logger, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
})
gp := new(core.GasPool).AddGas(block.GasLimit())
ret, gas, err := core.ApplyMessage(vmenv, msg, gp)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error executing transaction %v", err) return nil, fmt.Errorf("mutation failed: %v", err)
}
continue
}
// Otherwise trace the transaction and return
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{Debug: true, Logger: logger})
ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil {
return nil, fmt.Errorf("tracing failed: %v", err)
} }
return &ExecutionResult{ return &ExecutionResult{
Gas: gas, Gas: gas,
ReturnValue: fmt.Sprintf("%x", ret), ReturnValue: fmt.Sprintf("%x", ret),
StructLogs: formatLogs(vmenv.StructLogs()), StructLogs: formatLogs(vmenv.StructLogs()),
}, nil }, nil
}
return nil, errors.New("database inconsistency")
} }
func (s *PublicBlockChainAPI) TraceCall(args CallArgs, blockNr rpc.BlockNumber) (*ExecutionResult, error) { func (s *PublicBlockChainAPI) TraceCall(args CallArgs, blockNr rpc.BlockNumber) (*ExecutionResult, error) {