@@ -34,6 +34,7 @@ import (
3434 "github.com/CortexFoundation/CortexTheseus/common/mclock"
3535 "github.com/CortexFoundation/CortexTheseus/common/prque"
3636 "github.com/CortexFoundation/CortexTheseus/consensus"
37+ "github.com/CortexFoundation/CortexTheseus/core/history"
3738 "github.com/CortexFoundation/CortexTheseus/core/rawdb"
3839 "github.com/CortexFoundation/CortexTheseus/core/state"
3940 "github.com/CortexFoundation/CortexTheseus/core/state/snapshot"
@@ -153,7 +154,7 @@ type CacheConfig struct {
153154
154155 // This defines the cutoff block for history expiry.
155156 // Blocks before this number may be unavailable in the chain database.
156- HistoryPruningCutoff uint64
157+ ChainHistoryMode history. HistoryMode
157158}
158159
159160// defaultCacheConfig are the default caching values if none are specified by the
@@ -222,6 +223,7 @@ type BlockChain struct {
222223 currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
223224 currentFinalizedBlock atomic.Value // Current finalized head
224225 currentSafeBlock atomic.Value // Current safe head
226+ historyPrunePoint atomic.Pointer [history.PrunePoint ]
225227
226228 stateCache * state.CachingDB // State database to reuse between imports (contains state cache)
227229 txIndexer * txIndexer
@@ -503,6 +505,12 @@ func (bc *BlockChain) loadLastState() error {
503505 }
504506 bc .hc .SetCurrentHeader (currentHeader )
505507
508+ // Initialize history pruning.
509+ latest := max (currentBlock .NumberU64 (), currentHeader .Number .Uint64 ())
510+ if err := bc .initializeHistoryPruning (latest ); err != nil {
511+ return err
512+ }
513+
506514 // Restore the last known head fast block
507515 bc .currentFastBlock .Store (currentBlock )
508516 headFastBlockGauge .Update (int64 (currentBlock .NumberU64 ()))
@@ -541,9 +549,57 @@ func (bc *BlockChain) loadLastState() error {
541549 if pivot := rawdb .ReadLastPivotNumber (bc .db ); pivot != nil {
542550 log .Info ("Loaded last fast-sync pivot marker" , "number" , * pivot )
543551 }
552+ if pruning := bc .historyPrunePoint .Load (); pruning != nil {
553+ log .Info ("Chain history is pruned" , "earliest" , pruning .BlockNumber , "hash" , pruning .BlockHash )
554+ }
544555 return nil
545556}
546557
558+ // initializeHistoryPruning sets bc.historyPrunePoint.
559+ func (bc * BlockChain ) initializeHistoryPruning (latest uint64 ) error {
560+ freezerTail , _ := bc .db .Tail ()
561+
562+ switch bc .cacheConfig .ChainHistoryMode {
563+ case history .KeepAll :
564+ if freezerTail == 0 {
565+ return nil
566+ }
567+ // The database was pruned somehow, so we need to figure out if it's a known
568+ // configuration or an error.
569+ predefinedPoint := history .PrunePoints [bc .genesisBlock .Hash ()]
570+ if predefinedPoint == nil || freezerTail != predefinedPoint .BlockNumber {
571+ log .Error ("Chain history database is pruned with unknown configuration" , "tail" , freezerTail )
572+ return fmt .Errorf ("unexpected database tail" )
573+ }
574+ bc .historyPrunePoint .Store (predefinedPoint )
575+ return nil
576+
577+ case history .KeepPostMerge :
578+ if freezerTail == 0 && latest != 0 {
579+ // This is the case where a user is trying to run with --history.chain
580+ // postmerge directly on an existing DB. We could just trigger the pruning
581+ // here, but it'd be a bit dangerous since they may not have intended this
582+ // action to happen. So just tell them how to do it.
583+ log .Error (fmt .Sprintf ("Chain history mode is configured as %q, but database is not pruned." , bc .cacheConfig .ChainHistoryMode .String ()))
584+ log .Error (fmt .Sprintf ("Run 'geth prune-history' to prune pre-merge history." ))
585+ return fmt .Errorf ("history pruning requested via configuration" )
586+ }
587+ predefinedPoint := history .PrunePoints [bc .genesisBlock .Hash ()]
588+ if predefinedPoint == nil {
589+ log .Error ("Chain history pruning is not supported for this network" , "genesis" , bc .genesisBlock .Hash ())
590+ return fmt .Errorf ("history pruning requested for unknown network" )
591+ } else if freezerTail != predefinedPoint .BlockNumber {
592+ log .Error ("Chain history database is pruned to unknown block" , "tail" , freezerTail )
593+ return fmt .Errorf ("unexpected database tail" )
594+ }
595+ bc .historyPrunePoint .Store (predefinedPoint )
596+ return nil
597+
598+ default :
599+ return fmt .Errorf ("invalid history mode: %d" , bc .cacheConfig .ChainHistoryMode )
600+ }
601+ }
602+
547603// SetHead rewinds the local chain to a new head. Depending on whether the node
548604// was fast synced or full synced and in which state, the method will try to
549605// delete minimal data from disk whilst retaining chain consistency.
@@ -846,7 +902,9 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
846902 bc .hc .SetCurrentHeader (bc .genesisBlock .Header ())
847903 bc .currentFastBlock .Store (bc .genesisBlock )
848904 headFastBlockGauge .Update (int64 (bc .genesisBlock .NumberU64 ()))
849- return nil
905+
906+ // Reset history pruning status.
907+ return bc .initializeHistoryPruning (0 )
850908}
851909
852910// Export writes the active chain to the given writer.
@@ -2325,9 +2383,3 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i
23252383 _ , err := bc .hc .InsertHeaderChain (chain , start )
23262384 return 0 , err
23272385}
2328-
2329- // HistoryPruningCutoff returns the configured history pruning point.
2330- // Blocks before this might not be available in the database.
2331- func (bc * BlockChain ) HistoryPruningCutoff () uint64 {
2332- return bc .cacheConfig .HistoryPruningCutoff
2333- }
0 commit comments