From 9e7c1d6af6bbefb506a358fdbb5d07d0e516aebd Mon Sep 17 00:00:00 2001 From: Rupam Dey Date: Fri, 27 Dec 2024 02:16:29 +0530 Subject: [PATCH] Light client: add better error handling (#14749) * add better error handling * changelog --- CHANGELOG.md | 1 + .../blockchain/process_block_helpers.go | 45 ++++++++++++------- beacon-chain/core/light-client/lightclient.go | 9 +++- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bf522c3fe5..411b497f842 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,7 @@ Notable features: - Save light client updates and bootstraps in DB. - Added more comprehensive tests for `BlockToLightClientHeader`. [PR](https://github.com/prysmaticlabs/prysm/pull/14699) - Added light client feature flag check to RPC handlers. [PR](https://github.com/prysmaticlabs/prysm/pull/14736) +- Light client: Add better error handling. [PR](https://github.com/prysmaticlabs/prysm/pull/14749) ### Changed diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 97c195d1136..e4a37ff4b22 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "strings" "time" lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client" @@ -129,7 +130,7 @@ func (s *Service) saveLightClientUpdate(cfg *postBlockProcessConfig) { attestedRoot := cfg.roblock.Block().ParentRoot() attestedBlock, err := s.getBlock(cfg.ctx, attestedRoot) if err != nil { - log.WithError(err).Error("Saving light client update failed: Could not get attested block") + log.WithError(err).Errorf("Saving light client update failed: Could not get attested block for root %#x", attestedRoot) return } if attestedBlock == nil || attestedBlock.IsNil() { @@ -138,7 +139,7 @@ func (s *Service) saveLightClientUpdate(cfg *postBlockProcessConfig) { } attestedState, err := s.cfg.StateGen.StateByRoot(cfg.ctx, attestedRoot) if err != nil { - log.WithError(err).Error("Saving light client update failed: Could not get attested state") + log.WithError(err).Errorf("Saving light client update failed: Could not get attested state for root %#x", attestedRoot) return } if attestedState == nil || attestedState.IsNil() { @@ -149,7 +150,11 @@ func (s *Service) saveLightClientUpdate(cfg *postBlockProcessConfig) { finalizedRoot := attestedState.FinalizedCheckpoint().Root finalizedBlock, err := s.getBlock(cfg.ctx, [32]byte(finalizedRoot)) if err != nil { - log.WithError(err).Error("Saving light client update failed: Could not get finalized block") + if errors.Is(err, errBlockNotFoundInCacheOrDB) { + log.Debugf("Skipping saving light client update: Finalized block is nil for root %#x", finalizedRoot) + } else { + log.WithError(err).Errorf("Saving light client update failed: Could not get finalized block for root %#x", finalizedRoot) + } return } @@ -224,28 +229,30 @@ func (s *Service) processLightClientFinalityUpdate( attestedRoot := signed.Block().ParentRoot() attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot) if err != nil { - return errors.Wrap(err, "could not get attested block") + return errors.Wrapf(err, "could not get attested block for root %#x", attestedRoot) } attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot) if err != nil { - return errors.Wrap(err, "could not get attested state") + return errors.Wrapf(err, "could not get attested state for root %#x", attestedRoot) } - var finalizedBlock interfaces.ReadOnlySignedBeaconBlock - finalizedCheckPoint := attestedState.FinalizedCheckpoint() - if finalizedCheckPoint != nil { - finalizedRoot := bytesutil.ToBytes32(finalizedCheckPoint.Root) - finalizedBlock, err = s.cfg.BeaconDB.Block(ctx, finalizedRoot) - if err != nil { - finalizedBlock = nil - } - } + finalizedCheckpoint := attestedState.FinalizedCheckpoint() // Check if the finalized checkpoint has changed - if finalizedCheckPoint == nil || bytes.Equal(finalizedCheckPoint.GetRoot(), postState.FinalizedCheckpoint().Root) { + if finalizedCheckpoint == nil || bytes.Equal(finalizedCheckpoint.GetRoot(), postState.FinalizedCheckpoint().Root) { return nil } + finalizedRoot := bytesutil.ToBytes32(finalizedCheckpoint.Root) + finalizedBlock, err := s.cfg.BeaconDB.Block(ctx, finalizedRoot) + if err != nil { + if errors.Is(err, errBlockNotFoundInCacheOrDB) { + log.Debugf("Skipping processing light client finality update: Finalized block is nil for root %#x", finalizedRoot) + return nil + } + return errors.Wrapf(err, "could not get finalized block for root %#x", finalizedRoot) + } + update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState( ctx, postState.Slot(), @@ -272,11 +279,11 @@ func (s *Service) processLightClientOptimisticUpdate(ctx context.Context, signed attestedRoot := signed.Block().ParentRoot() attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot) if err != nil { - return errors.Wrap(err, "could not get attested block") + return errors.Wrapf(err, "could not get attested block for root %#x", attestedRoot) } attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot) if err != nil { - return errors.Wrap(err, "could not get attested state") + return errors.Wrapf(err, "could not get attested state for root %#x", attestedRoot) } update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState( @@ -289,6 +296,10 @@ func (s *Service) processLightClientOptimisticUpdate(ctx context.Context, signed ) if err != nil { + if strings.Contains(err.Error(), lightclient.ErrNotEnoughSyncCommitteeBits) { + log.WithError(err).Debug("Skipping processing light client optimistic update") + return nil + } return errors.Wrap(err, "could not create light client optimistic update") } diff --git a/beacon-chain/core/light-client/lightclient.go b/beacon-chain/core/light-client/lightclient.go index 6abf7d7c51c..c5518aecc4a 100644 --- a/beacon-chain/core/light-client/lightclient.go +++ b/beacon-chain/core/light-client/lightclient.go @@ -24,6 +24,8 @@ import ( "google.golang.org/protobuf/proto" ) +const ErrNotEnoughSyncCommitteeBits = "sync committee bits count is less than required" + func NewLightClientFinalityUpdateFromBeaconState( ctx context.Context, currentSlot primitives.Slot, @@ -84,7 +86,12 @@ func NewLightClientUpdateFromBeaconState( return nil, errors.Wrap(err, "could not get sync aggregate") } if syncAggregate.SyncCommitteeBits.Count() < params.BeaconConfig().MinSyncCommitteeParticipants { - return nil, fmt.Errorf("invalid sync committee bits count %d", syncAggregate.SyncCommitteeBits.Count()) + return nil, fmt.Errorf( + "%s (got %d, need %d)", + ErrNotEnoughSyncCommitteeBits, + syncAggregate.SyncCommitteeBits.Count(), + params.BeaconConfig().MinSyncCommitteeParticipants, + ) } // assert state.slot == state.latest_block_header.slot