@@ -514,19 +514,33 @@ func (bc *BlockChain) loadLastState() error {
514514 log .Warn ("Empty database, resetting chain" )
515515 return bc .Reset ()
516516 }
517- // Make sure the entire head block is available
518- headBlock := bc .GetBlockByHash (head )
517+ headHeader := bc .GetHeaderByHash (head )
518+ if headHeader == nil {
519+ // Corrupt or empty database, init from scratch
520+ log .Warn ("Head header missing, resetting chain" , "hash" , head )
521+ return bc .Reset ()
522+ }
523+
524+ var headBlock * types.Block
525+ if cmp := headHeader .Number .Cmp (new (big.Int )); cmp == 1 {
526+ // Make sure the entire head block is available.
527+ headBlock = bc .GetBlockByHash (head )
528+ } else if cmp == 0 {
529+ // On a pruned node the block body might not be available. But a pruned
530+ // block should never be the head block. The only exception is when, as
531+ // a last resort, chain is reset to genesis.
532+ headBlock = bc .genesisBlock
533+ }
519534 if headBlock == nil {
520535 // Corrupt or empty database, init from scratch
521536 log .Warn ("Head block missing, resetting chain" , "hash" , head )
522537 return bc .Reset ()
523538 }
524539 // Everything seems to be fine, set as the head block
525- bc .currentBlock .Store (headBlock . Header () )
540+ bc .currentBlock .Store (headHeader )
526541 headBlockGauge .Update (int64 (headBlock .NumberU64 ()))
527542
528543 // Restore the last known head header
529- headHeader := headBlock .Header ()
530544 if head := rawdb .ReadHeadHeaderHash (bc .db ); head != (common.Hash {}) {
531545 if header := bc .GetHeaderByHash (head ); header != nil {
532546 headHeader = header
@@ -642,11 +656,15 @@ func (bc *BlockChain) SetHead(head uint64) error {
642656 // Send chain head event to update the transaction pool
643657 header := bc .CurrentBlock ()
644658 if block := bc .GetBlock (header .Hash (), header .Number .Uint64 ()); block == nil {
645- // This should never happen. In practice, previously currentBlock
646- // contained the entire block whereas now only a "marker", so there
647- // is an ever so slight chance for a race we should handle.
648- log .Error ("Current block not found in database" , "block" , header .Number , "hash" , header .Hash ())
649- return fmt .Errorf ("current block missing: #%d [%x..]" , header .Number , header .Hash ().Bytes ()[:4 ])
659+ // In a pruned node the genesis block will not exist in the freezer.
660+ // It should not happen that we set head to any other pruned block.
661+ if header .Number .Uint64 () > 0 {
662+ // This should never happen. In practice, previously currentBlock
663+ // contained the entire block whereas now only a "marker", so there
664+ // is an ever so slight chance for a race we should handle.
665+ log .Error ("Current block not found in database" , "block" , header .Number , "hash" , header .Hash ())
666+ return fmt .Errorf ("current block missing: #%d [%x..]" , header .Number , header .Hash ().Bytes ()[:4 ])
667+ }
650668 }
651669 bc .chainHeadFeed .Send (ChainHeadEvent {Header : header })
652670 return nil
@@ -663,11 +681,15 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
663681 // Send chain head event to update the transaction pool
664682 header := bc .CurrentBlock ()
665683 if block := bc .GetBlock (header .Hash (), header .Number .Uint64 ()); block == nil {
666- // This should never happen. In practice, previously currentBlock
667- // contained the entire block whereas now only a "marker", so there
668- // is an ever so slight chance for a race we should handle.
669- log .Error ("Current block not found in database" , "block" , header .Number , "hash" , header .Hash ())
670- return fmt .Errorf ("current block missing: #%d [%x..]" , header .Number , header .Hash ().Bytes ()[:4 ])
684+ // In a pruned node the genesis block will not exist in the freezer.
685+ // It should not happen that we set head to any other pruned block.
686+ if header .Number .Uint64 () > 0 {
687+ // This should never happen. In practice, previously currentBlock
688+ // contained the entire block whereas now only a "marker", so there
689+ // is an ever so slight chance for a race we should handle.
690+ log .Error ("Current block not found in database" , "block" , header .Number , "hash" , header .Hash ())
691+ return fmt .Errorf ("current block missing: #%d [%x..]" , header .Number , header .Hash ().Bytes ()[:4 ])
692+ }
671693 }
672694 bc .chainHeadFeed .Send (ChainHeadEvent {Header : header })
673695 return nil
0 commit comments