diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index 122737e304..57248774af 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice" doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree" @@ -79,9 +81,9 @@ type CanonicalFetcher interface { // FinalizationFetcher defines a common interface for methods in blockchain service which // directly retrieve finalization and justification related data. type FinalizationFetcher interface { - FinalizedCheckpt() *ethpb.Checkpoint - CurrentJustifiedCheckpt() *ethpb.Checkpoint - PreviousJustifiedCheckpt() *ethpb.Checkpoint + FinalizedCheckpt() (*ethpb.Checkpoint, error) + CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) + PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) VerifyFinalizedBlkDescendant(ctx context.Context, blockRoot [32]byte) error } @@ -92,44 +94,47 @@ type OptimisticModeFetcher interface { } // FinalizedCheckpt returns the latest finalized checkpoint from chain store. -func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint { - cp := s.store.FinalizedCheckpt() - if cp == nil { - return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} +func (s *Service) FinalizedCheckpt() (*ethpb.Checkpoint, error) { + cp, err := s.store.FinalizedCheckpt() + if err != nil { + return nil, err } - return ethpb.CopyCheckpoint(cp) + return ethpb.CopyCheckpoint(cp), nil } // CurrentJustifiedCheckpt returns the current justified checkpoint from chain store. -func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint { - cp := s.store.JustifiedCheckpt() - if cp == nil { - return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} +func (s *Service) CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) { + cp, err := s.store.JustifiedCheckpt() + if err != nil { + return nil, err } - return ethpb.CopyCheckpoint(cp) + return ethpb.CopyCheckpoint(cp), nil } // PreviousJustifiedCheckpt returns the previous justified checkpoint from chain store. -func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint { - cp := s.store.PrevJustifiedCheckpt() - if cp == nil { - return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} +func (s *Service) PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) { + cp, err := s.store.PrevJustifiedCheckpt() + if err != nil { + return nil, err } - return ethpb.CopyCheckpoint(cp) + return ethpb.CopyCheckpoint(cp), nil } // BestJustifiedCheckpt returns the best justified checkpoint from store. -func (s *Service) BestJustifiedCheckpt() *ethpb.Checkpoint { - cp := s.store.BestJustifiedCheckpt() - // If there is no best justified checkpoint, return the checkpoint with root as zeros to be used for genesis cases. - if cp == nil { - return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} +func (s *Service) BestJustifiedCheckpt() (*ethpb.Checkpoint, error) { + cp, err := s.store.BestJustifiedCheckpt() + if err != nil { + // If there is no best justified checkpoint, return the checkpoint with root as zeros to be used for genesis cases. + if errors.Is(err, store.ErrNilCheckpoint) { + return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, nil + } + return nil, err } - return ethpb.CopyCheckpoint(cp) + return ethpb.CopyCheckpoint(cp), nil } // HeadSlot returns the slot of the head of the chain. diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index f5570c71e1..37e263ded7 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree" "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray" @@ -26,12 +27,6 @@ var _ ChainInfoFetcher = (*Service)(nil) var _ TimeFetcher = (*Service)(nil) var _ ForkFetcher = (*Service)(nil) -func TestFinalizedCheckpt_Nil(t *testing.T) { - beaconDB := testDB.SetupDB(t) - c := setupBeaconChain(t, beaconDB) - assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], c.FinalizedCheckpt().Root, "Incorrect pre chain start value") -} - func TestHeadRoot_Nil(t *testing.T) { beaconDB := testDB.SetupDB(t) c := setupBeaconChain(t, beaconDB) @@ -53,7 +48,9 @@ func TestFinalizedCheckpt_CanRetrieve(t *testing.T) { c := setupBeaconChain(t, beaconDB) c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'}) - assert.Equal(t, cp.Epoch, c.FinalizedCheckpt().Epoch, "Unexpected finalized epoch") + cp, err := c.FinalizedCheckpt() + require.NoError(t, err) + assert.Equal(t, cp.Epoch, cp.Epoch, "Unexpected finalized epoch") } func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) { @@ -64,17 +61,22 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) { c := setupBeaconChain(t, beaconDB) c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'}) c.originBlockRoot = genesisRoot - assert.DeepEqual(t, c.originBlockRoot[:], c.FinalizedCheckpt().Root) + cp, err := c.FinalizedCheckpt() + require.NoError(t, err) + assert.DeepEqual(t, c.originBlockRoot[:], cp.Root) } func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) { beaconDB := testDB.SetupDB(t) c := setupBeaconChain(t, beaconDB) - assert.Equal(t, params.BeaconConfig().ZeroHash, bytesutil.ToBytes32(c.CurrentJustifiedCheckpt().Root), "Unexpected justified epoch") + _, err := c.CurrentJustifiedCheckpt() + require.ErrorIs(t, err, store.ErrNilCheckpoint) cp := ðpb.Checkpoint{Epoch: 6, Root: bytesutil.PadTo([]byte("foo"), 32)} c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{}) - assert.Equal(t, cp.Epoch, c.CurrentJustifiedCheckpt().Epoch, "Unexpected justified epoch") + jp, err := c.CurrentJustifiedCheckpt() + require.NoError(t, err) + assert.Equal(t, cp.Epoch, jp.Epoch, "Unexpected justified epoch") } func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) { @@ -85,7 +87,9 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) { cp := ðpb.Checkpoint{Root: genesisRoot[:]} c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{}) c.originBlockRoot = genesisRoot - assert.DeepEqual(t, c.originBlockRoot[:], c.CurrentJustifiedCheckpt().Root) + cp, err := c.CurrentJustifiedCheckpt() + require.NoError(t, err) + assert.DeepEqual(t, c.originBlockRoot[:], cp.Root) } func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) { @@ -93,9 +97,12 @@ func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) { cp := ðpb.Checkpoint{Epoch: 7, Root: bytesutil.PadTo([]byte("foo"), 32)} c := setupBeaconChain(t, beaconDB) - assert.Equal(t, params.BeaconConfig().ZeroHash, bytesutil.ToBytes32(c.CurrentJustifiedCheckpt().Root), "Unexpected justified epoch") + _, err := c.PreviousJustifiedCheckpt() + require.ErrorIs(t, err, store.ErrNilCheckpoint) c.store.SetPrevJustifiedCheckpt(cp) - assert.Equal(t, cp.Epoch, c.PreviousJustifiedCheckpt().Epoch, "Unexpected previous justified epoch") + pcp, err := c.PreviousJustifiedCheckpt() + require.NoError(t, err) + assert.Equal(t, cp.Epoch, pcp.Epoch, "Unexpected previous justified epoch") } func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) { @@ -106,7 +113,9 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) { c := setupBeaconChain(t, beaconDB) c.store.SetPrevJustifiedCheckpt(cp) c.originBlockRoot = genesisRoot - assert.DeepEqual(t, c.originBlockRoot[:], c.PreviousJustifiedCheckpt().Root) + pcp, err := c.PreviousJustifiedCheckpt() + require.NoError(t, err) + assert.DeepEqual(t, c.originBlockRoot[:], pcp.Root) } func TestHeadSlot_CanRetrieve(t *testing.T) { diff --git a/beacon-chain/blockchain/error.go b/beacon-chain/blockchain/error.go index 0a8acba141..c63a780575 100644 --- a/beacon-chain/blockchain/error.go +++ b/beacon-chain/blockchain/error.go @@ -3,10 +3,6 @@ package blockchain import "github.com/pkg/errors" var ( - // errNilJustifiedInStore is returned when a nil justified checkpt is returned from store. - errNilJustifiedInStore = errors.New("nil justified checkpoint returned from store") - // errNilBestJustifiedInStore is returned when a nil justified checkpt is returned from store. - errNilBestJustifiedInStore = errors.New("nil best justified checkpoint returned from store") // errNilFinalizedInStore is returned when a nil finalized checkpt is returned from store. errNilFinalizedInStore = errors.New("nil finalized checkpoint returned from store") // errInvalidNilSummary is returned when a nil summary is returned from the DB. diff --git a/beacon-chain/blockchain/head.go b/beacon-chain/blockchain/head.go index f817e180b2..92ee6017a3 100644 --- a/beacon-chain/blockchain/head.go +++ b/beacon-chain/blockchain/head.go @@ -27,9 +27,9 @@ import ( // UpdateAndSaveHeadWithBalances updates the beacon state head after getting justified balanced from cache. // This function is only used in spec-tests, it does save the head after updating it. func (s *Service) UpdateAndSaveHeadWithBalances(ctx context.Context) error { - cp := s.store.JustifiedCheckpt() - if cp == nil { - return errors.New("no justified checkpoint") + cp, err := s.store.JustifiedCheckpt() + if err != nil { + return err } balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(cp.Root)) if err != nil { @@ -66,13 +66,13 @@ func (s *Service) updateHead(ctx context.Context, balances []uint64) ([32]byte, defer span.End() // Get head from the fork choice service. - f := s.store.FinalizedCheckpt() - if f == nil { - return [32]byte{}, errNilFinalizedInStore + f, err := s.store.FinalizedCheckpt() + if err != nil { + return [32]byte{}, errors.Wrap(err, "could not get finalized checkpoint") } - j := s.store.JustifiedCheckpt() - if j == nil { - return [32]byte{}, errNilJustifiedInStore + j, err := s.store.JustifiedCheckpt() + if err != nil { + return [32]byte{}, errors.Wrap(err, "could not get justified checkpoint") } // To get head before the first justified epoch, the fork choice will start with origin root // instead of zero hashes. diff --git a/beacon-chain/blockchain/new_slot.go b/beacon-chain/blockchain/new_slot.go index 0c64c24551..c933871f27 100644 --- a/beacon-chain/blockchain/new_slot.go +++ b/beacon-chain/blockchain/new_slot.go @@ -42,17 +42,17 @@ func (s *Service) NewSlot(ctx context.Context, slot types.Slot) error { } // Update store.justified_checkpoint if a better checkpoint on the store.finalized_checkpoint chain - bj := s.store.BestJustifiedCheckpt() - if bj == nil { - return errNilBestJustifiedInStore + bj, err := s.store.BestJustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get best justified checkpoint") } - j := s.store.JustifiedCheckpt() - if j == nil { - return errNilJustifiedInStore + j, err := s.store.JustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get justified checkpoint") } - f := s.store.FinalizedCheckpt() - if f == nil { - return errNilFinalizedInStore + f, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") } if bj.Epoch > j.Epoch { finalizedSlot, err := slots.EpochStart(f.Epoch) diff --git a/beacon-chain/blockchain/new_slot_test.go b/beacon-chain/blockchain/new_slot_test.go index 7d71b1f0df..0e50ae0397 100644 --- a/beacon-chain/blockchain/new_slot_test.go +++ b/beacon-chain/blockchain/new_slot_test.go @@ -103,9 +103,17 @@ func TestService_newSlot(t *testing.T) { require.NoError(t, service.NewSlot(ctx, test.args.slot)) if test.args.shouldEqual { - require.DeepSSZEqual(t, service.store.BestJustifiedCheckpt(), service.store.JustifiedCheckpt()) + bcp, err := service.store.BestJustifiedCheckpt() + require.NoError(t, err) + cp, err := service.store.JustifiedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, bcp, cp) } else { - require.DeepNotSSZEqual(t, service.store.BestJustifiedCheckpt(), service.store.JustifiedCheckpt()) + bcp, err := service.store.BestJustifiedCheckpt() + require.NoError(t, err) + cp, err := service.store.JustifiedCheckpt() + require.NoError(t, err) + require.DeepNotSSZEqual(t, bcp, cp) } } } diff --git a/beacon-chain/blockchain/process_block.go b/beacon-chain/blockchain/process_block.go index 205cf46697..89064badb3 100644 --- a/beacon-chain/blockchain/process_block.go +++ b/beacon-chain/blockchain/process_block.go @@ -176,9 +176,9 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo } // Update justified check point. - justified := s.store.JustifiedCheckpt() - if justified == nil { - return errNilJustifiedInStore + justified, err := s.store.JustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get justified checkpoint") } currJustifiedEpoch := justified.Epoch if postState.CurrentJustifiedCheckpoint().Epoch > currJustifiedEpoch { @@ -187,7 +187,10 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo } } - finalized := s.store.FinalizedCheckpt() + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") + } if finalized == nil { return errNilFinalizedInStore } @@ -473,9 +476,9 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf s.clearInitSyncBlocks() } - justified := s.store.JustifiedCheckpt() - if justified == nil { - return errNilJustifiedInStore + justified, err := s.store.JustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get justified checkpoint") } if jCheckpoint.Epoch > justified.Epoch { if err := s.updateJustifiedInitSync(ctx, jCheckpoint); err != nil { @@ -483,7 +486,10 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf } } - finalized := s.store.FinalizedCheckpt() + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") + } if finalized == nil { return errNilFinalizedInStore } diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 1cc1a7dcb3..9fbd3c34c7 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -92,9 +92,9 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBloc func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byte) error { ctx, span := trace.StartSpan(ctx, "blockChain.VerifyFinalizedBlkDescendant") defer span.End() - finalized := s.store.FinalizedCheckpt() - if finalized == nil { - return errNilFinalizedInStore + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") } fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root)) finalizedBlkSigned, err := s.getBlock(ctx, fRoot) @@ -123,9 +123,9 @@ func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byt // verifyBlkFinalizedSlot validates input block is not less than or equal // to current finalized slot. func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error { - finalized := s.store.FinalizedCheckpt() - if finalized == nil { - return errNilFinalizedInStore + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") } finalizedSlot, err := slots.EpochStart(finalized.Epoch) if err != nil { @@ -166,7 +166,10 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified if slots.SinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified { return true, nil } - justified := s.store.JustifiedCheckpt() + justified, err := s.store.JustifiedCheckpt() + if err != nil { + return false, errors.Wrap(err, "could not get justified checkpoint") + } jSlot, err := slots.EpochStart(justified.Epoch) if err != nil { return false, err @@ -188,9 +191,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco defer span.End() cpt := state.CurrentJustifiedCheckpoint() - bestJustified := s.store.BestJustifiedCheckpt() - if bestJustified == nil { - return errNilBestJustifiedInStore + bestJustified, err := s.store.BestJustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get best justified checkpoint") } if cpt.Epoch > bestJustified.Epoch { s.store.SetBestJustifiedCheckpt(cpt) @@ -201,9 +204,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco } if canUpdate { - justified := s.store.JustifiedCheckpt() - if justified == nil { - return errNilJustifiedInStore + justified, err := s.store.JustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get justified checkpoint") } s.store.SetPrevJustifiedCheckpt(justified) h, err := s.getPayloadHash(ctx, cpt.Root) @@ -220,9 +223,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco // caches justified checkpoint balances for fork choice and save justified checkpoint in DB. // This method does not have defense against fork choice bouncing attack, which is why it's only recommend to be used during initial syncing. func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpoint) error { - justified := s.store.JustifiedCheckpt() - if justified == nil { - return errNilJustifiedInStore + justified, err := s.store.JustifiedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get justified checkpoint") } s.store.SetPrevJustifiedCheckpt(justified) @@ -345,9 +348,9 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa parentRoot := bytesutil.ToBytes32(blk.ParentRoot()) slot := blk.Slot() // Fork choice only matters from last finalized slot. - finalized := s.store.FinalizedCheckpt() - if finalized == nil { - return errNilFinalizedInStore + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return err } fSlot, err := slots.EpochStart(finalized.Epoch) if err != nil { diff --git a/beacon-chain/blockchain/process_block_test.go b/beacon-chain/blockchain/process_block_test.go index a806bcd289..c963ca1582 100644 --- a/beacon-chain/blockchain/process_block_test.go +++ b/beacon-chain/blockchain/process_block_test.go @@ -709,13 +709,17 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) { require.NoError(t, s.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{Epoch: 1, Root: r[:]})) require.NoError(t, service.updateJustified(context.Background(), s)) - assert.Equal(t, s.CurrentJustifiedCheckpoint().Epoch, service.store.BestJustifiedCheckpt().Epoch, "Incorrect justified epoch in service") + cp, err := service.store.BestJustifiedCheckpt() + require.NoError(t, err) + assert.Equal(t, s.CurrentJustifiedCheckpoint().Epoch, cp.Epoch, "Incorrect justified epoch in service") // Could not update service.store.SetBestJustifiedCheckpt(ðpb.Checkpoint{Root: []byte{'A'}, Epoch: 2}) require.NoError(t, service.updateJustified(context.Background(), s)) - assert.Equal(t, types.Epoch(2), service.store.BestJustifiedCheckpt().Epoch, "Incorrect justified epoch in service") + cp, err = service.store.BestJustifiedCheckpt() + require.NoError(t, err) + assert.Equal(t, types.Epoch(2), cp.Epoch, "Incorrect justified epoch in service") } func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) { @@ -1394,9 +1398,13 @@ func TestUpdateJustifiedInitSync(t *testing.T) { require.NoError(t, service.updateJustifiedInitSync(ctx, newCp)) - assert.DeepSSZEqual(t, currentCp, service.PreviousJustifiedCheckpt(), "Incorrect previous justified checkpoint") - assert.DeepSSZEqual(t, newCp, service.CurrentJustifiedCheckpt(), "Incorrect current justified checkpoint in cache") - cp, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx) + cp, err := service.PreviousJustifiedCheckpt() + require.NoError(t, err) + assert.DeepSSZEqual(t, currentCp, cp, "Incorrect previous justified checkpoint") + cp, err = service.CurrentJustifiedCheckpt() + require.NoError(t, err) + assert.DeepSSZEqual(t, newCp, cp, "Incorrect current justified checkpoint in cache") + cp, err = service.cfg.BeaconDB.JustifiedCheckpoint(ctx) require.NoError(t, err) assert.DeepSSZEqual(t, newCp, cp, "Incorrect current justified checkpoint in db") } @@ -1464,16 +1472,24 @@ func TestOnBlock_CanFinalize(t *testing.T) { testState, err = service.cfg.StateGen.StateByRoot(ctx, r) require.NoError(t, err) } - require.Equal(t, types.Epoch(3), service.CurrentJustifiedCheckpt().Epoch) - require.Equal(t, types.Epoch(2), service.FinalizedCheckpt().Epoch) + cp, err := service.CurrentJustifiedCheckpt() + require.NoError(t, err) + require.Equal(t, types.Epoch(3), cp.Epoch) + cp, err = service.FinalizedCheckpt() + require.NoError(t, err) + require.Equal(t, types.Epoch(2), cp.Epoch) // The update should persist in DB. j, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx) require.NoError(t, err) - require.Equal(t, j.Epoch, service.CurrentJustifiedCheckpt().Epoch) + cp, err = service.CurrentJustifiedCheckpt() + require.NoError(t, err) + require.Equal(t, j.Epoch, cp.Epoch) f, err := service.cfg.BeaconDB.FinalizedCheckpoint(ctx) require.NoError(t, err) - require.Equal(t, f.Epoch, service.FinalizedCheckpt().Epoch) + cp, err = service.FinalizedCheckpt() + require.NoError(t, err) + require.Equal(t, f.Epoch, cp.Epoch) } func TestOnBlock_NilBlock(t *testing.T) { diff --git a/beacon-chain/blockchain/receive_attestation.go b/beacon-chain/blockchain/receive_attestation.go index 58d2b804f3..7c5b91c19f 100644 --- a/beacon-chain/blockchain/receive_attestation.go +++ b/beacon-chain/blockchain/receive_attestation.go @@ -71,9 +71,9 @@ func (s *Service) VerifyFinalizedConsistency(ctx context.Context, root []byte) e return nil } - f := s.FinalizedCheckpt() - if f == nil { - return errNilFinalizedInStore + f, err := s.FinalizedCheckpt() + if err != nil { + return err } ss, err := slots.EpochStart(f.Epoch) if err != nil { @@ -152,9 +152,9 @@ func (s *Service) UpdateHead(ctx context.Context) error { s.processAttestations(ctx) - justified := s.store.JustifiedCheckpt() - if justified == nil { - return errNilJustifiedInStore + justified, err := s.store.JustifiedCheckpt() + if err != nil { + return err } balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(justified.Root)) if err != nil { diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index efbdd3c309..4dc62493a7 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -59,9 +59,9 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaco } // Reports on block and fork choice metrics. - finalized := s.store.FinalizedCheckpt() - if finalized == nil { - return errNilFinalizedInStore + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") } reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized) @@ -106,9 +106,9 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.Sig }) // Reports on blockCopy and fork choice metrics. - finalized := s.store.FinalizedCheckpt() - if finalized == nil { - return errNilFinalizedInStore + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") } reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized) } @@ -116,7 +116,10 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.Sig if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil { return err } - finalized := s.store.FinalizedCheckpt() + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return errors.Wrap(err, "could not get finalized checkpoint") + } if finalized == nil { return errNilFinalizedInStore } @@ -169,7 +172,10 @@ func (s *Service) checkSaveHotStateDB(ctx context.Context) error { currentEpoch := slots.ToEpoch(s.CurrentSlot()) // Prevent `sinceFinality` going underflow. var sinceFinality types.Epoch - finalized := s.store.FinalizedCheckpt() + finalized, err := s.store.FinalizedCheckpt() + if err != nil { + return err + } if finalized == nil { return errNilFinalizedInStore } diff --git a/beacon-chain/blockchain/service_test.go b/beacon-chain/blockchain/service_test.go index 869c7a2039..ced717d644 100644 --- a/beacon-chain/blockchain/service_test.go +++ b/beacon-chain/blockchain/service_test.go @@ -277,8 +277,12 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) { // Test the start function. chainService.Start() - require.DeepEqual(t, blkRoot[:], chainService.store.FinalizedCheckpt().Root, "Finalize Checkpoint root is incorrect") - require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], chainService.store.JustifiedCheckpt().Root, "Justified Checkpoint root is incorrect") + cp, err := chainService.store.FinalizedCheckpt() + require.NoError(t, err) + require.DeepEqual(t, blkRoot[:], cp.Root, "Finalize Checkpoint root is incorrect") + cp, err = chainService.store.JustifiedCheckpt() + require.NoError(t, err) + require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], cp.Root, "Justified Checkpoint root is incorrect") require.NoError(t, chainService.Stop(), "Unable to stop chain service") diff --git a/beacon-chain/blockchain/store/BUILD.bazel b/beacon-chain/blockchain/store/BUILD.bazel index 7a8b81966c..731fe78375 100644 --- a/beacon-chain/blockchain/store/BUILD.bazel +++ b/beacon-chain/blockchain/store/BUILD.bazel @@ -10,7 +10,10 @@ go_library( ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store", visibility = ["//beacon-chain:__subpackages__"], - deps = ["//proto/prysm/v1alpha1:go_default_library"], + deps = [ + "//proto/prysm/v1alpha1:go_default_library", + "@com_github_pkg_errors//:go_default_library", + ], ) go_test( diff --git a/beacon-chain/blockchain/store/new_test.go b/beacon-chain/blockchain/store/new_test.go index 06bbe9810c..91836113e6 100644 --- a/beacon-chain/blockchain/store/new_test.go +++ b/beacon-chain/blockchain/store/new_test.go @@ -17,9 +17,19 @@ func TestNew(t *testing.T) { Root: []byte("hello"), } s := New(j, f) - require.DeepSSZEqual(t, s.JustifiedCheckpt(), j) - require.DeepSSZEqual(t, s.BestJustifiedCheckpt(), j) - require.DeepSSZEqual(t, s.PrevJustifiedCheckpt(), j) - require.DeepSSZEqual(t, s.FinalizedCheckpt(), f) - require.DeepSSZEqual(t, s.PrevFinalizedCheckpt(), f) + cp, err := s.JustifiedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, j, cp) + cp, err = s.BestJustifiedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, j, cp) + cp, err = s.PrevJustifiedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, j, cp) + cp, err = s.FinalizedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, f, cp) + cp, err = s.PrevFinalizedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, f, cp) } diff --git a/beacon-chain/blockchain/store/setter_getter.go b/beacon-chain/blockchain/store/setter_getter.go index 857af7703f..45c0e30a24 100644 --- a/beacon-chain/blockchain/store/setter_getter.go +++ b/beacon-chain/blockchain/store/setter_getter.go @@ -1,26 +1,42 @@ package store -import ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" +import ( + "github.com/pkg/errors" + ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" +) + +var ( + ErrNilCheckpoint = errors.New("nil checkpoint") +) // PrevJustifiedCheckpt returns the previous justified checkpoint in the Store. -func (s *Store) PrevJustifiedCheckpt() *ethpb.Checkpoint { +func (s *Store) PrevJustifiedCheckpt() (*ethpb.Checkpoint, error) { s.RLock() defer s.RUnlock() - return s.prevJustifiedCheckpt + if s.prevJustifiedCheckpt == nil { + return nil, ErrNilCheckpoint + } + return s.prevJustifiedCheckpt, nil } // BestJustifiedCheckpt returns the best justified checkpoint in the Store. -func (s *Store) BestJustifiedCheckpt() *ethpb.Checkpoint { +func (s *Store) BestJustifiedCheckpt() (*ethpb.Checkpoint, error) { s.RLock() defer s.RUnlock() - return s.bestJustifiedCheckpt + if s.bestJustifiedCheckpt == nil { + return nil, ErrNilCheckpoint + } + return s.bestJustifiedCheckpt, nil } // JustifiedCheckpt returns the justified checkpoint in the Store. -func (s *Store) JustifiedCheckpt() *ethpb.Checkpoint { +func (s *Store) JustifiedCheckpt() (*ethpb.Checkpoint, error) { s.RLock() defer s.RUnlock() - return s.justifiedCheckpt + if s.justifiedCheckpt == nil { + return nil, ErrNilCheckpoint + } + return s.justifiedCheckpt, nil } // JustifiedPayloadBlockHash returns the justified payload block hash reflecting justified check point. @@ -31,17 +47,23 @@ func (s *Store) JustifiedPayloadBlockHash() [32]byte { } // PrevFinalizedCheckpt returns the previous finalized checkpoint in the Store. -func (s *Store) PrevFinalizedCheckpt() *ethpb.Checkpoint { +func (s *Store) PrevFinalizedCheckpt() (*ethpb.Checkpoint, error) { s.RLock() defer s.RUnlock() - return s.prevFinalizedCheckpt + if s.prevFinalizedCheckpt == nil { + return nil, ErrNilCheckpoint + } + return s.prevFinalizedCheckpt, nil } // FinalizedCheckpt returns the finalized checkpoint in the Store. -func (s *Store) FinalizedCheckpt() *ethpb.Checkpoint { +func (s *Store) FinalizedCheckpt() (*ethpb.Checkpoint, error) { s.RLock() defer s.RUnlock() - return s.finalizedCheckpt + if s.finalizedCheckpt == nil { + return nil, ErrNilCheckpoint + } + return s.finalizedCheckpt, nil } // FinalizedPayloadBlockHash returns the finalized payload block hash reflecting finalized check point. diff --git a/beacon-chain/blockchain/store/setter_getter_test.go b/beacon-chain/blockchain/store/setter_getter_test.go index 2c6174fd1c..21a1f03a11 100644 --- a/beacon-chain/blockchain/store/setter_getter_test.go +++ b/beacon-chain/blockchain/store/setter_getter_test.go @@ -10,48 +10,63 @@ import ( func Test_store_PrevJustifiedCheckpt(t *testing.T) { s := &Store{} var cp *ethpb.Checkpoint - require.Equal(t, cp, s.PrevJustifiedCheckpt()) + _, err := s.PrevJustifiedCheckpt() + require.ErrorIs(t, ErrNilCheckpoint, err) cp = ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} s.SetPrevJustifiedCheckpt(cp) - require.Equal(t, cp, s.PrevJustifiedCheckpt()) + got, err := s.PrevJustifiedCheckpt() + require.NoError(t, err) + require.Equal(t, cp, got) } func Test_store_BestJustifiedCheckpt(t *testing.T) { s := &Store{} var cp *ethpb.Checkpoint - require.Equal(t, cp, s.BestJustifiedCheckpt()) + _, err := s.BestJustifiedCheckpt() + require.ErrorIs(t, ErrNilCheckpoint, err) cp = ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} s.SetBestJustifiedCheckpt(cp) - require.Equal(t, cp, s.BestJustifiedCheckpt()) + got, err := s.BestJustifiedCheckpt() + require.NoError(t, err) + require.Equal(t, cp, got) } func Test_store_JustifiedCheckpt(t *testing.T) { s := &Store{} var cp *ethpb.Checkpoint - require.Equal(t, cp, s.JustifiedCheckpt()) + _, err := s.JustifiedCheckpt() + require.ErrorIs(t, ErrNilCheckpoint, err) cp = ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} h := [32]byte{'b'} s.SetJustifiedCheckptAndPayloadHash(cp, h) - require.Equal(t, cp, s.JustifiedCheckpt()) + got, err := s.JustifiedCheckpt() + require.NoError(t, err) + require.Equal(t, cp, got) require.Equal(t, h, s.JustifiedPayloadBlockHash()) } func Test_store_FinalizedCheckpt(t *testing.T) { s := &Store{} var cp *ethpb.Checkpoint - require.Equal(t, cp, s.FinalizedCheckpt()) + _, err := s.FinalizedCheckpt() + require.ErrorIs(t, ErrNilCheckpoint, err) cp = ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} h := [32]byte{'b'} s.SetFinalizedCheckptAndPayloadHash(cp, h) - require.Equal(t, cp, s.FinalizedCheckpt()) + got, err := s.FinalizedCheckpt() + require.NoError(t, err) + require.Equal(t, cp, got) require.Equal(t, h, s.FinalizedPayloadBlockHash()) } func Test_store_PrevFinalizedCheckpt(t *testing.T) { s := &Store{} var cp *ethpb.Checkpoint - require.Equal(t, cp, s.PrevFinalizedCheckpt()) + _, err := s.PrevFinalizedCheckpt() + require.ErrorIs(t, ErrNilCheckpoint, err) cp = ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} s.SetPrevFinalizedCheckpt(cp) - require.Equal(t, cp, s.PrevFinalizedCheckpt()) + got, err := s.PrevFinalizedCheckpt() + require.NoError(t, err) + require.Equal(t, cp, got) } diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index d6fb68175c..75e27ef8ad 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -282,18 +282,18 @@ func (s *ChainService) CurrentFork() *ethpb.Fork { } // FinalizedCheckpt mocks FinalizedCheckpt method in chain service. -func (s *ChainService) FinalizedCheckpt() *ethpb.Checkpoint { - return s.FinalizedCheckPoint +func (s *ChainService) FinalizedCheckpt() (*ethpb.Checkpoint, error) { + return s.FinalizedCheckPoint, nil } // CurrentJustifiedCheckpt mocks CurrentJustifiedCheckpt method in chain service. -func (s *ChainService) CurrentJustifiedCheckpt() *ethpb.Checkpoint { - return s.CurrentJustifiedCheckPoint +func (s *ChainService) CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) { + return s.CurrentJustifiedCheckPoint, nil } // PreviousJustifiedCheckpt mocks PreviousJustifiedCheckpt method in chain service. -func (s *ChainService) PreviousJustifiedCheckpt() *ethpb.Checkpoint { - return s.PreviousJustifiedCheckPoint +func (s *ChainService) PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) { + return s.PreviousJustifiedCheckPoint, nil } // ReceiveAttestation mocks ReceiveAttestation method in chain service. diff --git a/beacon-chain/blockchain/weak_subjectivity_checks_test.go b/beacon-chain/blockchain/weak_subjectivity_checks_test.go index 19585c06a3..85e2fc97ea 100644 --- a/beacon-chain/blockchain/weak_subjectivity_checks_test.go +++ b/beacon-chain/blockchain/weak_subjectivity_checks_test.go @@ -80,7 +80,9 @@ func TestService_VerifyWeakSubjectivityRoot(t *testing.T) { wsVerifier: wv, } s.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: tt.finalizedEpoch}, [32]byte{}) - err = s.wsVerifier.VerifyWeakSubjectivity(context.Background(), s.store.FinalizedCheckpt().Epoch) + cp, err := s.store.FinalizedCheckpt() + require.NoError(t, err) + err = s.wsVerifier.VerifyWeakSubjectivity(context.Background(), cp.Epoch) if tt.wantErr == nil { require.NoError(t, err) } else { diff --git a/beacon-chain/rpc/eth/beacon/blocks.go b/beacon-chain/rpc/eth/beacon/blocks.go index 706a68a091..3554218a7d 100644 --- a/beacon-chain/rpc/eth/beacon/blocks.go +++ b/beacon-chain/rpc/eth/beacon/blocks.go @@ -574,7 +574,10 @@ func (bs *Server) GetBlockRoot(ctx context.Context, req *ethpbv1.BlockRequest) ( return nil, status.Errorf(codes.NotFound, "No head root was found") } case "finalized": - finalized := bs.ChainInfoFetcher.FinalizedCheckpt() + finalized, err := bs.ChainInfoFetcher.FinalizedCheckpt() + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not retrieve finalized checkpoint: %v", err) + } root = finalized.Root case "genesis": blk, err := bs.BeaconDB.GenesisBlock(ctx) @@ -725,7 +728,10 @@ func (bs *Server) blockFromBlockID(ctx context.Context, blockId []byte) (interfa return nil, errors.Wrap(err, "could not retrieve head block") } case "finalized": - finalized := bs.ChainInfoFetcher.FinalizedCheckpt() + finalized, err := bs.ChainInfoFetcher.FinalizedCheckpt() + if err != nil { + return nil, errors.Wrap(err, "could not retrieve finalized checkpoint") + } finalizedRoot := bytesutil.ToBytes32(finalized.Root) blk, err = bs.BeaconDB.Block(ctx, finalizedRoot) if err != nil { diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go index cc43c35621..83ccc0779b 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go @@ -425,17 +425,26 @@ func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, err return nil } - finalizedCheckpoint := bs.FinalizationFetcher.FinalizedCheckpt() + finalizedCheckpoint, err := bs.FinalizationFetcher.FinalizedCheckpt() + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get finalized checkpoint: %v", err) + } if err := validateCP(finalizedCheckpoint, "finalized"); err != nil { return nil, err } - justifiedCheckpoint := bs.FinalizationFetcher.CurrentJustifiedCheckpt() + justifiedCheckpoint, err := bs.FinalizationFetcher.CurrentJustifiedCheckpt() + if err != nil { + return nil, err + } if err := validateCP(justifiedCheckpoint, "justified"); err != nil { return nil, err } - prevJustifiedCheckpoint := bs.FinalizationFetcher.PreviousJustifiedCheckpt() + prevJustifiedCheckpoint, err := bs.FinalizationFetcher.PreviousJustifiedCheckpt() + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get previous justified checkpoint: %v", err) + } if err := validateCP(prevJustifiedCheckpoint, "prev justified"); err != nil { return nil, err } diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go index 6e598cf1b9..259b02b6b4 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go @@ -540,10 +540,13 @@ func (bs *Server) GetValidatorParticipation( default: return nil, status.Errorf(codes.Internal, "Invalid state type retrieved with a version of %d", beaconState.Version()) } - + cp, err := bs.FinalizationFetcher.FinalizedCheckpt() + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get finalized checkpoint: %v", err) + } p := ðpb.ValidatorParticipationResponse{ Epoch: requestedEpoch, - Finalized: requestedEpoch <= bs.FinalizationFetcher.FinalizedCheckpt().Epoch, + Finalized: requestedEpoch <= cp.Epoch, Participation: ðpb.ValidatorParticipation{ // TODO(7130): Remove these three deprecated fields. GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch), diff --git a/beacon-chain/rpc/statefetcher/fetcher.go b/beacon-chain/rpc/statefetcher/fetcher.go index 69a1804f01..3886317d15 100644 --- a/beacon-chain/rpc/statefetcher/fetcher.go +++ b/beacon-chain/rpc/statefetcher/fetcher.go @@ -116,13 +116,19 @@ func (p *StateProvider) State(ctx context.Context, stateId []byte) (state.Beacon return nil, errors.Wrap(err, "could not get genesis state") } case "finalized": - checkpoint := p.ChainInfoFetcher.FinalizedCheckpt() + checkpoint, err := p.ChainInfoFetcher.FinalizedCheckpt() + if err != nil { + return nil, errors.Wrap(err, "could not get finalized checkpoint") + } s, err = p.StateGenService.StateByRoot(ctx, bytesutil.ToBytes32(checkpoint.Root)) if err != nil { return nil, errors.Wrap(err, "could not get finalized state") } case "justified": - checkpoint := p.ChainInfoFetcher.CurrentJustifiedCheckpt() + checkpoint, err := p.ChainInfoFetcher.CurrentJustifiedCheckpt() + if err != nil { + return nil, errors.Wrap(err, "could not get justified checkpoint") + } s, err = p.StateGenService.StateByRoot(ctx, bytesutil.ToBytes32(checkpoint.Root)) if err != nil { return nil, errors.Wrap(err, "could not get justified state") diff --git a/beacon-chain/sync/initial-sync/blocks_fetcher_peers.go b/beacon-chain/sync/initial-sync/blocks_fetcher_peers.go index d9dd1d2ab7..1d749aa401 100644 --- a/beacon-chain/sync/initial-sync/blocks_fetcher_peers.go +++ b/beacon-chain/sync/initial-sync/blocks_fetcher_peers.go @@ -73,7 +73,11 @@ func (f *blocksFetcher) waitForMinimumPeers(ctx context.Context) ([]peer.ID, err } var peers []peer.ID if f.mode == modeStopOnFinalizedEpoch { - headEpoch := f.chain.FinalizedCheckpt().Epoch + cp, err := f.chain.FinalizedCheckpt() + if err != nil { + return nil, err + } + headEpoch := cp.Epoch _, peers = f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch) } else { headEpoch := slots.ToEpoch(f.chain.HeadSlot()) diff --git a/beacon-chain/sync/initial-sync/blocks_fetcher_utils.go b/beacon-chain/sync/initial-sync/blocks_fetcher_utils.go index 8b288c3cab..ff0fef67b2 100644 --- a/beacon-chain/sync/initial-sync/blocks_fetcher_utils.go +++ b/beacon-chain/sync/initial-sync/blocks_fetcher_utils.go @@ -157,13 +157,17 @@ func (f *blocksFetcher) findFork(ctx context.Context, slot types.Slot) (*forkDat // The current slot's epoch must be after the finalization epoch, // triggering backtracking on earlier epochs is unnecessary. - finalizedEpoch := f.chain.FinalizedCheckpt().Epoch + cp, err := f.chain.FinalizedCheckpt() + if err != nil { + return nil, err + } + finalizedEpoch := cp.Epoch epoch := slots.ToEpoch(slot) if epoch <= finalizedEpoch { return nil, errors.New("slot is not after the finalized epoch, no backtracking is necessary") } // Update slot to the beginning of the current epoch (preserve original slot for comparison). - slot, err := slots.EpochStart(epoch) + slot, err = slots.EpochStart(epoch) if err != nil { return nil, err } @@ -287,8 +291,13 @@ func (f *blocksFetcher) findAncestor(ctx context.Context, pid peer.ID, b interfa // bestFinalizedSlot returns the highest finalized slot of the majority of connected peers. func (f *blocksFetcher) bestFinalizedSlot() types.Slot { + cp, err := f.chain.FinalizedCheckpt() + if err != nil { + log.WithError(err).Error("Failed to get finalized checkpoint") + return 0 + } finalizedEpoch, _ := f.p2p.Peers().BestFinalized( - params.BeaconConfig().MaxPeersToSync, f.chain.FinalizedCheckpt().Epoch) + params.BeaconConfig().MaxPeersToSync, cp.Epoch) return params.BeaconConfig().SlotsPerEpoch.Mul(uint64(finalizedEpoch)) } @@ -303,7 +312,12 @@ func (f *blocksFetcher) bestNonFinalizedSlot() types.Slot { // epoch. For the latter peers supporting that target epoch are returned as well. func (f *blocksFetcher) calculateHeadAndTargetEpochs() (headEpoch, targetEpoch types.Epoch, peers []peer.ID) { if f.mode == modeStopOnFinalizedEpoch { - headEpoch = f.chain.FinalizedCheckpt().Epoch + cp, err := f.chain.FinalizedCheckpt() + if err != nil { + log.WithError(err).Error("Failed to get finalized checkpoint") + return 0, 0, peers + } + headEpoch = cp.Epoch targetEpoch, peers = f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch) } else { headEpoch = slots.ToEpoch(f.chain.HeadSlot()) diff --git a/beacon-chain/sync/initial-sync/blocks_queue_test.go b/beacon-chain/sync/initial-sync/blocks_queue_test.go index 7cd13d251f..ea02a08d85 100644 --- a/beacon-chain/sync/initial-sync/blocks_queue_test.go +++ b/beacon-chain/sync/initial-sync/blocks_queue_test.go @@ -1321,7 +1321,9 @@ func TestBlocksQueue_stuckWhenHeadIsSetToOrphanedBlock(t *testing.T) { require.NoError(t, queue.start()) isProcessedBlock := func(ctx context.Context, blk interfaces.SignedBeaconBlock, blkRoot [32]byte) bool { - finalizedSlot, err := slots.EpochStart(mc.FinalizedCheckpt().Epoch) + cp, err := mc.FinalizedCheckpt() + require.NoError(t, err) + finalizedSlot, err := slots.EpochStart(cp.Epoch) if err != nil { return false } diff --git a/beacon-chain/sync/initial-sync/round_robin.go b/beacon-chain/sync/initial-sync/round_robin.go index bd4757b307..50e6ce6154 100644 --- a/beacon-chain/sync/initial-sync/round_robin.go +++ b/beacon-chain/sync/initial-sync/round_robin.go @@ -308,7 +308,12 @@ func (s *Service) updatePeerScorerStats(pid peer.ID, startSlot types.Slot) { // isProcessedBlock checks DB and local cache for presence of a given block, to avoid duplicates. func (s *Service) isProcessedBlock(ctx context.Context, blk interfaces.SignedBeaconBlock, blkRoot [32]byte) bool { - finalizedSlot, err := slots.EpochStart(s.cfg.Chain.FinalizedCheckpt().Epoch) + cp, err := s.cfg.Chain.FinalizedCheckpt() + if err != nil { + log.Errorf("could not get finalized checkpoint: %v", err) + return false + } + finalizedSlot, err := slots.EpochStart(cp.Epoch) if err != nil { return false } diff --git a/beacon-chain/sync/initial-sync/service.go b/beacon-chain/sync/initial-sync/service.go index ef4c237fcd..d121f8e1c4 100644 --- a/beacon-chain/sync/initial-sync/service.go +++ b/beacon-chain/sync/initial-sync/service.go @@ -173,7 +173,12 @@ func (s *Service) waitForMinimumPeers() { required = flags.Get().MinimumSyncPeers } for { - _, peers := s.cfg.P2P.Peers().BestNonFinalized(flags.Get().MinimumSyncPeers, s.cfg.Chain.FinalizedCheckpt().Epoch) + cp, err := s.cfg.Chain.FinalizedCheckpt() + if err != nil { + log.WithError(err).Error("Could not retrieve finalized checkpoint") + return + } + _, peers := s.cfg.P2P.Peers().BestNonFinalized(flags.Get().MinimumSyncPeers, cp.Epoch) if len(peers) >= required { break } diff --git a/beacon-chain/sync/pending_blocks_queue.go b/beacon-chain/sync/pending_blocks_queue.go index 9e4f797b5b..5a5be0c666 100644 --- a/beacon-chain/sync/pending_blocks_queue.go +++ b/beacon-chain/sync/pending_blocks_queue.go @@ -210,8 +210,11 @@ func (s *Service) sendBatchRootRequest(ctx context.Context, roots [][32]byte, ra if len(roots) == 0 { return nil } - - _, bestPeers := s.cfg.p2p.Peers().BestFinalized(maxPeerRequest, s.cfg.chain.FinalizedCheckpt().Epoch) + cp, err := s.cfg.chain.FinalizedCheckpt() + if err != nil { + return err + } + _, bestPeers := s.cfg.p2p.Peers().BestFinalized(maxPeerRequest, cp.Epoch) if len(bestPeers) == 0 { return nil } @@ -272,7 +275,11 @@ func (s *Service) validatePendingSlots() error { defer s.pendingQueueLock.Unlock() oldBlockRoots := make(map[[32]byte]bool) - finalizedEpoch := s.cfg.chain.FinalizedCheckpt().Epoch + cp, err := s.cfg.chain.FinalizedCheckpt() + if err != nil { + return err + } + finalizedEpoch := cp.Epoch if s.slotToPendingBlocks == nil { return errors.New("slotToPendingBlocks cache can't be nil") } diff --git a/beacon-chain/sync/rpc_status.go b/beacon-chain/sync/rpc_status.go index a9d36f3c74..a71f1f68f0 100644 --- a/beacon-chain/sync/rpc_status.go +++ b/beacon-chain/sync/rpc_status.go @@ -131,10 +131,14 @@ func (s *Service) sendRPCStatusRequest(ctx context.Context, id peer.ID) error { if err != nil { return err } + cp, err := s.cfg.chain.FinalizedCheckpt() + if err != nil { + return err + } resp := &pb.Status{ ForkDigest: forkDigest[:], - FinalizedRoot: s.cfg.chain.FinalizedCheckpt().Root, - FinalizedEpoch: s.cfg.chain.FinalizedCheckpt().Epoch, + FinalizedRoot: cp.Root, + FinalizedEpoch: cp.Epoch, HeadRoot: headRoot, HeadSlot: s.cfg.chain.HeadSlot(), } @@ -260,10 +264,14 @@ func (s *Service) respondWithStatus(ctx context.Context, stream network.Stream) if err != nil { return err } + cp, err := s.cfg.chain.FinalizedCheckpt() + if err != nil { + return err + } resp := &pb.Status{ ForkDigest: forkDigest[:], - FinalizedRoot: s.cfg.chain.FinalizedCheckpt().Root, - FinalizedEpoch: s.cfg.chain.FinalizedCheckpt().Epoch, + FinalizedRoot: cp.Root, + FinalizedEpoch: cp.Epoch, HeadRoot: headRoot, HeadSlot: s.cfg.chain.HeadSlot(), } @@ -284,7 +292,11 @@ func (s *Service) validateStatusMessage(ctx context.Context, msg *pb.Status) err return p2ptypes.ErrWrongForkDigestVersion } genesis := s.cfg.chain.GenesisTime() - finalizedEpoch := s.cfg.chain.FinalizedCheckpt().Epoch + cp, err := s.cfg.chain.FinalizedCheckpt() + if err != nil { + return err + } + finalizedEpoch := cp.Epoch maxEpoch := slots.EpochsSinceGenesis(genesis) // It would take a minimum of 2 epochs to finalize a // previous epoch diff --git a/beacon-chain/sync/validate_beacon_blocks.go b/beacon-chain/sync/validate_beacon_blocks.go index 5198efd979..6d3974d338 100644 --- a/beacon-chain/sync/validate_beacon_blocks.go +++ b/beacon-chain/sync/validate_beacon_blocks.go @@ -131,7 +131,11 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms return pubsub.ValidationIgnore, nil } - startSlot, err := slots.EpochStart(s.cfg.chain.FinalizedCheckpt().Epoch) + cp, err := s.cfg.chain.FinalizedCheckpt() + if err != nil { + return pubsub.ValidationIgnore, nil + } + startSlot, err := slots.EpochStart(cp.Epoch) if err != nil { log.WithError(err).WithFields(getBlockFields(blk)).Debug("Ignored block: could not calculate epoch start slot") return pubsub.ValidationIgnore, nil diff --git a/testing/spectest/shared/common/forkchoice/builder.go b/testing/spectest/shared/common/forkchoice/builder.go index 8e4d0f92d4..9e40f1d952 100644 --- a/testing/spectest/shared/common/forkchoice/builder.go +++ b/testing/spectest/shared/common/forkchoice/builder.go @@ -103,21 +103,27 @@ func (bb *Builder) Check(t testing.TB, c *Check) { Epoch: types.Epoch(c.JustifiedCheckPoint.Epoch), Root: common.FromHex(c.JustifiedCheckPoint.Root), } - require.DeepEqual(t, cp, bb.service.CurrentJustifiedCheckpt()) + got, err := bb.service.CurrentJustifiedCheckpt() + require.NoError(t, err) + require.DeepEqual(t, cp, got) } if c.BestJustifiedCheckPoint != nil { cp := ðpb.Checkpoint{ Epoch: types.Epoch(c.BestJustifiedCheckPoint.Epoch), Root: common.FromHex(c.BestJustifiedCheckPoint.Root), } - require.DeepEqual(t, cp, bb.service.BestJustifiedCheckpt()) + got, err := bb.service.BestJustifiedCheckpt() + require.NoError(t, err) + require.DeepEqual(t, cp, got) } if c.FinalizedCheckPoint != nil { cp := ðpb.Checkpoint{ Epoch: types.Epoch(c.FinalizedCheckPoint.Epoch), Root: common.FromHex(c.FinalizedCheckPoint.Root), } - require.DeepSSZEqual(t, cp, bb.service.FinalizedCheckpt()) + got, err := bb.service.FinalizedCheckpt() + require.NoError(t, err) + require.DeepSSZEqual(t, cp, got) } if c.ProposerBoostRoot != nil { want := fmt.Sprintf("%#x", common.FromHex(*c.ProposerBoostRoot))