diff --git a/core/blockchain.go b/core/blockchain.go index 737c11904b..50e9827d0d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -486,7 +486,23 @@ func (bc *BlockChain) loadLastState() error { return bc.Reset() } // Make sure the entire head block is available - currentBlock := bc.GetBlockByHash(head) + currentHeader := bc.GetHeaderByHash(head) + if currentHeader == nil { + // Corrupt or empty database, init from scratch + log.Warn("Head header missing, resetting chain", "hash", head) + return bc.Reset() + } + + var currentBlock *types.Block + if cmp := currentHeader.Number.Cmp(new(big.Int)); cmp == 1 { + // Make sure the entire head block is available. + currentBlock = bc.GetBlockByHash(head) + } else if cmp == 0 { + // On a pruned node the block body might not be available. But a pruned + // block should never be the head block. The only exception is when, as + // a last resort, chain is reset to genesis. + currentBlock = bc.genesisBlock + } if currentBlock == nil { // Corrupt or empty database, init from scratch log.Warn("Head block missing, resetting chain", "hash", head) @@ -497,7 +513,6 @@ func (bc *BlockChain) loadLastState() error { headBlockGauge.Update(int64(currentBlock.NumberU64())) // Restore the last known head header - currentHeader := currentBlock.Header() if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) { if header := bc.GetHeaderByHash(head); header != nil { currentHeader = header @@ -609,11 +624,13 @@ func (bc *BlockChain) SetHead(head uint64) error { } // Send chain head event to update the transaction pool if block := bc.CurrentBlock(); block == nil { - // This should never happen. In practice, previously currentBlock - // contained the entire block whereas now only a "marker", so there - // is an ever so slight chance for a race we should handle. - log.Error("Current block not found in database", "block", block.Number(), "hash", block.Hash()) - return fmt.Errorf("current block missing: #%d [%x..]", block.Number(), block.Hash().Bytes()[:4]) + if block.Number().Uint64() > 0 { + // This should never happen. In practice, previously currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", block.Number(), "hash", block.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", block.Number(), block.Hash().Bytes()[:4]) + } } else { bc.chainHeadFeed.Send(ChainHeadEvent{Header: block.Header()}) } @@ -630,11 +647,13 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error { } // Send chain head event to update the transaction pool if block := bc.CurrentBlock(); block == nil { - // This should never happen. In practice, previously currentBlock - // contained the entire block whereas now only a "marker", so there - // is an ever so slight chance for a race we should handle. - log.Error("Current block not found in database", "block", block.Number(), "hash", block.Hash()) - return fmt.Errorf("current block missing: #%d [%x..]", block.Number(), block.Hash().Bytes()[:4]) + if block.Number().Uint64() > 0 { + // This should never happen. In practice, previously currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", block.Number(), "hash", block.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", block.Number(), block.Hash().Bytes()[:4]) + } } else { bc.chainHeadFeed.Send(ChainHeadEvent{Header: block.Header()}) } diff --git a/core/txindexer.go b/core/txindexer.go index 7411ff9617..c26b5acd15 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -196,6 +196,19 @@ func (indexer *txIndexer) repair(head uint64) { } } +// resolveHead resolves the block number of the current chain head. +func (indexer *txIndexer) resolveHead() uint64 { + headBlockHash := rawdb.ReadHeadBlockHash(indexer.db) + if headBlockHash == (common.Hash{}) { + return 0 + } + headBlockNumber := rawdb.ReadHeaderNumber(indexer.db, headBlockHash) + if headBlockNumber == nil { + return 0 + } + return *headBlockNumber +} + // loop is the scheduler of the indexer, assigning indexing/unindexing tasks depending // on the received chain event. func (indexer *txIndexer) loop(chain *BlockChain) { @@ -203,9 +216,9 @@ func (indexer *txIndexer) loop(chain *BlockChain) { // Listening to chain events and manipulate the transaction indexes. var ( - stop chan struct{} // Non-nil if background routine is active - done chan struct{} // Non-nil if background routine is active - head = rawdb.ReadHeadBlock(indexer.db).NumberU64() // The latest announced chain head + stop chan struct{} // Non-nil if background routine is active + done chan struct{} // Non-nil if background routine is active + head = indexer.resolveHead() // The latest announced chain head headCh = make(chan ChainHeadEvent) sub = chain.SubscribeChainHeadEvent(headCh)