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