Skip to content

Commit bbc77f4

Browse files
committed
eth: fix single transaction tracing (run prev mutations)
1 parent e50e3be commit bbc77f4

File tree

1 file changed

+47
-41
lines changed

1 file changed

+47
-41
lines changed

eth/api.go

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,55 +1772,61 @@ func formatError(err error) string {
17721772
// TraceTransaction returns the structured logs created during the execution of EVM
17731773
// and returns them as a JSON object.
17741774
func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger vm.LogConfig) (*ExecutionResult, error) {
1775-
// Retrieve the tx from the chain
1776-
tx, _, blockIndex, _ := core.GetTransaction(s.eth.ChainDb(), txHash)
1777-
1775+
// Retrieve the tx from the chain and the containing block
1776+
tx, blockHash, _, txIndex := core.GetTransaction(s.eth.ChainDb(), txHash)
17781777
if tx == nil {
1779-
return nil, fmt.Errorf("Transaction not found")
1778+
return nil, fmt.Errorf("transaction %x not found", txHash)
17801779
}
1781-
1782-
block := s.eth.BlockChain().GetBlockByNumber(blockIndex - 1)
1780+
block := s.eth.BlockChain().GetBlock(blockHash)
17831781
if block == nil {
1784-
return nil, fmt.Errorf("Unable to retrieve prior block")
1782+
return nil, fmt.Errorf("block %x not found", blockHash)
17851783
}
1786-
1787-
// Create the state database
1788-
stateDb, err := state.New(block.Root(), s.eth.ChainDb())
1789-
if err != nil {
1790-
return nil, err
1784+
// Create the state database to mutate and eventually trace
1785+
parent := s.eth.BlockChain().GetBlock(block.ParentHash())
1786+
if parent == nil {
1787+
return nil, fmt.Errorf("block parent %x not found", block.ParentHash())
17911788
}
1792-
1793-
txFrom, err := tx.FromFrontier()
1794-
1789+
stateDb, err := state.New(parent.Root(), s.eth.ChainDb())
17951790
if err != nil {
1796-
return nil, fmt.Errorf("Unable to create transaction sender")
1797-
}
1798-
from := stateDb.GetOrNewStateObject(txFrom)
1799-
msg := callmsg{
1800-
from: from,
1801-
to: tx.To(),
1802-
gas: tx.Gas(),
1803-
gasPrice: tx.GasPrice(),
1804-
value: tx.Value(),
1805-
data: tx.Data(),
1791+
return nil, err
18061792
}
1807-
1808-
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, block.Header(), vm.Config{
1809-
Debug: true,
1810-
Logger: logger,
1811-
})
1812-
gp := new(core.GasPool).AddGas(block.GasLimit())
1813-
1814-
ret, gas, err := core.ApplyMessage(vmenv, msg, gp)
1815-
if err != nil {
1816-
return nil, fmt.Errorf("Error executing transaction %v", err)
1793+
// Mutate the state and trace the selected transaction
1794+
for idx, tx := range block.Transactions() {
1795+
// Assemble the transaction call message
1796+
from, err := tx.FromFrontier()
1797+
if err != nil {
1798+
return nil, fmt.Errorf("sender retrieval failed: %v", err)
1799+
}
1800+
msg := callmsg{
1801+
from: stateDb.GetOrNewStateObject(from),
1802+
to: tx.To(),
1803+
gas: tx.Gas(),
1804+
gasPrice: tx.GasPrice(),
1805+
value: tx.Value(),
1806+
data: tx.Data(),
1807+
}
1808+
// Mutate the state if we haven't reached the tracing transaction yet
1809+
if uint64(idx) < txIndex {
1810+
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{})
1811+
_, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
1812+
if err != nil {
1813+
return nil, fmt.Errorf("mutation failed: %v", err)
1814+
}
1815+
continue
1816+
}
1817+
// Otherwise trace the transaction and return
1818+
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{Debug: true, Logger: logger})
1819+
ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
1820+
if err != nil {
1821+
return nil, fmt.Errorf("tracing failed: %v", err)
1822+
}
1823+
return &ExecutionResult{
1824+
Gas: gas,
1825+
ReturnValue: fmt.Sprintf("%x", ret),
1826+
StructLogs: formatLogs(vmenv.StructLogs()),
1827+
}, nil
18171828
}
1818-
1819-
return &ExecutionResult{
1820-
Gas: gas,
1821-
ReturnValue: fmt.Sprintf("%x", ret),
1822-
StructLogs: formatLogs(vmenv.StructLogs()),
1823-
}, nil
1829+
return nil, errors.New("database inconsistency")
18241830
}
18251831

18261832
func (s *PublicBlockChainAPI) TraceCall(args CallArgs, blockNr rpc.BlockNumber) (*ExecutionResult, error) {

0 commit comments

Comments
 (0)