@@ -53,6 +53,13 @@ const (
53
53
// and reexecute to produce missing historical state necessary to run a specific
54
54
// trace.
55
55
defaultTraceReexec = uint64 (128 )
56
+
57
+ // defaultTracechainMemLimit is the size of the triedb, at which traceChain
58
+ // switches over and tries to use a disk-backed database instead of building
59
+ // on top of memory.
60
+ // For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
61
+ // will only be found every ~15K blocks or so.
62
+ defaultTracechainMemLimit = common .StorageSize (500 * 1024 * 1024 )
56
63
)
57
64
58
65
// Backend interface provides the common API services (that are provided by
@@ -67,7 +74,10 @@ type Backend interface {
67
74
ChainConfig () * params.ChainConfig
68
75
Engine () consensus.Engine
69
76
ChainDb () ethdb.Database
70
- StateAtBlock (ctx context.Context , block * types.Block , reexec uint64 , base * state.StateDB , checkLive bool ) (* state.StateDB , error )
77
+ // StateAtBlock returns the state corresponding to the stateroot of the block.
78
+ // N.B: For executing transactions on block N, the required stateRoot is block N-1,
79
+ // so this method should be called with the parent.
80
+ StateAtBlock (ctx context.Context , block * types.Block , reexec uint64 , base * state.StateDB , checkLive , preferDisk bool ) (* state.StateDB , error )
71
81
StateAtTransaction (ctx context.Context , block * types.Block , txIndex int , reexec uint64 ) (core.Message , vm.BlockContext , * state.StateDB , error )
72
82
}
73
83
@@ -320,6 +330,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
320
330
}
321
331
close (results )
322
332
}()
333
+ var preferDisk bool
323
334
// Feed all the blocks both into the tracer, as well as fast process concurrently
324
335
for number = start .NumberU64 (); number < end .NumberU64 (); number ++ {
325
336
// Stop tracing if interruption was requested
@@ -349,18 +360,24 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
349
360
}
350
361
// Prepare the statedb for tracing. Don't use the live database for
351
362
// tracing to avoid persisting state junks into the database.
352
- statedb , err = api .backend .StateAtBlock (localctx , block , reexec , statedb , false )
363
+ statedb , err = api .backend .StateAtBlock (localctx , block , reexec , statedb , false , preferDisk )
353
364
if err != nil {
354
365
failed = err
355
366
break
356
367
}
357
- if statedb .Database ().TrieDB () != nil {
368
+ if trieDb := statedb .Database ().TrieDB (); trieDb != nil {
358
369
// Hold the reference for tracer, will be released at the final stage
359
- statedb . Database (). TrieDB () .Reference (block .Root (), common.Hash {})
370
+ trieDb .Reference (block .Root (), common.Hash {})
360
371
361
372
// Release the parent state because it's already held by the tracer
362
373
if parent != (common.Hash {}) {
363
- statedb .Database ().TrieDB ().Dereference (parent )
374
+ trieDb .Dereference (parent )
375
+ }
376
+ // Prefer disk if the trie db memory grows too much
377
+ s1 , s2 := trieDb .Size ()
378
+ if ! preferDisk && (s1 + s2 ) > defaultTracechainMemLimit {
379
+ log .Info ("Switching to prefer-disk mode for tracing" , "size" , s1 + s2 )
380
+ preferDisk = true
364
381
}
365
382
}
366
383
parent = block .Root ()
@@ -496,7 +513,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
496
513
if config != nil && config .Reexec != nil {
497
514
reexec = * config .Reexec
498
515
}
499
- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
516
+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
500
517
if err != nil {
501
518
return nil , err
502
519
}
@@ -557,7 +574,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
557
574
if config != nil && config .Reexec != nil {
558
575
reexec = * config .Reexec
559
576
}
560
- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
577
+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
561
578
if err != nil {
562
579
return nil , err
563
580
}
@@ -646,7 +663,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
646
663
if config != nil && config .Reexec != nil {
647
664
reexec = * config .Reexec
648
665
}
649
- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
666
+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
650
667
if err != nil {
651
668
return nil , err
652
669
}
@@ -810,7 +827,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
810
827
if config != nil && config .Reexec != nil {
811
828
reexec = * config .Reexec
812
829
}
813
- statedb , err := api .backend .StateAtBlock (ctx , block , reexec , nil , true )
830
+ statedb , err := api .backend .StateAtBlock (ctx , block , reexec , nil , true , false )
814
831
if err != nil {
815
832
return nil , err
816
833
}
0 commit comments