@@ -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 // SYSCOIN
7383 ReadSYSHash (ctx context.Context , number rpc.BlockNumber ) ([]byte , error )
@@ -329,6 +339,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
329339 }
330340 close (results )
331341 }()
342+ var preferDisk bool
332343 // Feed all the blocks both into the tracer, as well as fast process concurrently
333344 for number = start .NumberU64 (); number < end .NumberU64 (); number ++ {
334345 // Stop tracing if interruption was requested
@@ -358,18 +369,24 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
358369 }
359370 // Prepare the statedb for tracing. Don't use the live database for
360371 // tracing to avoid persisting state junks into the database.
361- statedb , err = api .backend .StateAtBlock (localctx , block , reexec , statedb , false )
372+ statedb , err = api .backend .StateAtBlock (localctx , block , reexec , statedb , false , preferDisk )
362373 if err != nil {
363374 failed = err
364375 break
365376 }
366- if statedb .Database ().TrieDB () != nil {
377+ if trieDb := statedb .Database ().TrieDB (); trieDb != nil {
367378 // Hold the reference for tracer, will be released at the final stage
368- statedb . Database (). TrieDB () .Reference (block .Root (), common.Hash {})
379+ trieDb .Reference (block .Root (), common.Hash {})
369380
370381 // Release the parent state because it's already held by the tracer
371382 if parent != (common.Hash {}) {
372- statedb .Database ().TrieDB ().Dereference (parent )
383+ trieDb .Dereference (parent )
384+ }
385+ // Prefer disk if the trie db memory grows too much
386+ s1 , s2 := trieDb .Size ()
387+ if ! preferDisk && (s1 + s2 ) > defaultTracechainMemLimit {
388+ log .Info ("Switching to prefer-disk mode for tracing" , "size" , s1 + s2 )
389+ preferDisk = true
373390 }
374391 }
375392 parent = block .Root ()
@@ -505,7 +522,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
505522 if config != nil && config .Reexec != nil {
506523 reexec = * config .Reexec
507524 }
508- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
525+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
509526 if err != nil {
510527 return nil , err
511528 }
@@ -566,7 +583,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
566583 if config != nil && config .Reexec != nil {
567584 reexec = * config .Reexec
568585 }
569- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
586+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
570587 if err != nil {
571588 return nil , err
572589 }
@@ -655,7 +672,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
655672 if config != nil && config .Reexec != nil {
656673 reexec = * config .Reexec
657674 }
658- statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
675+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true , false )
659676 if err != nil {
660677 return nil , err
661678 }
@@ -819,7 +836,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
819836 if config != nil && config .Reexec != nil {
820837 reexec = * config .Reexec
821838 }
822- statedb , err := api .backend .StateAtBlock (ctx , block , reexec , nil , true )
839+ statedb , err := api .backend .StateAtBlock (ctx , block , reexec , nil , true , false )
823840 if err != nil {
824841 return nil , err
825842 }
0 commit comments