@@ -66,7 +66,7 @@ type TraceConfig struct {
66
66
type StdTraceConfig struct {
67
67
* vm.LogConfig
68
68
Reexec * uint64
69
- TxHash * common.Hash
69
+ TxHash common.Hash
70
70
}
71
71
72
72
// txTraceResult is the result of a single transaction trace.
@@ -375,7 +375,7 @@ func (api *PrivateDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.B
375
375
func (api * PrivateDebugAPI ) TraceBlockByHash (ctx context.Context , hash common.Hash , config * TraceConfig ) ([]* txTraceResult , error ) {
376
376
block := api .eth .blockchain .GetBlockByHash (hash )
377
377
if block == nil {
378
- return nil , fmt .Errorf ("block #% x not found" , hash )
378
+ return nil , fmt .Errorf ("block %# x not found" , hash )
379
379
}
380
380
return api .traceBlock (ctx , block , config )
381
381
}
@@ -400,37 +400,41 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string,
400
400
return api .TraceBlock (ctx , blob , config )
401
401
}
402
402
403
- // TraceBadBlockByHash returns the structured logs created during the execution of a block
404
- func (api * PrivateDebugAPI ) TraceBadBlock (ctx context.Context , blockHash common.Hash , config * TraceConfig ) ([]* txTraceResult , error ) {
403
+ // TraceBadBlockByHash returns the structured logs created during the execution of
404
+ // EVM against a block pulled from the pool of bad ones and returns them as a JSON
405
+ // object.
406
+ func (api * PrivateDebugAPI ) TraceBadBlock (ctx context.Context , hash common.Hash , config * TraceConfig ) ([]* txTraceResult , error ) {
405
407
blocks := api .eth .blockchain .BadBlocks ()
406
408
for _ , block := range blocks {
407
- if block .Hash () == blockHash {
409
+ if block .Hash () == hash {
408
410
return api .traceBlock (ctx , block , config )
409
411
}
410
412
}
411
- return nil , fmt .Errorf ("hash not found among bad blocks" )
413
+ return nil , fmt .Errorf ("bad block %#x not found" , hash )
412
414
}
413
415
414
- // StandardTraceBadBlockToFile dumps the standard-json logs to files on the local filesystem,
415
- // and returns a list of files to the caller.
416
- func (api * PrivateDebugAPI ) StandardTraceBadBlockToFile (ctx context.Context , blockHash common.Hash , stdConfig * StdTraceConfig ) ([]string , error ) {
417
- blocks := api .eth .blockchain .BadBlocks ()
418
- for _ , block := range blocks {
419
- if block .Hash () == blockHash {
420
- return api .standardTraceBlockToFile (ctx , block , stdConfig )
421
- }
416
+ // StandardTraceBlockToFile dumps the structured logs created during the
417
+ // execution of EVM to the local file system and returns a list of files
418
+ // to the caller.
419
+ func (api * PrivateDebugAPI ) StandardTraceBlockToFile (ctx context.Context , hash common.Hash , config * StdTraceConfig ) ([]string , error ) {
420
+ block := api .eth .blockchain .GetBlockByHash (hash )
421
+ if block == nil {
422
+ return nil , fmt .Errorf ("block %#x not found" , hash )
422
423
}
423
- return nil , fmt . Errorf ( "hash not found among bad blocks" )
424
+ return api . standardTraceBlockToFile ( ctx , block , config )
424
425
}
425
426
426
- // StandardTraceBlockToFile dumps the standard-json logs to files on the local filesystem,
427
- // and returns a list of files to the caller.
428
- func (api * PrivateDebugAPI ) StandardTraceBlockToFile (ctx context.Context , blockHash common.Hash , stdConfig * StdTraceConfig ) ([]string , error ) {
429
- block := api .eth .blockchain .GetBlockByHash (blockHash )
430
- if block == nil {
431
- return nil , fmt .Errorf ("block #%x not found" , blockHash )
427
+ // StandardTraceBadBlockToFile dumps the structured logs created during the
428
+ // execution of EVM against a block pulled from the pool of bad ones to the
429
+ // local file system and returns a list of files to the caller.
430
+ func (api * PrivateDebugAPI ) StandardTraceBadBlockToFile (ctx context.Context , hash common.Hash , config * StdTraceConfig ) ([]string , error ) {
431
+ blocks := api .eth .blockchain .BadBlocks ()
432
+ for _ , block := range blocks {
433
+ if block .Hash () == hash {
434
+ return api .standardTraceBlockToFile (ctx , block , config )
435
+ }
432
436
}
433
- return api . standardTraceBlockToFile ( ctx , block , stdConfig )
437
+ return nil , fmt . Errorf ( "bad block %#x not found" , hash )
434
438
}
435
439
436
440
// traceBlock configures a new tracer according to the provided configuration, and
@@ -443,7 +447,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
443
447
}
444
448
parent := api .eth .blockchain .GetBlock (block .ParentHash (), block .NumberU64 ()- 1 )
445
449
if parent == nil {
446
- return nil , fmt .Errorf ("parent %x not found" , block .ParentHash ())
450
+ return nil , fmt .Errorf ("parent %# x not found" , block .ParentHash ())
447
451
}
448
452
reexec := defaultTraceReexec
449
453
if config != nil && config .Reexec != nil {
@@ -514,90 +518,104 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
514
518
return results , nil
515
519
}
516
520
517
- // standardTraceBlockToFile configures a new tracer which uses standard-json output, and
518
- // traces either a full block or an individual transaction. The return value will be one filename
519
- // per transaction traced.
520
- func (api * PrivateDebugAPI ) standardTraceBlockToFile (ctx context.Context , block * types.Block , stdConfig * StdTraceConfig ) ([]string , error ) {
521
+ // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
522
+ // and traces either a full block or an individual transaction. The return value will
523
+ // be one filename per transaction traced.
524
+ func (api * PrivateDebugAPI ) standardTraceBlockToFile (ctx context.Context , block * types.Block , config * StdTraceConfig ) ([]string , error ) {
525
+ // If we're tracing a single transaction, make sure it's present
526
+ if config != nil && config .TxHash != (common.Hash {}) {
527
+ var exists bool
528
+ for _ , tx := range block .Transactions () {
529
+ if exists = (tx .Hash () == config .TxHash ); exists {
530
+ break
531
+ }
532
+ }
533
+ if ! exists {
534
+ return nil , fmt .Errorf ("transaction %#x not found in block" , config .TxHash )
535
+ }
536
+ }
521
537
// Create the parent state database
522
538
if err := api .eth .engine .VerifyHeader (api .eth .blockchain , block .Header (), true ); err != nil {
523
539
return nil , err
524
540
}
525
541
parent := api .eth .blockchain .GetBlock (block .ParentHash (), block .NumberU64 ()- 1 )
526
542
if parent == nil {
527
- return nil , fmt .Errorf ("parent %x not found" , block .ParentHash ())
543
+ return nil , fmt .Errorf ("parent %# x not found" , block .ParentHash ())
528
544
}
529
- var (
530
- signer = types .MakeSigner (api .config , block .Number ())
531
- done = false
532
- blockPrefix = fmt .Sprintf ("block_0x%x" , block .Hash ().Bytes ()[:4 ])
533
- usedLogConfig = & vm.LogConfig {Debug : true }
534
- files []string
535
- reExec_val = defaultTraceReexec
536
- txHash * common.Hash
537
- )
538
- if stdConfig != nil {
539
- if stdConfig .Reexec != nil {
540
- reExec_val = * stdConfig .Reexec
541
- }
542
- if stdConfig .LogConfig != nil {
543
- usedLogConfig .DisableMemory = stdConfig .LogConfig .DisableMemory
544
- usedLogConfig .DisableStack = stdConfig .LogConfig .DisableStack
545
- usedLogConfig .DisableStorage = stdConfig .LogConfig .DisableStorage
546
- usedLogConfig .Limit = stdConfig .LogConfig .Limit
547
- }
548
- txHash = stdConfig .TxHash
545
+ reexec := defaultTraceReexec
546
+ if config != nil && config .Reexec != nil {
547
+ reexec = * config .Reexec
549
548
}
550
- statedb , err := api .computeStateDB (parent , reExec_val )
549
+ statedb , err := api .computeStateDB (parent , reexec )
551
550
if err != nil {
552
551
return nil , err
553
552
}
553
+ // Retrieve the tracing configurations, or use default values
554
+ var (
555
+ logConfig vm.LogConfig
556
+ txHash common.Hash
557
+ )
558
+ if config != nil {
559
+ if config .LogConfig != nil {
560
+ logConfig = * config .LogConfig
561
+ }
562
+ txHash = config .TxHash
563
+ }
564
+ logConfig .Debug = true
554
565
566
+ // Execute transaction, either tracing all or just the requested one
567
+ var (
568
+ signer = types .MakeSigner (api .config , block .Number ())
569
+ dumps []string
570
+ )
555
571
for i , tx := range block .Transactions () {
572
+ // Prepare the trasaction for un-traced execution
556
573
var (
557
- outfile * os.File
558
- err error
574
+ msg , _ = tx .AsMessage (signer )
575
+ vmctx = core .NewEVMContext (msg , block .Header (), api .eth .blockchain , nil )
576
+
577
+ vmConf vm.Config
578
+ dump * os.File
579
+ err error
559
580
)
560
- msg , _ := tx .AsMessage (signer )
561
- vmctx := core .NewEVMContext (msg , block .Header (), api .eth .blockchain , nil )
562
- vmConf := vm.Config {}
563
- if txHash == nil || bytes .Equal (txHash .Bytes (), tx .Hash ().Bytes ()) {
564
- prefix := fmt .Sprintf ("%v-%d-0x%x-" , blockPrefix , i , tx .Hash ().Bytes ()[:4 ])
565
- // Open a file to dump trace into
566
- outfile , err = ioutil .TempFile (os .TempDir (), prefix )
581
+ // If the transaction needs tracing, swap out the configs
582
+ if tx .Hash () == txHash || txHash == (common.Hash {}) {
583
+ // Generate a unique temporary file to dump it into
584
+ prefix := fmt .Sprintf ("block_%#x-%d-%#x-" , block .Hash ().Bytes ()[:4 ], i , tx .Hash ().Bytes ()[:4 ])
585
+
586
+ dump , err = ioutil .TempFile (os .TempDir (), prefix )
567
587
if err != nil {
568
588
return nil , err
569
589
}
570
- files = append (files , outfile .Name ())
590
+ dumps = append (dumps , dump .Name ())
591
+
592
+ // Swap out the noop logger to the standard tracer
571
593
vmConf = vm.Config {
572
594
Debug : true ,
573
- Tracer : vm .NewJSONLogger (usedLogConfig , bufio .NewWriter (outfile )),
595
+ Tracer : vm .NewJSONLogger (& logConfig , bufio .NewWriter (dump )),
574
596
EnablePreimageRecording : true ,
575
597
}
576
- if txHash != nil { // Only one tx to trace
577
- done = true
578
- }
579
598
}
599
+ // Execute the transaction and flush any traces to disk
580
600
vmenv := vm .NewEVM (vmctx , statedb , api .config , vmConf )
581
601
_ , _ , _ , err = core .ApplyMessage (vmenv , msg , new (core.GasPool ).AddGas (msg .Gas ()))
582
602
583
- if outfile != nil {
584
- outfile .Close ()
585
- log .Info ("Wrote trace" , "file" , outfile .Name ())
603
+ if dump != nil {
604
+ dump .Close ()
605
+ log .Info ("Wrote standard trace" , "file" , dump .Name ())
586
606
}
587
607
if err != nil {
588
- return files , err
608
+ return dumps , err
589
609
}
590
610
// Finalize the state so any modifications are written to the trie
591
611
statedb .Finalise (true )
592
612
593
- if done {
613
+ // If we've traced the transaction we were looking for, abort
614
+ if tx .Hash () == txHash {
594
615
break
595
616
}
596
617
}
597
- if txHash != nil && ! done {
598
- return nil , fmt .Errorf ("transaction hash not found in block" )
599
- }
600
- return files , nil
618
+ return dumps , nil
601
619
}
602
620
603
621
// computeStateDB retrieves the state database associated with a certain block.
@@ -675,7 +693,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
675
693
// Retrieve the transaction and assemble its EVM context
676
694
tx , blockHash , _ , index := rawdb .ReadTransaction (api .eth .ChainDb (), hash )
677
695
if tx == nil {
678
- return nil , fmt .Errorf ("transaction %x not found" , hash )
696
+ return nil , fmt .Errorf ("transaction %# x not found" , hash )
679
697
}
680
698
reexec := defaultTraceReexec
681
699
if config != nil && config .Reexec != nil {
@@ -755,11 +773,11 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
755
773
// Create the parent state database
756
774
block := api .eth .blockchain .GetBlockByHash (blockHash )
757
775
if block == nil {
758
- return nil , vm.Context {}, nil , fmt .Errorf ("block %x not found" , blockHash )
776
+ return nil , vm.Context {}, nil , fmt .Errorf ("block %# x not found" , blockHash )
759
777
}
760
778
parent := api .eth .blockchain .GetBlock (block .ParentHash (), block .NumberU64 ()- 1 )
761
779
if parent == nil {
762
- return nil , vm.Context {}, nil , fmt .Errorf ("parent %x not found" , block .ParentHash ())
780
+ return nil , vm.Context {}, nil , fmt .Errorf ("parent %# x not found" , block .ParentHash ())
763
781
}
764
782
statedb , err := api .computeStateDB (parent , reexec )
765
783
if err != nil {
@@ -778,10 +796,10 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
778
796
// Not yet the searched for transaction, execute on top of the current state
779
797
vmenv := vm .NewEVM (context , statedb , api .config , vm.Config {})
780
798
if _ , _ , _ , err := core .ApplyMessage (vmenv , msg , new (core.GasPool ).AddGas (tx .Gas ())); err != nil {
781
- return nil , vm.Context {}, nil , fmt .Errorf ("tx % x failed: %v" , tx .Hash (), err )
799
+ return nil , vm.Context {}, nil , fmt .Errorf ("transaction %# x failed: %v" , tx .Hash (), err )
782
800
}
783
801
// Ensure any modifications are committed to the state
784
802
statedb .Finalise (true )
785
803
}
786
- return nil , vm.Context {}, nil , fmt .Errorf ("tx index %d out of range for block %x" , txIndex , blockHash )
804
+ return nil , vm.Context {}, nil , fmt .Errorf ("transaction index %d out of range for block %# x" , txIndex , blockHash )
787
805
}
0 commit comments