From 7ddca95c2044b5010ba21192f570929e99fc9606 Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Fri, 20 Sep 2024 21:38:53 +0700 Subject: [PATCH] e3: CanonicalHash to return `ok` as found-marker (#11942) to fix: ``` curl --data '{"method":"debug_traceBlockByNumber","params":["0x13C2924"],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8549 {"jsonrpc":"2.0","id":1,"result":null,"error":{"code":-32000,"message":"invalid arguments; block with hash 0000000000000000000000000000000000000000000000000000000000000000 not found"}} ``` --- accounts/abi/bind/backends/simulated.go | 5 +- cmd/hack/hack.go | 4 +- cmd/integration/commands/stages.go | 5 +- cmd/rpcdaemon/rpcservices/eth_backend.go | 6 +- cmd/state/verify/verify_txlookup.go | 6 +- core/rawdb/accessors_chain_test.go | 6 +- core/rawdb/accessors_indexes_test.go | 4 +- eth/integrity/no_gaps_in_canonical_headers.go | 4 +- eth/stagedsync/stage_execute.go | 11 ++- eth/stagedsync/stage_headers.go | 15 ++-- eth/stagedsync/stage_polygon_sync.go | 11 ++- eth/stagedsync/stage_snapshots.go | 5 +- ethdb/privateapi/ethbackend.go | 5 +- tests/block_test_util.go | 2 +- .../engine_helpers/fork_validator.go | 7 +- turbo/execution/eth1/ethereum_execution.go | 15 +++- turbo/jsonrpc/debug_api.go | 8 +- turbo/jsonrpc/debug_api_test.go | 10 +-- turbo/jsonrpc/eth_api.go | 5 +- turbo/jsonrpc/eth_block.go | 5 +- turbo/jsonrpc/eth_call.go | 4 +- turbo/jsonrpc/eth_callMany.go | 6 +- turbo/jsonrpc/otterscan_search_trace.go | 5 +- ...terscan_transaction_by_sender_and_nonce.go | 5 +- turbo/jsonrpc/overlay_api.go | 12 +-- turbo/jsonrpc/tracing.go | 6 +- turbo/rpchelper/helper.go | 45 +++++++----- turbo/services/interfaces.go | 2 +- .../snapshotsync/freezeblocks/block_reader.go | 73 ++++++++++++------- turbo/stages/blockchain_test.go | 8 +- turbo/stages/bodydownload/body_algos.go | 12 ++- turbo/stages/headerdownload/header_algos.go | 11 ++- 32 files changed, 215 insertions(+), 113 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index c3d53b69283..be93657fb9c 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -317,10 +317,13 @@ func (b *SimulatedBackend) TransactionByHash(ctx context.Context, txHash libcomm if !ok { return nil, false, ethereum.NotFound } - blockHash, err := b.BlockReader().CanonicalHash(ctx, tx, blockNumber) + blockHash, ok, err := b.BlockReader().CanonicalHash(ctx, tx, blockNumber) if err != nil { return nil, false, err } + if !ok { + return nil, false, ethereum.NotFound + } body, err := b.BlockReader().BodyWithTransactions(ctx, tx, blockHash, blockNumber) if err != nil { return nil, false, err diff --git a/cmd/hack/hack.go b/cmd/hack/hack.go index a26254ab8c4..2e860fa65e5 100644 --- a/cmd/hack/hack.go +++ b/cmd/hack/hack.go @@ -223,7 +223,7 @@ func extractHashes(chaindata string, blockStep uint64, blockTotalOrOffset int64, blockTotal := getBlockTotal(tx, b, blockTotalOrOffset) // Note: blockTotal used here as block number rather than block count for b <= blockTotal { - hash, err := br.CanonicalHash(context.Background(), tx, b) + hash, _, err := br.CanonicalHash(context.Background(), tx, b) if err != nil { return err } @@ -340,7 +340,7 @@ func extractBodies(datadir string) error { blockNumber := binary.BigEndian.Uint64(k[:8]) blockHash := libcommon.BytesToHash(k[8:]) var hash libcommon.Hash - if hash, err = br.CanonicalHash(context.Background(), tx, blockNumber); err != nil { + if hash, _, err = br.CanonicalHash(context.Background(), tx, blockNumber); err != nil { return err } _, baseTxnID, txCount := rawdb.ReadBody(tx, blockHash, blockNumber) diff --git a/cmd/integration/commands/stages.go b/cmd/integration/commands/stages.go index 21fa690abc9..223bee009fb 100644 --- a/cmd/integration/commands/stages.go +++ b/cmd/integration/commands/stages.go @@ -743,10 +743,13 @@ func stageHeaders(db kv.RwDB, ctx context.Context, logger log.Logger) error { if err = rawdb.TruncateTd(tx, progress+1); err != nil { return err } - hash, err := br.CanonicalHash(ctx, tx, progress-1) + hash, ok, err := br.CanonicalHash(ctx, tx, progress-1) if err != nil { return err } + if !ok { + return fmt.Errorf("canonical hash not found: %d", progress-1) + } if err = rawdb.WriteHeadHeaderHash(tx, hash); err != nil { return err } diff --git a/cmd/rpcdaemon/rpcservices/eth_backend.go b/cmd/rpcdaemon/rpcservices/eth_backend.go index 8c5781e2858..d30932af83a 100644 --- a/cmd/rpcdaemon/rpcservices/eth_backend.go +++ b/cmd/rpcdaemon/rpcservices/eth_backend.go @@ -91,11 +91,11 @@ func (back *RemoteBackend) ReadAncestor(db kv.Getter, hash common.Hash, number, panic("not implemented") } func (back *RemoteBackend) BlockByNumber(ctx context.Context, db kv.Tx, number uint64) (*types.Block, error) { - hash, err := back.CanonicalHash(ctx, db, number) + hash, ok, err := back.CanonicalHash(ctx, db, number) if err != nil { return nil, fmt.Errorf("failed ReadCanonicalHash: %w", err) } - if hash == (common.Hash{}) { + if !ok || hash == (common.Hash{}) { return nil, nil } block, _, err := back.BlockWithSenders(ctx, db, hash, number) @@ -298,7 +298,7 @@ func (back *RemoteBackend) HeaderByNumber(ctx context.Context, tx kv.Getter, blo func (back *RemoteBackend) HeaderByHash(ctx context.Context, tx kv.Getter, hash common.Hash) (*types.Header, error) { return back.blockReader.HeaderByHash(ctx, tx, hash) } -func (back *RemoteBackend) CanonicalHash(ctx context.Context, tx kv.Getter, blockNum uint64) (common.Hash, error) { +func (back *RemoteBackend) CanonicalHash(ctx context.Context, tx kv.Getter, blockNum uint64) (common.Hash, bool, error) { return back.blockReader.CanonicalHash(ctx, tx, blockNum) } func (back *RemoteBackend) HeaderNumber(ctx context.Context, tx kv.Getter, hash common.Hash) (*uint64, error) { diff --git a/cmd/state/verify/verify_txlookup.go b/cmd/state/verify/verify_txlookup.go index cc23ee1c30a..692f2278994 100644 --- a/cmd/state/verify/verify_txlookup.go +++ b/cmd/state/verify/verify_txlookup.go @@ -74,10 +74,14 @@ func ValidateTxLookups(chaindata string, logger log.Logger) error { if err := libcommon.Stopped(quitCh); err != nil { return err } - blockHash, err := br.CanonicalHash(ctx, tx, blockNum) + blockHash, ok, err := br.CanonicalHash(ctx, tx, blockNum) if err != nil { return err } + if !ok { + logger.Error("no canonnical hash", "blocknum", blockNum) + break + } body, err := br.BodyWithTransactions(ctx, tx, blockHash, blockNum) if err != nil { return err diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 6abd0cef448..115667a89a8 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -378,7 +378,7 @@ func TestCanonicalMappingStorage(t *testing.T) { // Create a test canonical number and assinged hash to move around hash, number := libcommon.Hash{0: 0xff}, uint64(314) - entry, err := br.CanonicalHash(m.Ctx, tx, number) + entry, _, err := br.CanonicalHash(m.Ctx, tx, number) if err != nil { t.Fatalf("ReadCanonicalHash failed: %v", err) } @@ -390,7 +390,7 @@ func TestCanonicalMappingStorage(t *testing.T) { if err != nil { t.Fatalf("WriteCanoncalHash failed: %v", err) } - entry, err = br.CanonicalHash(m.Ctx, tx, number) + entry, _, err = br.CanonicalHash(m.Ctx, tx, number) if err != nil { t.Fatalf("ReadCanonicalHash failed: %v", err) } @@ -404,7 +404,7 @@ func TestCanonicalMappingStorage(t *testing.T) { if err != nil { t.Fatalf("DeleteCanonicalHash failed: %v", err) } - entry, err = br.CanonicalHash(m.Ctx, tx, number) + entry, _, err = br.CanonicalHash(m.Ctx, tx, number) if err != nil { t.Error(err) } diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 7ba5587b2f5..2f0291a4562 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -122,11 +122,11 @@ func readTransactionByHash(db kv.Tx, hash libcommon.Hash, br services.FullBlockR if blockNumber == nil { return nil, libcommon.Hash{}, 0, 0, nil } - blockHash, err := br.CanonicalHash(context.Background(), db, *blockNumber) + blockHash, ok, err := br.CanonicalHash(context.Background(), db, *blockNumber) if err != nil { return nil, libcommon.Hash{}, 0, 0, err } - if blockHash == (libcommon.Hash{}) { + if !ok || blockHash == (libcommon.Hash{}) { return nil, libcommon.Hash{}, 0, 0, nil } body, _ := br.BodyWithTransactions(context.Background(), db, blockHash, *blockNumber) diff --git a/eth/integrity/no_gaps_in_canonical_headers.go b/eth/integrity/no_gaps_in_canonical_headers.go index b9fae306fe8..cbeea4c863f 100644 --- a/eth/integrity/no_gaps_in_canonical_headers.go +++ b/eth/integrity/no_gaps_in_canonical_headers.go @@ -45,11 +45,11 @@ func NoGapsInCanonicalHeaders(tx kv.Tx, ctx context.Context, br services.FullBlo } for i := firstBlockInDB; i < lastBlockNum; i++ { - hash, err := br.CanonicalHash(ctx, tx, i) + hash, ok, err := br.CanonicalHash(ctx, tx, i) if err != nil { panic(err) } - if hash == (common.Hash{}) { + if !ok || hash == (common.Hash{}) { err = fmt.Errorf("canonical marker not found: %d", i) panic(err) } diff --git a/eth/stagedsync/stage_execute.go b/eth/stagedsync/stage_execute.go index a8ebf2bc6d2..1d0b1920826 100644 --- a/eth/stagedsync/stage_execute.go +++ b/eth/stagedsync/stage_execute.go @@ -191,11 +191,13 @@ func unwindExec3(u *UnwindState, s *StageState, txc wrap.TxContainer, ctx contex t := time.Now() var changeset *[kv.DomainLen][]libstate.DomainEntryDiff for currentBlock := u.CurrentBlockNumber; currentBlock > u.UnwindPoint; currentBlock-- { - currentHash, err := br.CanonicalHash(ctx, txc.Tx, currentBlock) + currentHash, ok, err := br.CanonicalHash(ctx, txc.Tx, currentBlock) if err != nil { return err } - var ok bool + if !ok { + return fmt.Errorf("canonical hash not found %d", currentBlock) + } var currentKeys [kv.DomainLen][]libstate.DomainEntryDiff currentKeys, ok, err = domains.GetDiffset(txc.Tx, currentHash, currentBlock) if !ok { @@ -362,10 +364,13 @@ func unwindExecutionStage(u *UnwindState, s *StageState, txc wrap.TxContainer, c if cfg.stateStream && s.BlockNumber-u.UnwindPoint < stateStreamLimit { accumulator = cfg.notifications.Accumulator - hash, err := cfg.blockReader.CanonicalHash(ctx, txc.Tx, u.UnwindPoint) + hash, ok, err := cfg.blockReader.CanonicalHash(ctx, txc.Tx, u.UnwindPoint) if err != nil { return fmt.Errorf("read canonical hash of unwind point: %w", err) } + if !ok { + return fmt.Errorf("canonical hash not found %d", u.UnwindPoint) + } txs, err := cfg.blockReader.RawTransactions(ctx, txc.Tx, u.UnwindPoint, s.BlockNumber) if err != nil { return err diff --git a/eth/stagedsync/stage_headers.go b/eth/stagedsync/stage_headers.go index 3a1d51b98fa..60deb4cdaac 100644 --- a/eth/stagedsync/stage_headers.go +++ b/eth/stagedsync/stage_headers.go @@ -141,16 +141,16 @@ func HeadersPOW(s *StageState, u Unwinder, ctx context.Context, tx kv.RwTx, cfg defer logEvery.Stop() // Check if this is called straight after the unwinds, which means we need to create new canonical markings - hash, err := cfg.blockReader.CanonicalHash(ctx, tx, startProgress) + hash, ok, err := cfg.blockReader.CanonicalHash(ctx, tx, startProgress) if err != nil { return err } - if hash == (libcommon.Hash{}) { // restore canonical markers after unwind + if !ok || hash == (libcommon.Hash{}) { // restore canonical markers after unwind headHash := rawdb.ReadHeadHeaderHash(tx) if err = fixCanonicalChain(logPrefix, logEvery, startProgress, headHash, tx, cfg.blockReader, logger); err != nil { return err } - hash, err = cfg.blockReader.CanonicalHash(ctx, tx, startProgress) + hash, _, err = cfg.blockReader.CanonicalHash(ctx, tx, startProgress) if err != nil { return err } @@ -377,7 +377,7 @@ func fixCanonicalChain(logPrefix string, logEvery *time.Ticker, height uint64, h var ch libcommon.Hash var err error - for ch, err = headerReader.CanonicalHash(context.Background(), tx, ancestorHeight); err == nil && ch != ancestorHash; ch, err = headerReader.CanonicalHash(context.Background(), tx, ancestorHeight) { + for ch, _, err = headerReader.CanonicalHash(context.Background(), tx, ancestorHeight); err == nil && ch != ancestorHash; ch, _, err = headerReader.CanonicalHash(context.Background(), tx, ancestorHeight) { if err = rawdb.WriteCanonicalHash(tx, ancestorHash, ancestorHeight); err != nil { return fmt.Errorf("marking canonical header %d %x: %w", ancestorHeight, ancestorHash, err) } @@ -497,9 +497,14 @@ func HeadersUnwind(ctx context.Context, u *UnwindState, s *StageState, tx kv.RwT */ if maxNum == 0 { maxNum = u.UnwindPoint - if maxHash, err = cfg.blockReader.CanonicalHash(ctx, tx, maxNum); err != nil { + var ok bool + if maxHash, ok, err = cfg.blockReader.CanonicalHash(ctx, tx, maxNum); err != nil { return err } + if !ok { + return fmt.Errorf("not found canonical marker: %d", maxNum) + } + } if err = rawdb.WriteHeadHeaderHash(tx, maxHash); err != nil { return err diff --git a/eth/stagedsync/stage_polygon_sync.go b/eth/stagedsync/stage_polygon_sync.go index 81fea073548..5849e4c8e32 100644 --- a/eth/stagedsync/stage_polygon_sync.go +++ b/eth/stagedsync/stage_polygon_sync.go @@ -220,10 +220,13 @@ func UnwindPolygonSyncStage(ctx context.Context, tx kv.RwTx, u *UnwindState, cfg return err } - canonicalHash, err := cfg.blockReader.CanonicalHash(ctx, tx, u.UnwindPoint) + canonicalHash, ok, err := cfg.blockReader.CanonicalHash(ctx, tx, u.UnwindPoint) if err != nil { return err } + if !ok { + return fmt.Errorf("canonical marker not found: %d", u.UnwindPoint) + } if err = rawdb.WriteHeadHeaderHash(tx, canonicalHash); err != nil { return err @@ -1564,10 +1567,14 @@ func (e *polygonSyncStageExecutionEngine) connectTip( var emptyHash common.Hash var ch common.Hash for { - ch, err = e.blockReader.CanonicalHash(ctx, tx, blockNum) + var ok bool + ch, ok, err = e.blockReader.CanonicalHash(ctx, tx, blockNum) if err != nil { return nil, nil, fmt.Errorf("connectTip reading canonical hash for %d: %w", blockNum, err) } + if !ok { + return nil, nil, fmt.Errorf("connectTip canonical hash not found. blockNum %d", blockNum) + } if ch == blockHash { break } diff --git a/eth/stagedsync/stage_snapshots.go b/eth/stagedsync/stage_snapshots.go index c895e221c92..958e58c5041 100644 --- a/eth/stagedsync/stage_snapshots.go +++ b/eth/stagedsync/stage_snapshots.go @@ -434,10 +434,13 @@ func FillDBFromSnapshots(logPrefix string, ctx context.Context, tx kv.RwTx, dirs if err := h2n.Load(tx, kv.HeaderNumber, etl.IdentityLoadFunc, etl.TransformArgs{}); err != nil { return err } - canonicalHash, err := blockReader.CanonicalHash(ctx, tx, blocksAvailable) + canonicalHash, ok, err := blockReader.CanonicalHash(ctx, tx, blocksAvailable) if err != nil { return err } + if !ok { + return fmt.Errorf("canonical marker not found: %d", blocksAvailable) + } if err = rawdb.WriteHeadHeaderHash(tx, canonicalHash); err != nil { return err } diff --git a/ethdb/privateapi/ethbackend.go b/ethdb/privateapi/ethbackend.go index f5908fcbea7..3aaf0c56893 100644 --- a/ethdb/privateapi/ethbackend.go +++ b/ethdb/privateapi/ethbackend.go @@ -284,10 +284,13 @@ func (s *EthBackendServer) CanonicalHash(ctx context.Context, req *remote.Canoni } defer tx.Rollback() - hash, err := s.blockReader.CanonicalHash(ctx, tx, req.BlockNumber) + hash, ok, err := s.blockReader.CanonicalHash(ctx, tx, req.BlockNumber) if err != nil { return nil, err } + if !ok { + return nil, nil + } return &remote.CanonicalHashReply{Hash: gointerfaces.ConvertHashToH256(hash)}, nil } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index dc03306d241..8c1f34d9fa2 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -224,7 +224,7 @@ func (bt *BlockTest) insertBlocks(m *mock.MockSentry) ([]btBlock, error) { return nil, err } defer roTx.Rollback() - canonical, cErr := bt.br.CanonicalHash(context.Background(), roTx, cb.NumberU64()) + canonical, _, cErr := bt.br.CanonicalHash(context.Background(), roTx, cb.NumberU64()) if cErr != nil { return nil, cErr } diff --git a/turbo/engineapi/engine_helpers/fork_validator.go b/turbo/engineapi/engine_helpers/fork_validator.go index 935b07b6e61..094672ab21d 100644 --- a/turbo/engineapi/engine_helpers/fork_validator.go +++ b/turbo/engineapi/engine_helpers/fork_validator.go @@ -320,10 +320,15 @@ func (fv *ForkValidator) validateAndStorePayload(txc wrap.TxContainer, header *t if criticalError != nil { return } - latestValidHash, criticalError = fv.blockReader.CanonicalHash(fv.ctx, txc.Tx, latestValidNumber) + var ok bool + latestValidHash, ok, criticalError = fv.blockReader.CanonicalHash(fv.ctx, txc.Tx, latestValidNumber) if criticalError != nil { return } + if !ok { + criticalError = fmt.Errorf("canonical hash not found: %d", latestValidNumber) + return + } status = engine_types.InvalidStatus if fv.sharedDom != nil { fv.sharedDom.Close() diff --git a/turbo/execution/eth1/ethereum_execution.go b/turbo/execution/eth1/ethereum_execution.go index be347ada84c..fd4317610b4 100644 --- a/turbo/execution/eth1/ethereum_execution.go +++ b/turbo/execution/eth1/ethereum_execution.go @@ -160,11 +160,18 @@ func (e *EthereumExecutionModule) canonicalHash(ctx context.Context, tx kv.Tx, b var err error if e.blockReader == nil { canonical, err = rawdb.ReadCanonicalHash(tx, blockNumber) + if err != nil { + return libcommon.Hash{}, err + } } else { - canonical, err = e.blockReader.CanonicalHash(ctx, tx, blockNumber) - } - if err != nil { - return libcommon.Hash{}, err + var ok bool + canonical, ok, err = e.blockReader.CanonicalHash(ctx, tx, blockNumber) + if err != nil { + return libcommon.Hash{}, err + } + if !ok { + return libcommon.Hash{}, nil + } } td, err := rawdb.ReadTd(tx, canonical, blockNumber) diff --git a/turbo/jsonrpc/debug_api.go b/turbo/jsonrpc/debug_api.go index ab26c2933e2..d932b50ccf9 100644 --- a/turbo/jsonrpc/debug_api.go +++ b/turbo/jsonrpc/debug_api.go @@ -313,7 +313,13 @@ func (api *PrivateDebugAPIImpl) AccountAt(ctx context.Context, blockHash common. if number == nil { return nil, nil // not error, see https://github.com/erigontech/erigon/issues/1645 } - canonicalHash, _ := api._blockReader.CanonicalHash(ctx, tx, *number) + canonicalHash, ok, err := api._blockReader.CanonicalHash(ctx, tx, *number) + if err != nil { + return nil, err + } + if !ok { + return nil, fmt.Errorf("canonical hash not found %d", *number) + } isCanonical := canonicalHash == blockHash if !isCanonical { return nil, errors.New("block hash is not canonical") diff --git a/turbo/jsonrpc/debug_api_test.go b/turbo/jsonrpc/debug_api_test.go index 0f17f768916..667f921728f 100644 --- a/turbo/jsonrpc/debug_api_test.go +++ b/turbo/jsonrpc/debug_api_test.go @@ -465,11 +465,11 @@ func TestAccountAt(t *testing.T) { var blockHash0, blockHash1, blockHash3, blockHash10, blockHash12 common.Hash _ = m.DB.View(m.Ctx, func(tx kv.Tx) error { - blockHash0, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 0) - blockHash1, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 1) - blockHash3, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 3) - blockHash10, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 10) - blockHash12, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 12) + blockHash0, _, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 0) + blockHash1, _, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 1) + blockHash3, _, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 3) + blockHash10, _, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 10) + blockHash12, _, _ = m.BlockReader.CanonicalHash(m.Ctx, tx, 12) _, _, _, _, _ = blockHash0, blockHash1, blockHash3, blockHash10, blockHash12 return nil }) diff --git a/turbo/jsonrpc/eth_api.go b/turbo/jsonrpc/eth_api.go index 61041dbdcd4..bc951c16024 100644 --- a/turbo/jsonrpc/eth_api.go +++ b/turbo/jsonrpc/eth_api.go @@ -195,10 +195,13 @@ func (api *BaseAPI) txnLookup(ctx context.Context, tx kv.Tx, txnHash common.Hash } func (api *BaseAPI) blockByNumberWithSenders(ctx context.Context, tx kv.Tx, number uint64) (*types.Block, error) { - hash, hashErr := api._blockReader.CanonicalHash(ctx, tx, number) + hash, ok, hashErr := api._blockReader.CanonicalHash(ctx, tx, number) if hashErr != nil { return nil, hashErr } + if !ok { + return nil, nil + } return api.blockWithSenders(ctx, tx, hash, number) } diff --git a/turbo/jsonrpc/eth_block.go b/turbo/jsonrpc/eth_block.go index 64321722071..ed454a3a478 100644 --- a/turbo/jsonrpc/eth_block.go +++ b/turbo/jsonrpc/eth_block.go @@ -344,10 +344,13 @@ func (api *APIImpl) GetBlockTransactionCountByNumber(ctx context.Context, blockN return nil, nil } - _, txCount, err := api._blockReader.Body(ctx, tx, blockHash, blockNum) + body, txCount, err := api._blockReader.Body(ctx, tx, blockHash, blockNum) if err != nil { return nil, err } + if body == nil { + return nil, nil + } chainConfig, err := api.chainConfig(ctx, tx) if err != nil { diff --git a/turbo/jsonrpc/eth_call.go b/turbo/jsonrpc/eth_call.go index 8cea96d8197..adece60919b 100644 --- a/turbo/jsonrpc/eth_call.go +++ b/turbo/jsonrpc/eth_call.go @@ -106,11 +106,11 @@ func (api *APIImpl) Call(ctx context.Context, args ethapi2.CallArgs, blockNrOrHa // headerByNumberOrHash - intent to read recent headers only, tries from the lru cache before reading from the db func headerByNumberOrHash(ctx context.Context, tx kv.Tx, blockNrOrHash rpc.BlockNumberOrHash, api *APIImpl) (*types.Header, error) { - _, bNrOrHashHash, _, err := rpchelper.GetCanonicalBlockNumber(ctx, blockNrOrHash, tx, api._blockReader, api.filters) + _, hash, _, err := rpchelper.GetCanonicalBlockNumber(ctx, blockNrOrHash, tx, api._blockReader, api.filters) if err != nil { return nil, err } - block := api.tryBlockFromLru(bNrOrHashHash) + block := api.tryBlockFromLru(hash) if block != nil { return block.Header(), nil } diff --git a/turbo/jsonrpc/eth_callMany.go b/turbo/jsonrpc/eth_callMany.go index 4e298517cb1..a7672aab4fc 100644 --- a/turbo/jsonrpc/eth_callMany.go +++ b/turbo/jsonrpc/eth_callMany.go @@ -166,9 +166,9 @@ func (api *APIImpl) CallMany(ctx context.Context, bundles []Bundle, simulateCont if hash, ok := overrideBlockHash[i]; ok { return hash } - hash, err := api._blockReader.CanonicalHash(ctx, tx, i) - if err != nil { - log.Debug("Can't get block hash by number", "number", i, "only-canonical", true) + hash, ok, err := api._blockReader.CanonicalHash(ctx, tx, i) + if err != nil || !ok { + log.Debug("Can't get block hash by number", "number", i, "only-canonical", true, "err", err, "ok", ok) } return hash } diff --git a/turbo/jsonrpc/otterscan_search_trace.go b/turbo/jsonrpc/otterscan_search_trace.go index e96239ea166..6250604b9e8 100644 --- a/turbo/jsonrpc/otterscan_search_trace.go +++ b/turbo/jsonrpc/otterscan_search_trace.go @@ -59,10 +59,13 @@ func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNu receipts := make([]map[string]interface{}, 0) // Retrieve the transaction and assemble its EVM context - blockHash, err := api._blockReader.CanonicalHash(ctx, dbtx, blockNum) + blockHash, ok, err := api._blockReader.CanonicalHash(ctx, dbtx, blockNum) if err != nil { return false, nil, err } + if !ok { + return false, nil, fmt.Errorf("canonical hash not found %d", blockNum) + } block, err := api.blockWithSenders(ctx, dbtx, blockHash, blockNum) if err != nil { diff --git a/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce.go b/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce.go index eeee12dde3c..292e9db274e 100644 --- a/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce.go +++ b/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce.go @@ -166,10 +166,13 @@ func (api *OtterscanAPIImpl) GetTransactionBySenderAndNonce(ctx context.Context, } func (api *OtterscanAPIImpl) findNonce(ctx context.Context, tx kv.Tx, addr common.Address, nonce uint64, blockNum uint64) (bool, common.Hash, error) { - hash, err := api._blockReader.CanonicalHash(ctx, tx, blockNum) + hash, ok, err := api._blockReader.CanonicalHash(ctx, tx, blockNum) if err != nil { return false, common.Hash{}, err } + if !ok { + return false, common.Hash{}, fmt.Errorf("canonical hash not found: %d", blockNum) + } block, err := api.blockWithSenders(ctx, tx, hash, blockNum) if err != nil { return false, common.Hash{}, err diff --git a/turbo/jsonrpc/overlay_api.go b/turbo/jsonrpc/overlay_api.go index a634c33eeaf..cbdbaec7c49 100644 --- a/turbo/jsonrpc/overlay_api.go +++ b/turbo/jsonrpc/overlay_api.go @@ -167,9 +167,9 @@ func (api *OverlayAPIImpl) CallConstructor(ctx context.Context, address common.A if hash, ok := overrideBlockHash[i]; ok { return hash } - hash, err := api._blockReader.CanonicalHash(ctx, tx, i) - if err != nil { - log.Debug("Can't get block hash by number", "number", i, "only-canonical", true) + hash, ok, err := api._blockReader.CanonicalHash(ctx, tx, i) + if err != nil || !ok { + log.Debug("Can't get block hash by number", "number", i, "only-canonical", true, "err", err, "ok", ok) } return hash } @@ -443,9 +443,9 @@ func (api *OverlayAPIImpl) replayBlock(ctx context.Context, blockNum uint64, sta if hash, ok := overrideBlockHash[i]; ok { return hash } - hash, err := api._blockReader.CanonicalHash(ctx, tx, i) - if err != nil { - log.Debug("Can't get block hash by number", "number", i, "only-canonical", true) + hash, ok, err := api._blockReader.CanonicalHash(ctx, tx, i) + if err != nil || !ok { + log.Debug("Can't get block hash by number", "number", i, "only-canonical", true, "err", err, "ok", ok) } return hash } diff --git a/turbo/jsonrpc/tracing.go b/turbo/jsonrpc/tracing.go index 41ab5ec046f..07c70dd2cb2 100644 --- a/turbo/jsonrpc/tracing.go +++ b/turbo/jsonrpc/tracing.go @@ -498,9 +498,9 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun if hash, ok := overrideBlockHash[i]; ok { return hash } - hash, err := api._blockReader.CanonicalHash(ctx, tx, i) - if err != nil { - log.Debug("Can't get block hash by number", "number", i, "only-canonical", true) + hash, ok, err := api._blockReader.CanonicalHash(ctx, tx, i) + if err != nil || !ok { + log.Debug("Can't get block hash by number", "number", i, "only-canonical", true, "err", err, "ok", ok) } return hash } diff --git a/turbo/rpchelper/helper.go b/turbo/rpchelper/helper.go index f93130487ac..ae7988829fe 100644 --- a/turbo/rpchelper/helper.go +++ b/turbo/rpchelper/helper.go @@ -46,19 +46,21 @@ func (e nonCanonocalHashError) Error() string { } func GetBlockNumber(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, tx kv.Tx, br services.FullBlockReader, filters *Filters) (uint64, libcommon.Hash, bool, error) { - return _GetBlockNumber(ctx, blockNrOrHash.RequireCanonical, blockNrOrHash, tx, br, filters) + bn, bh, latest, _, err := _GetBlockNumber(ctx, blockNrOrHash.RequireCanonical, blockNrOrHash, tx, br, filters) + return bn, bh, latest, err } func GetCanonicalBlockNumber(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, tx kv.Tx, br services.FullBlockReader, filters *Filters) (uint64, libcommon.Hash, bool, error) { - return _GetBlockNumber(ctx, true, blockNrOrHash, tx, br, filters) + bn, bh, latest, _, err := _GetBlockNumber(ctx, blockNrOrHash.RequireCanonical, blockNrOrHash, tx, br, filters) + return bn, bh, latest, err } -func _GetBlockNumber(ctx context.Context, requireCanonical bool, blockNrOrHash rpc.BlockNumberOrHash, tx kv.Tx, br services.FullBlockReader, filters *Filters) (blockNumber uint64, hash libcommon.Hash, latest bool, err error) { +func _GetBlockNumber(ctx context.Context, requireCanonical bool, blockNrOrHash rpc.BlockNumberOrHash, tx kv.Tx, br services.FullBlockReader, filters *Filters) (blockNumber uint64, hash libcommon.Hash, latest bool, found bool, err error) { // Due to changed semantics of `lastest` block in RPC request, it is now distinct // from the block number corresponding to the plain state var plainStateBlockNumber uint64 if plainStateBlockNumber, err = stages.GetStageProgress(tx, stages.Execution); err != nil { - return 0, libcommon.Hash{}, false, fmt.Errorf("getting plain state block number: %w", err) + return 0, libcommon.Hash{}, false, false, fmt.Errorf("getting plain state block number: %w", err) } var ok bool hash, ok = blockNrOrHash.Hash() @@ -67,7 +69,7 @@ func _GetBlockNumber(ctx context.Context, requireCanonical bool, blockNrOrHash r switch number { case rpc.LatestBlockNumber: if blockNumber, err = GetLatestBlockNumber(tx); err != nil { - return 0, libcommon.Hash{}, false, err + return 0, libcommon.Hash{}, false, false, err } case rpc.EarliestBlockNumber: blockNumber = 0 @@ -76,61 +78,64 @@ func _GetBlockNumber(ctx context.Context, requireCanonical bool, blockNrOrHash r num := borfinality.GetFinalizedBlockNumber(tx) if num == 0 { // nolint - return 0, libcommon.Hash{}, false, errors.New("No finalized block") + return 0, libcommon.Hash{}, false, false, errors.New("No finalized block") } blockNum := borfinality.CurrentFinalizedBlock(tx, num).NumberU64() blockHash := rawdb.ReadHeaderByNumber(tx, blockNum).Hash() - return blockNum, blockHash, false, nil + return blockNum, blockHash, false, false, nil } blockNumber, err = GetFinalizedBlockNumber(tx) if err != nil { - return 0, libcommon.Hash{}, false, err + return 0, libcommon.Hash{}, false, false, err } case rpc.SafeBlockNumber: blockNumber, err = GetSafeBlockNumber(tx) if err != nil { - return 0, libcommon.Hash{}, false, err + return 0, libcommon.Hash{}, false, false, err } case rpc.PendingBlockNumber: pendingBlock := filters.LastPendingBlock() if pendingBlock == nil { blockNumber = plainStateBlockNumber } else { - return pendingBlock.NumberU64(), pendingBlock.Hash(), false, nil + return pendingBlock.NumberU64(), pendingBlock.Hash(), false, true, nil } case rpc.LatestExecutedBlockNumber: blockNumber = plainStateBlockNumber default: blockNumber = uint64(number.Int64()) } - hash, err = br.CanonicalHash(ctx, tx, blockNumber) + hash, ok, err = br.CanonicalHash(ctx, tx, blockNumber) if err != nil { - return 0, libcommon.Hash{}, false, err + return 0, libcommon.Hash{}, false, false, err + } + if !ok { + return 0, libcommon.Hash{}, false, false, nil } } else { number, err := br.HeaderNumber(ctx, tx, hash) if err != nil { - return 0, libcommon.Hash{}, false, err + return 0, libcommon.Hash{}, false, false, err } if number == nil { - return 0, libcommon.Hash{}, false, fmt.Errorf("block %x not found", hash) + return 0, libcommon.Hash{}, false, false, fmt.Errorf("block %x not found", hash) } blockNumber = *number - ch, err := br.CanonicalHash(ctx, tx, blockNumber) + ch, ok, err := br.CanonicalHash(ctx, tx, blockNumber) if err != nil { - return 0, libcommon.Hash{}, false, err + return 0, libcommon.Hash{}, false, false, err } - if requireCanonical && ch != hash { - return 0, libcommon.Hash{}, false, nonCanonocalHashError{hash} + if requireCanonical && (!ok || ch != hash) { + return 0, libcommon.Hash{}, false, false, nonCanonocalHashError{hash} } } - return blockNumber, hash, blockNumber == plainStateBlockNumber, nil + return blockNumber, hash, blockNumber == plainStateBlockNumber, true, nil } func CreateStateReader(ctx context.Context, tx kv.Tx, br services.FullBlockReader, blockNrOrHash rpc.BlockNumberOrHash, txnIndex int, filters *Filters, stateCache kvcache.Cache, chainName string) (state.StateReader, error) { - blockNumber, _, latest, err := _GetBlockNumber(ctx, true, blockNrOrHash, tx, br, filters) + blockNumber, _, latest, _, err := _GetBlockNumber(ctx, true, blockNrOrHash, tx, br, filters) if err != nil { return nil, err } diff --git a/turbo/services/interfaces.go b/turbo/services/interfaces.go index fbbece6f1ff..dcb7ca661dd 100644 --- a/turbo/services/interfaces.go +++ b/turbo/services/interfaces.go @@ -80,7 +80,7 @@ type BorCheckpointReader interface { } type CanonicalReader interface { - CanonicalHash(ctx context.Context, tx kv.Getter, blockNum uint64) (common.Hash, error) + CanonicalHash(ctx context.Context, tx kv.Getter, blockNum uint64) (h common.Hash, ok bool, err error) IsCanonical(ctx context.Context, tx kv.Getter, hash common.Hash, blockNum uint64) (bool, error) BadHeaderNumber(ctx context.Context, tx kv.Getter, hash common.Hash) (blockHeight *uint64, err error) } diff --git a/turbo/snapshotsync/freezeblocks/block_reader.go b/turbo/snapshotsync/freezeblocks/block_reader.go index c0953f2ab71..656eae2f665 100644 --- a/turbo/snapshotsync/freezeblocks/block_reader.go +++ b/turbo/snapshotsync/freezeblocks/block_reader.go @@ -95,11 +95,11 @@ func (r *RemoteBlockReader) BadHeaderNumber(ctx context.Context, tx kv.Getter, h } func (r *RemoteBlockReader) BlockByNumber(ctx context.Context, db kv.Tx, number uint64) (*types.Block, error) { - hash, err := r.CanonicalHash(ctx, db, number) + hash, ok, err := r.CanonicalHash(ctx, db, number) if err != nil { return nil, fmt.Errorf("failed ReadCanonicalHash: %w", err) } - if hash == (common.Hash{}) { + if !ok { return nil, nil } block, _, err := r.BlockWithSenders(ctx, db, hash, number) @@ -117,10 +117,13 @@ func (r *RemoteBlockReader) BlockByHash(ctx context.Context, db kv.Tx, hash comm return block, err } func (r *RemoteBlockReader) HeaderByNumber(ctx context.Context, tx kv.Getter, blockHeight uint64) (*types.Header, error) { - canonicalHash, err := r.CanonicalHash(ctx, tx, blockHeight) + canonicalHash, ok, err := r.CanonicalHash(ctx, tx, blockHeight) if err != nil { return nil, err } + if !ok { + return nil, nil + } block, _, err := r.BlockWithSenders(ctx, tx, canonicalHash, blockHeight) if err != nil { return nil, err @@ -150,12 +153,16 @@ func (r *RemoteBlockReader) HeaderByHash(ctx context.Context, tx kv.Getter, hash return block.Header(), nil } -func (r *RemoteBlockReader) CanonicalHash(ctx context.Context, tx kv.Getter, blockHeight uint64) (common.Hash, error) { - resp, err := r.client.CanonicalHash(ctx, &remote.CanonicalHashRequest{BlockNumber: blockHeight}) +func (r *RemoteBlockReader) CanonicalHash(ctx context.Context, tx kv.Getter, blockHeight uint64) (h common.Hash, ok bool, err error) { + reply, err := r.client.CanonicalHash(ctx, &remote.CanonicalHashRequest{BlockNumber: blockHeight}) if err != nil { - return common.Hash{}, err + return common.Hash{}, false, err + } + if reply == nil || reply.Hash == nil { + return h, false, nil } - return gointerfaces.ConvertH256ToHash(resp.Hash), nil + h = gointerfaces.ConvertH256ToHash(reply.Hash) + return h, h != emptyHash, nil } var _ services.FullBlockReader = &RemoteBlockReader{} @@ -176,10 +183,13 @@ func (r *RemoteBlockReader) TxnLookup(ctx context.Context, tx kv.Getter, txnHash } func (r *RemoteBlockReader) TxnByIdxInBlock(ctx context.Context, tx kv.Getter, blockNum uint64, i int) (txn types.Transaction, err error) { - canonicalHash, err := r.CanonicalHash(ctx, tx, blockNum) + canonicalHash, ok, err := r.CanonicalHash(ctx, tx, blockNum) if err != nil { return nil, err } + if !ok { + return nil, nil + } b, err := r.BodyWithTransactions(ctx, tx, canonicalHash, blockNum) if err != nil { return nil, err @@ -246,10 +256,13 @@ func (r *RemoteBlockReader) Body(ctx context.Context, tx kv.Getter, hash common. return block.Body(), uint32(len(block.Body().Transactions)), nil } func (r *RemoteBlockReader) IsCanonical(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (bool, error) { - expected, err := r.CanonicalHash(ctx, tx, blockHeight) + expected, ok, err := r.CanonicalHash(ctx, tx, blockHeight) if err != nil { return false, err } + if !ok { + return false, nil + } return expected == hash, nil } func (r *RemoteBlockReader) BodyWithTransactions(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (body *types.Body, err error) { @@ -493,11 +506,11 @@ func (r *BlockReader) HeaderNumber(ctx context.Context, tx kv.Getter, hash commo return ret, nil } func (r *BlockReader) IsCanonical(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (bool, error) { - expected, err := r.CanonicalHash(ctx, tx, blockHeight) + expected, ok, err := r.CanonicalHash(ctx, tx, blockHeight) if err != nil { return false, err } - return expected == hash, nil + return ok && expected == hash, nil } // HeaderByHash - will search header in all snapshots starting from recent @@ -529,30 +542,30 @@ func (r *BlockReader) HeaderByHash(ctx context.Context, tx kv.Getter, hash commo var emptyHash = common.Hash{} -func (r *BlockReader) CanonicalHash(ctx context.Context, tx kv.Getter, blockHeight uint64) (h common.Hash, err error) { +func (r *BlockReader) CanonicalHash(ctx context.Context, tx kv.Getter, blockHeight uint64) (h common.Hash, ok bool, err error) { h, err = rawdb.ReadCanonicalHash(tx, blockHeight) if err != nil { - return emptyHash, err + return emptyHash, false, err } if h != emptyHash { - return h, nil + return h, true, nil } seg, ok, release := r.sn.ViewSingleFile(coresnaptype.Headers, blockHeight) if !ok { - return h, nil + return h, false, nil } defer release() header, _, err := r.headerFromSnapshot(blockHeight, seg, nil) if err != nil { - return h, err + return h, false, err } if header == nil { - return h, nil + return h, false, nil } h = header.Hash() - return h, nil + return h, true, nil } func (r *BlockReader) Header(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (h *types.Header, err error) { @@ -715,10 +728,13 @@ func (r *BlockReader) BlockWithSenders(ctx context.Context, tx kv.Getter, hash c func (r *BlockReader) CanonicalBodyForStorage(ctx context.Context, tx kv.Getter, blockNum uint64) (body *types.BodyForStorage, err error) { bodySeg, ok, release := r.sn.ViewSingleFile(coresnaptype.Bodies, blockNum) if !ok { - hash, err := r.CanonicalHash(ctx, tx, blockNum) + hash, ok, err := r.CanonicalHash(ctx, tx, blockNum) if err != nil { return nil, err } + if !ok { + return nil, nil + } return rawdb.ReadBodyForStorageByKey(tx, dbutils.BlockBodyKey(blockNum, hash)) } defer release() @@ -743,11 +759,11 @@ func (r *BlockReader) blockWithSenders(ctx context.Context, tx kv.Getter, hash c return nil, nil, nil } if forceCanonical { - canonicalHash, err := r.CanonicalHash(ctx, tx, blockHeight) + canonicalHash, ok, err := r.CanonicalHash(ctx, tx, blockHeight) if err != nil { return nil, nil, fmt.Errorf("requested non-canonical hash %x. canonical=%x", hash, canonicalHash) } - if canonicalHash != hash { + if !ok || canonicalHash != hash { if dbgLogs { log.Info(dbgPrefix + fmt.Sprintf("this hash is not canonical now. current one is %x", canonicalHash)) } @@ -1097,10 +1113,13 @@ func (r *BlockReader) txnByHash(txnHash common.Hash, segments []*VisibleSegment, func (r *BlockReader) TxnByIdxInBlock(ctx context.Context, tx kv.Getter, blockNum uint64, txIdxInBlock int) (txn types.Transaction, err error) { maxBlockNumInFiles := r.sn.BlocksAvailable() if maxBlockNumInFiles == 0 || blockNum > maxBlockNumInFiles { - canonicalHash, err := r.CanonicalHash(ctx, tx, blockNum) + canonicalHash, ok, err := r.CanonicalHash(ctx, tx, blockNum) if err != nil { return nil, err } + if !ok { + return nil, nil + } return rawdb.TxnByIdxInBlock(tx, canonicalHash, blockNum, txIdxInBlock) } @@ -1281,20 +1300,20 @@ func (r *BlockReader) ReadAncestor(db kv.Getter, hash common.Hash, number, ances return common.Hash{}, 0 } for ancestor != 0 { - h, err := r.CanonicalHash(context.Background(), db, number) + h, ok, err := r.CanonicalHash(context.Background(), db, number) if err != nil { panic(err) } - if h == hash { - ancestorHash, err := r.CanonicalHash(context.Background(), db, number-ancestor) + if ok && h == hash { + ancestorHash, ok1, err := r.CanonicalHash(context.Background(), db, number-ancestor) if err != nil { panic(err) } - h, err := r.CanonicalHash(context.Background(), db, number) + h, ok2, err := r.CanonicalHash(context.Background(), db, number) if err != nil { panic(err) } - if h == hash { + if ok1 && ok2 && h == hash { number -= ancestor return ancestorHash, number } diff --git a/turbo/stages/blockchain_test.go b/turbo/stages/blockchain_test.go index cd35629ad11..9da9f3556b1 100644 --- a/turbo/stages/blockchain_test.go +++ b/turbo/stages/blockchain_test.go @@ -103,7 +103,7 @@ func testFork(t *testing.T, m *mock.MockSentry, i, n int, comparator func(td1, t // Assert the chains have the same header/block at #i var hash1, hash2 libcommon.Hash err = m.DB.View(m.Ctx, func(tx kv.Tx) error { - if hash1, err = m.BlockReader.CanonicalHash(m.Ctx, tx, uint64(i)); err != nil { + if hash1, _, err = m.BlockReader.CanonicalHash(m.Ctx, tx, uint64(i)); err != nil { t.Fatalf("Failed to read canonical hash: %v", err) } if block1, _, _ := m.BlockReader.BlockWithSenders(ctx, tx, hash1, uint64(i)); block1 == nil { @@ -114,7 +114,7 @@ func testFork(t *testing.T, m *mock.MockSentry, i, n int, comparator func(td1, t require.NoError(t, err) canonicalMock.DB.View(ctx, func(tx kv.Tx) error { - if hash2, err = m.BlockReader.CanonicalHash(m.Ctx, tx, uint64(i)); err != nil { + if hash2, _, err = m.BlockReader.CanonicalHash(m.Ctx, tx, uint64(i)); err != nil { t.Fatalf("Failed to read canonical hash: %v", err) } if block2, _, _ := m.BlockReader.BlockWithSenders(ctx, tx, hash2, uint64(i)); block2 == nil { @@ -589,7 +589,7 @@ func readReceipt(db kv.Tx, txHash libcommon.Hash, m *mock.MockSentry) (*types.Re if blockNumber == nil { return nil, libcommon.Hash{}, 0, 0, nil } - blockHash, err := m.BlockReader.CanonicalHash(context.Background(), db, *blockNumber) + blockHash, _, err := m.BlockReader.CanonicalHash(context.Background(), db, *blockNumber) if err != nil { return nil, libcommon.Hash{}, 0, 0, err } @@ -633,7 +633,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) { for _, block := range chain.Blocks { // try to retrieve a block by its canonical hash and see if the block data can be retrieved. - ch, err := m.BlockReader.CanonicalHash(m.Ctx, tx, block.NumberU64()) + ch, _, err := m.BlockReader.CanonicalHash(m.Ctx, tx, block.NumberU64()) require.NoError(t, err) if err != nil { panic(err) diff --git a/turbo/stages/bodydownload/body_algos.go b/turbo/stages/bodydownload/body_algos.go index b5f8d068f54..86599929ff3 100644 --- a/turbo/stages/bodydownload/body_algos.go +++ b/turbo/stages/bodydownload/body_algos.go @@ -61,10 +61,14 @@ func (bd *BodyDownload) UpdateFromDb(db kv.Tx) (headHeight, headTime uint64, hea maps.Clear(bd.peerMap) bd.ClearBodyCache() headHeight = bodyProgress - headHash, err = bd.br.CanonicalHash(context.Background(), db, headHeight) + var ok bool + headHash, ok, err = bd.br.CanonicalHash(context.Background(), db, headHeight) if err != nil { return 0, 0, libcommon.Hash{}, nil, err } + if !ok { + return 0, 0, libcommon.Hash{}, nil, fmt.Errorf("canonical marker not found: %d", headHeight) + } var headTd *big.Int headTd, err = rawdb.ReadTd(db, headHash, headHeight) if err != nil { @@ -137,10 +141,14 @@ func (bd *BodyDownload) RequestMoreBodies(tx kv.RwTx, blockReader services.FullB request = false } } else { - hash, err = blockReader.CanonicalHash(context.Background(), tx, blockNum) + var ok bool + hash, ok, err = blockReader.CanonicalHash(context.Background(), tx, blockNum) if err != nil { return nil, fmt.Errorf("could not find canonical header: %w, blockNum=%d, trace=%s", err, blockNum, dbg.Stack()) } + if !ok { + return nil, fmt.Errorf("CanonicalHash not found: blockNum=%d, trace=%s", blockNum, dbg.Stack()) + } header, err = blockReader.Header(context.Background(), tx, hash, blockNum) if err != nil { diff --git a/turbo/stages/headerdownload/header_algos.go b/turbo/stages/headerdownload/header_algos.go index 3332710a049..2eaa685577f 100644 --- a/turbo/stages/headerdownload/header_algos.go +++ b/turbo/stages/headerdownload/header_algos.go @@ -851,9 +851,13 @@ func (hi *HeaderInserter) ForkingPoint(db kv.StatelessRwTx, header, parent *type if fromCache, ok := hi.canonicalCache.Get(blockHeight - 1); ok { ch = fromCache } else { - if ch, err = hi.headerReader.CanonicalHash(context.Background(), db, blockHeight-1); err != nil { + if ch, ok, err = hi.headerReader.CanonicalHash(context.Background(), db, blockHeight-1); err != nil { return 0, fmt.Errorf("reading canonical hash for height %d: %w", blockHeight-1, err) } + if !ok { + log.Warn("[dbg] HeaderInserter.ForkPoint0", "blockHeight", blockHeight) + } + } if ch == header.ParentHash { forkingPoint = blockHeight - 1 @@ -879,7 +883,7 @@ func (hi *HeaderInserter) ForkingPoint(db kv.StatelessRwTx, header, parent *type } // Now look in the DB for { - ch, err := hi.headerReader.CanonicalHash(context.Background(), db, ancestorHeight) + ch, _, err := hi.headerReader.CanonicalHash(context.Background(), db, ancestorHeight) if err != nil { return 0, fmt.Errorf("[%s] reading canonical hash for %d: %w", hi.logPrefix, ancestorHeight, err) } @@ -890,6 +894,9 @@ func (hi *HeaderInserter) ForkingPoint(db kv.StatelessRwTx, header, parent *type if err != nil { return 0, err } + if ancestor == nil { + return 0, fmt.Errorf("[%s] not found header: %d, %x", hi.logPrefix, ancestorHeight, ancestorHash) + } ancestorHash = ancestor.ParentHash ancestorHeight-- }