@@ -53,6 +53,13 @@ const (
5353 // and reexecute to produce missing historical state necessary to run a specific
5454 // trace.
5555 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 )
5663)
5764
5865// Backend interface provides the common API services (that are provided by
@@ -67,7 +74,10 @@ type Backend interface {
6774 ChainConfig () * params.ChainConfig
6875 Engine () consensus.Engine
6976 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 )
7181 StateAtTransaction (ctx context.Context , block * types.Block , txIndex int , reexec uint64 ) (core.Message , vm.BlockContext , * state.StateDB , error )
7282}
7383
@@ -320,6 +330,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
320330 }
321331 close (results )
322332 }()
333+ var preferDisk bool
323334 // Feed all the blocks both into the tracer, as well as fast process concurrently
324335 for number = start .NumberU64 (); number < end .NumberU64 (); number ++ {
325336 // Stop tracing if interruption was requested
@@ -349,18 +360,24 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
349360 }
350361 // Prepare the statedb for tracing. Don't use the live database for
351362 // 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 )
353364 if err != nil {
354365 failed = err
355366 break
356367 }
357- if statedb .Database ().TrieDB () != nil {
368+ if trieDb := statedb .Database ().TrieDB (); trieDb != nil {
358369 // 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 {})
360371
361372 // Release the parent state because it's already held by the tracer
362373 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
364381 }
365382 }
366383 parent = block .Root ()
@@ -496,7 +513,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
496513 if config != nil && config .Reexec != nil {
497514 reexec = * config .Reexec
498515 }
499- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
516+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
500517 if err != nil {
501518 return nil , err
502519 }
@@ -557,7 +574,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
557574 if config != nil && config .Reexec != nil {
558575 reexec = * config .Reexec
559576 }
560- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
577+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
561578 if err != nil {
562579 return nil , err
563580 }
@@ -646,7 +663,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
646663 if config != nil && config .Reexec != nil {
647664 reexec = * config .Reexec
648665 }
649- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
666+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
650667 if err != nil {
651668 return nil , err
652669 }
@@ -810,7 +827,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
810827 if config != nil && config .Reexec != nil {
811828 reexec = * config .Reexec
812829 }
813- statedb , err := api .backend .StateAtBlock (ctx , block , reexec , nil , true )
830+ statedb , err := api .backend .StateAtBlock (ctx , block , reexec , nil , true , false )
814831 if err != nil {
815832 return nil , err
816833 }
0 commit comments