Skip to content

Commit 5f91771

Browse files
committed
Merge pull request #2454 from karalabe/trace-fix
eth: fix single transaction tracing (run prev mutations)
2 parents e50e3be + 53016c1 commit 5f91771

File tree

2 files changed

+65
-53
lines changed

2 files changed

+65
-53
lines changed

eth/api.go

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,7 +1594,7 @@ type BlockTraceResult struct {
15941594

15951595
// TraceBlock processes the given block's RLP but does not import the block in to
15961596
// the chain.
1597-
func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config vm.Config) BlockTraceResult {
1597+
func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config *vm.Config) BlockTraceResult {
15981598
var block types.Block
15991599
err := rlp.Decode(bytes.NewReader(blockRlp), &block)
16001600
if err != nil {
@@ -1611,7 +1611,7 @@ func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config vm.Config) BlockT
16111611

16121612
// TraceBlockFromFile loads the block's RLP from the given file name and attempts to
16131613
// process it but does not import the block in to the chain.
1614-
func (api *PrivateDebugAPI) TraceBlockFromFile(file string, config vm.Config) BlockTraceResult {
1614+
func (api *PrivateDebugAPI) TraceBlockFromFile(file string, config *vm.Config) BlockTraceResult {
16151615
blockRlp, err := ioutil.ReadFile(file)
16161616
if err != nil {
16171617
return BlockTraceResult{Error: fmt.Sprintf("could not read file: %v", err)}
@@ -1620,7 +1620,7 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(file string, config vm.Config) Bl
16201620
}
16211621

16221622
// TraceProcessBlock processes the block by canonical block number.
1623-
func (api *PrivateDebugAPI) TraceBlockByNumber(number uint64, config vm.Config) BlockTraceResult {
1623+
func (api *PrivateDebugAPI) TraceBlockByNumber(number uint64, config *vm.Config) BlockTraceResult {
16241624
// Fetch the block that we aim to reprocess
16251625
block := api.eth.BlockChain().GetBlockByNumber(number)
16261626
if block == nil {
@@ -1636,7 +1636,7 @@ func (api *PrivateDebugAPI) TraceBlockByNumber(number uint64, config vm.Config)
16361636
}
16371637

16381638
// TraceBlockByHash processes the block by hash.
1639-
func (api *PrivateDebugAPI) TraceBlockByHash(hash common.Hash, config vm.Config) BlockTraceResult {
1639+
func (api *PrivateDebugAPI) TraceBlockByHash(hash common.Hash, config *vm.Config) BlockTraceResult {
16401640
// Fetch the block that we aim to reprocess
16411641
block := api.eth.BlockChain().GetBlock(hash)
16421642
if block == nil {
@@ -1664,14 +1664,17 @@ func (t *TraceCollector) AddStructLog(slog vm.StructLog) {
16641664
}
16651665

16661666
// traceBlock processes the given block but does not save the state.
1667-
func (api *PrivateDebugAPI) traceBlock(block *types.Block, config vm.Config) (bool, []vm.StructLog, error) {
1667+
func (api *PrivateDebugAPI) traceBlock(block *types.Block, config *vm.Config) (bool, []vm.StructLog, error) {
16681668
// Validate and reprocess the block
16691669
var (
16701670
blockchain = api.eth.BlockChain()
16711671
validator = blockchain.Validator()
16721672
processor = blockchain.Processor()
16731673
collector = &TraceCollector{}
16741674
)
1675+
if config == nil {
1676+
config = new(vm.Config)
1677+
}
16751678
config.Debug = true // make sure debug is set.
16761679
config.Logger.Collector = collector
16771680

@@ -1683,7 +1686,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, config vm.Config) (bo
16831686
return false, collector.traces, err
16841687
}
16851688

1686-
receipts, _, usedGas, err := processor.Process(block, statedb, config)
1689+
receipts, _, usedGas, err := processor.Process(block, statedb, *config)
16871690
if err != nil {
16881691
return false, collector.traces, err
16891692
}
@@ -1771,56 +1774,65 @@ func formatError(err error) string {
17711774

17721775
// TraceTransaction returns the structured logs created during the execution of EVM
17731776
// and returns them as a JSON object.
1774-
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-
1777+
func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogConfig) (*ExecutionResult, error) {
1778+
if logger == nil {
1779+
logger = new(vm.LogConfig)
1780+
}
1781+
// Retrieve the tx from the chain and the containing block
1782+
tx, blockHash, _, txIndex := core.GetTransaction(s.eth.ChainDb(), txHash)
17781783
if tx == nil {
1779-
return nil, fmt.Errorf("Transaction not found")
1784+
return nil, fmt.Errorf("transaction %x not found", txHash)
17801785
}
1781-
1782-
block := s.eth.BlockChain().GetBlockByNumber(blockIndex - 1)
1786+
block := s.eth.BlockChain().GetBlock(blockHash)
17831787
if block == nil {
1784-
return nil, fmt.Errorf("Unable to retrieve prior block")
1788+
return nil, fmt.Errorf("block %x not found", blockHash)
17851789
}
1786-
1787-
// Create the state database
1788-
stateDb, err := state.New(block.Root(), s.eth.ChainDb())
1789-
if err != nil {
1790-
return nil, err
1790+
// Create the state database to mutate and eventually trace
1791+
parent := s.eth.BlockChain().GetBlock(block.ParentHash())
1792+
if parent == nil {
1793+
return nil, fmt.Errorf("block parent %x not found", block.ParentHash())
17911794
}
1792-
1793-
txFrom, err := tx.FromFrontier()
1794-
1795+
stateDb, err := state.New(parent.Root(), s.eth.ChainDb())
17951796
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(),
1797+
return nil, err
18061798
}
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)
1799+
// Mutate the state and trace the selected transaction
1800+
for idx, tx := range block.Transactions() {
1801+
// Assemble the transaction call message
1802+
from, err := tx.FromFrontier()
1803+
if err != nil {
1804+
return nil, fmt.Errorf("sender retrieval failed: %v", err)
1805+
}
1806+
msg := callmsg{
1807+
from: stateDb.GetOrNewStateObject(from),
1808+
to: tx.To(),
1809+
gas: tx.Gas(),
1810+
gasPrice: tx.GasPrice(),
1811+
value: tx.Value(),
1812+
data: tx.Data(),
1813+
}
1814+
// Mutate the state if we haven't reached the tracing transaction yet
1815+
if uint64(idx) < txIndex {
1816+
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{})
1817+
_, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
1818+
if err != nil {
1819+
return nil, fmt.Errorf("mutation failed: %v", err)
1820+
}
1821+
continue
1822+
}
1823+
// Otherwise trace the transaction and return
1824+
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{Debug: true, Logger: *logger})
1825+
ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
1826+
if err != nil {
1827+
return nil, fmt.Errorf("tracing failed: %v", err)
1828+
}
1829+
return &ExecutionResult{
1830+
Gas: gas,
1831+
ReturnValue: fmt.Sprintf("%x", ret),
1832+
StructLogs: formatLogs(vmenv.StructLogs()),
1833+
}, nil
18171834
}
1818-
1819-
return &ExecutionResult{
1820-
Gas: gas,
1821-
ReturnValue: fmt.Sprintf("%x", ret),
1822-
StructLogs: formatLogs(vmenv.StructLogs()),
1823-
}, nil
1835+
return nil, errors.New("database inconsistency")
18241836
}
18251837

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

rpc/javascript.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,22 +268,22 @@ web3._extend({
268268
new web3._extend.Method({
269269
name: 'traceBlock',
270270
call: 'debug_traceBlock',
271-
params: 2
271+
params: 1
272272
}),
273273
new web3._extend.Method({
274274
name: 'traceBlockByFile',
275275
call: 'debug_traceBlockByFile',
276-
params: 2
276+
params: 1
277277
}),
278278
new web3._extend.Method({
279279
name: 'traceBlockByNumber',
280280
call: 'debug_traceBlockByNumber',
281-
params: 2
281+
params: 1
282282
}),
283283
new web3._extend.Method({
284284
name: 'traceBlockByHash',
285285
call: 'debug_traceBlockByHash',
286-
params: 2
286+
params: 1
287287
}),
288288
new web3._extend.Method({
289289
name: 'seedHash',
@@ -390,7 +390,7 @@ web3._extend({
390390
new web3._extend.Method({
391391
name: 'traceTransaction',
392392
call: 'debug_traceTransaction',
393-
params: 2
393+
params: 1
394394
})
395395
],
396396
properties: []

0 commit comments

Comments
 (0)