@@ -1594,7 +1594,7 @@ type BlockTraceResult struct {
1594
1594
1595
1595
// TraceBlock processes the given block's RLP but does not import the block in to
1596
1596
// the chain.
1597
- func (api * PrivateDebugAPI ) TraceBlock (blockRlp []byte , config vm.Config ) BlockTraceResult {
1597
+ func (api * PrivateDebugAPI ) TraceBlock (blockRlp []byte , config * vm.Config ) BlockTraceResult {
1598
1598
var block types.Block
1599
1599
err := rlp .Decode (bytes .NewReader (blockRlp ), & block )
1600
1600
if err != nil {
@@ -1611,7 +1611,7 @@ func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config vm.Config) BlockT
1611
1611
1612
1612
// TraceBlockFromFile loads the block's RLP from the given file name and attempts to
1613
1613
// 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 {
1615
1615
blockRlp , err := ioutil .ReadFile (file )
1616
1616
if err != nil {
1617
1617
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
1620
1620
}
1621
1621
1622
1622
// 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 {
1624
1624
// Fetch the block that we aim to reprocess
1625
1625
block := api .eth .BlockChain ().GetBlockByNumber (number )
1626
1626
if block == nil {
@@ -1636,7 +1636,7 @@ func (api *PrivateDebugAPI) TraceBlockByNumber(number uint64, config vm.Config)
1636
1636
}
1637
1637
1638
1638
// 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 {
1640
1640
// Fetch the block that we aim to reprocess
1641
1641
block := api .eth .BlockChain ().GetBlock (hash )
1642
1642
if block == nil {
@@ -1664,14 +1664,17 @@ func (t *TraceCollector) AddStructLog(slog vm.StructLog) {
1664
1664
}
1665
1665
1666
1666
// 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 ) {
1668
1668
// Validate and reprocess the block
1669
1669
var (
1670
1670
blockchain = api .eth .BlockChain ()
1671
1671
validator = blockchain .Validator ()
1672
1672
processor = blockchain .Processor ()
1673
1673
collector = & TraceCollector {}
1674
1674
)
1675
+ if config == nil {
1676
+ config = new (vm.Config )
1677
+ }
1675
1678
config .Debug = true // make sure debug is set.
1676
1679
config .Logger .Collector = collector
1677
1680
@@ -1683,7 +1686,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, config vm.Config) (bo
1683
1686
return false , collector .traces , err
1684
1687
}
1685
1688
1686
- receipts , _ , usedGas , err := processor .Process (block , statedb , config )
1689
+ receipts , _ , usedGas , err := processor .Process (block , statedb , * config )
1687
1690
if err != nil {
1688
1691
return false , collector .traces , err
1689
1692
}
@@ -1771,56 +1774,65 @@ func formatError(err error) string {
1771
1774
1772
1775
// TraceTransaction returns the structured logs created during the execution of EVM
1773
1776
// 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 )
1778
1783
if tx == nil {
1779
- return nil , fmt .Errorf ("Transaction not found" )
1784
+ return nil , fmt .Errorf ("transaction %x not found" , txHash )
1780
1785
}
1781
-
1782
- block := s .eth .BlockChain ().GetBlockByNumber (blockIndex - 1 )
1786
+ block := s .eth .BlockChain ().GetBlock (blockHash )
1783
1787
if block == nil {
1784
- return nil , fmt .Errorf ("Unable to retrieve prior block" )
1788
+ return nil , fmt .Errorf ("block %x not found" , blockHash )
1785
1789
}
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 ())
1791
1794
}
1792
-
1793
- txFrom , err := tx .FromFrontier ()
1794
-
1795
+ stateDb , err := state .New (parent .Root (), s .eth .ChainDb ())
1795
1796
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
1806
1798
}
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
1817
1834
}
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" )
1824
1836
}
1825
1837
1826
1838
func (s * PublicBlockChainAPI ) TraceCall (args CallArgs , blockNr rpc.BlockNumber ) (* ExecutionResult , error ) {
0 commit comments