From b789de62ae8c947759901335d325cda131f2797d Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Wed, 12 Feb 2025 10:34:23 +0100 Subject: [PATCH] make indexer handle null block hashes (#473) Before the future release 0.2.0 the block_hash is not stored in database. In future releases we're using the block_hash to check for reorgs. There's a rare corner case where the indexer tries to retrieve a block hash that happens to be null, in that case we should skip it and check for reorgs later in the chain. In the case when a reorg happens later in the chain, and the reorg handler algorithm determines the reorg happened in a range we don't have any data about, then the indexer should simply start indexing from 0, as it's the safest option. ## Summary by CodeRabbit - **Bug Fixes** - Enhanced reorganization detection by adding safeguards to handle scenarios with missing block data. - Improved error handling to prevent issues during blockchain updates. --- pkg/indexer/indexer.go | 3 ++- pkg/indexer/reorgHandler.go | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pkg/indexer/indexer.go b/pkg/indexer/indexer.go index fce2c8ca..4bb5750b 100644 --- a/pkg/indexer/indexer.go +++ b/pkg/indexer/indexer.go @@ -304,7 +304,8 @@ func indexLogs( zap.Uint64("blockNumber", reorgCheckAt), ) - if !bytes.Equal(storedBlockHash, onchainBlock.Hash().Bytes()) { + if storedBlockHash != nil && + !bytes.Equal(storedBlockHash, onchainBlock.Hash().Bytes()) { logger.Warn("blockchain reorg detected", zap.Uint64("storedBlockNumber", storedBlockNumber), zap.String("storedBlockHash", hex.EncodeToString(storedBlockHash)), diff --git a/pkg/indexer/reorgHandler.go b/pkg/indexer/reorgHandler.go index 2bc1be38..e1c424e4 100644 --- a/pkg/indexer/reorgHandler.go +++ b/pkg/indexer/reorgHandler.go @@ -72,6 +72,26 @@ func (r *ReorgHandler) FindReorgPoint(detectedAt uint64) (uint64, []byte, error) } oldestBlock := storedBlocks[0] + + if oldestBlock.BlockHash == nil { + startAtZero, err := r.client.BlockByNumber( + r.ctx, + big.NewInt(0), + ) + if err != nil { + return 0, nil, fmt.Errorf("%w %d: %v", ErrGetBlock, oldestBlock.BlockNumber, err) + } + + if err := r.queries.UpdateBlocksCanonicalityInRange(r.ctx, queries.UpdateBlocksCanonicalityInRangeParams{ + StartBlockNumber: 0, + EndBlockNumber: detectedAt, + }); err != nil { + return 0, nil, fmt.Errorf("failed to update block range canonicality: %w", err) + } + + return 0, startAtZero.Hash().Bytes(), nil + } + chainBlock, err := r.client.BlockByNumber(r.ctx, big.NewInt(int64(oldestBlock.BlockNumber))) if err != nil { return 0, nil, fmt.Errorf("%w %d: %v", ErrGetBlock, oldestBlock.BlockNumber, err)