From 9501f9370d1d073a264db09c547c7535d0e7f900 Mon Sep 17 00:00:00 2001 From: battlmonstr Date: Tue, 28 May 2024 11:36:26 +0200 Subject: [PATCH] p2p/sentry: sentry doesn't start with ErrNoHead (#10454) (#10523) cherry-pick https://github.com/ledgerwatch/erigon/pull/10494 to release/2.60 --- cmd/integration/commands/stages.go | 1 + eth/backend.go | 1 + .../sentry_multi_client.go | 4 +- p2p/sentry/status_data_provider.go | 53 ++++++++++++++----- turbo/stages/mock/mock_sentry.go | 1 + 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/cmd/integration/commands/stages.go b/cmd/integration/commands/stages.go index d2a4b54d493..428903d3fab 100644 --- a/cmd/integration/commands/stages.go +++ b/cmd/integration/commands/stages.go @@ -1621,6 +1621,7 @@ func newSync(ctx context.Context, db kv.RwDB, miningConfig *params.MiningConfig, chainConfig, genesisBlock, chainConfig.ChainID.Uint64(), + logger, ) maxBlockBroadcastPeers := func(header *types.Header) uint { return 0 } diff --git a/eth/backend.go b/eth/backend.go index 4816822d42d..ea632176776 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -573,6 +573,7 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger chainConfig, genesis, backend.config.NetworkID, + logger, ) // limit "new block" broadcasts to at most 10 random peers at time diff --git a/p2p/sentry/sentry_multi_client/sentry_multi_client.go b/p2p/sentry/sentry_multi_client/sentry_multi_client.go index ef62bfaa84a..0f32615b949 100644 --- a/p2p/sentry/sentry_multi_client/sentry_multi_client.go +++ b/p2p/sentry/sentry_multi_client/sentry_multi_client.go @@ -156,9 +156,7 @@ func SentryReconnectAndPumpStreamLoop[TMessage interface{}]( statusData, err := statusDataFactory(ctx) if err != nil { - if !errors.Is(err, sentry.ErrNoHead) { - logger.Error("SentryReconnectAndPumpStreamLoop: statusDataFactory error", "stream", streamName, "err", err) - } + logger.Error("SentryReconnectAndPumpStreamLoop: statusDataFactory error", "stream", streamName, "err", err) time.Sleep(time.Second) continue } diff --git a/p2p/sentry/status_data_provider.go b/p2p/sentry/status_data_provider.go index 91137e5c321..83da0d3bad3 100644 --- a/p2p/sentry/status_data_provider.go +++ b/p2p/sentry/status_data_provider.go @@ -7,6 +7,7 @@ import ( "math/big" "github.com/holiman/uint256" + "github.com/ledgerwatch/log/v3" "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" @@ -32,8 +33,11 @@ type StatusDataProvider struct { networkId uint64 genesisHash libcommon.Hash + genesisHead ChainHead heightForks []uint64 timeForks []uint64 + + logger log.Logger } func NewStatusDataProvider( @@ -41,11 +45,14 @@ func NewStatusDataProvider( chainConfig *chain.Config, genesis *types.Block, networkId uint64, + logger log.Logger, ) *StatusDataProvider { s := &StatusDataProvider{ db: db, networkId: networkId, genesisHash: genesis.Hash(), + genesisHead: makeGenesisChainHead(genesis), + logger: logger, } s.heightForks, s.timeForks = forkid.GatherForks(chainConfig, genesis.Time()) @@ -53,6 +60,32 @@ func NewStatusDataProvider( return s } +func uint256FromBigInt(num *big.Int) (*uint256.Int, error) { + if num == nil { + num = new(big.Int) + } + num256 := new(uint256.Int) + overflow := num256.SetFromBig(num) + if overflow { + return nil, fmt.Errorf("uint256FromBigInt: big.Int greater than 2^256-1") + } + return num256, nil +} + +func makeGenesisChainHead(genesis *types.Block) ChainHead { + genesisDifficulty, err := uint256FromBigInt(genesis.Difficulty()) + if err != nil { + panic(fmt.Errorf("makeGenesisChainHead: difficulty conversion error: %w", err)) + } + + return ChainHead{ + HeadHeight: genesis.NumberU64(), + HeadTime: genesis.Time(), + HeadHash: genesis.Hash(), + HeadTd: genesisDifficulty, + } +} + func (s *StatusDataProvider) makeStatusData(head ChainHead) *proto_sentry.StatusData { return &proto_sentry.StatusData{ NetworkId: s.networkId, @@ -71,6 +104,10 @@ func (s *StatusDataProvider) makeStatusData(head ChainHead) *proto_sentry.Status func (s *StatusDataProvider) GetStatusData(ctx context.Context) (*proto_sentry.StatusData, error) { chainHead, err := ReadChainHead(ctx, s.db) if err != nil { + if errors.Is(err, ErrNoHead) { + s.logger.Warn("sentry.StatusDataProvider: The canonical chain current header not found in the database. Check the database consistency. Using genesis as a fallback.") + return s.makeStatusData(s.genesisHead), nil + } return nil, err } return s.makeStatusData(chainHead), err @@ -84,23 +121,15 @@ func ReadChainHeadWithTx(tx kv.Tx) (ChainHead, error) { height := header.Number.Uint64() hash := header.Hash() - - var time uint64 - if header != nil { - time = header.Time - } + time := header.Time td, err := rawdb.ReadTd(tx, hash, height) if err != nil { return ChainHead{}, fmt.Errorf("ReadChainHead: ReadTd error at height %d and hash %s: %w", height, hash, err) } - if td == nil { - td = new(big.Int) - } - td256 := new(uint256.Int) - overflow := td256.SetFromBig(td) - if overflow { - return ChainHead{}, fmt.Errorf("ReadChainHead: total difficulty higher than 2^256-1") + td256, err := uint256FromBigInt(td) + if err != nil { + return ChainHead{}, fmt.Errorf("ReadChainHead: total difficulty conversion error: %w", err) } return ChainHead{height, time, hash, td256}, nil diff --git a/turbo/stages/mock/mock_sentry.go b/turbo/stages/mock/mock_sentry.go index 3994c6508b6..8eab77cdf6e 100644 --- a/turbo/stages/mock/mock_sentry.go +++ b/turbo/stages/mock/mock_sentry.go @@ -371,6 +371,7 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK mock.ChainConfig, mock.Genesis, mock.ChainConfig.ChainID.Uint64(), + logger, ) maxBlockBroadcastPeers := func(header *types.Header) uint { return 0 }