Chain info: Return err if checkpoint is nil (#10729)

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
terencechain
2022-05-20 11:41:33 -07:00
committed by GitHub
parent 76f6d74b83
commit 370cf1a6c8
31 changed files with 365 additions and 177 deletions

View File

@@ -4,6 +4,8 @@ import (
"context" "context"
"time" "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/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice" "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree" 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 // FinalizationFetcher defines a common interface for methods in blockchain service which
// directly retrieve finalization and justification related data. // directly retrieve finalization and justification related data.
type FinalizationFetcher interface { type FinalizationFetcher interface {
FinalizedCheckpt() *ethpb.Checkpoint FinalizedCheckpt() (*ethpb.Checkpoint, error)
CurrentJustifiedCheckpt() *ethpb.Checkpoint CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error)
PreviousJustifiedCheckpt() *ethpb.Checkpoint PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error)
VerifyFinalizedBlkDescendant(ctx context.Context, blockRoot [32]byte) 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. // FinalizedCheckpt returns the latest finalized checkpoint from chain store.
func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint { func (s *Service) FinalizedCheckpt() (*ethpb.Checkpoint, error) {
cp := s.store.FinalizedCheckpt() cp, err := s.store.FinalizedCheckpt()
if cp == nil { if err != nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} return nil, err
} }
return ethpb.CopyCheckpoint(cp) return ethpb.CopyCheckpoint(cp), nil
} }
// CurrentJustifiedCheckpt returns the current justified checkpoint from chain store. // CurrentJustifiedCheckpt returns the current justified checkpoint from chain store.
func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint { func (s *Service) CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) {
cp := s.store.JustifiedCheckpt() cp, err := s.store.JustifiedCheckpt()
if cp == nil { if err != nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} return nil, err
} }
return ethpb.CopyCheckpoint(cp) return ethpb.CopyCheckpoint(cp), nil
} }
// PreviousJustifiedCheckpt returns the previous justified checkpoint from chain store. // PreviousJustifiedCheckpt returns the previous justified checkpoint from chain store.
func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint { func (s *Service) PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) {
cp := s.store.PrevJustifiedCheckpt() cp, err := s.store.PrevJustifiedCheckpt()
if cp == nil { if err != nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} return nil, err
} }
return ethpb.CopyCheckpoint(cp) return ethpb.CopyCheckpoint(cp), nil
} }
// BestJustifiedCheckpt returns the best justified checkpoint from store. // BestJustifiedCheckpt returns the best justified checkpoint from store.
func (s *Service) BestJustifiedCheckpt() *ethpb.Checkpoint { func (s *Service) BestJustifiedCheckpt() (*ethpb.Checkpoint, error) {
cp := s.store.BestJustifiedCheckpt() cp, err := s.store.BestJustifiedCheckpt()
// If there is no best justified checkpoint, return the checkpoint with root as zeros to be used for genesis cases. if err != nil {
if cp == nil { // If there is no best justified checkpoint, return the checkpoint with root as zeros to be used for genesis cases.
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} if errors.Is(err, store.ErrNilCheckpoint) {
return &ethpb.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. // HeadSlot returns the slot of the head of the chain.

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree" doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray" "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
@@ -26,12 +27,6 @@ var _ ChainInfoFetcher = (*Service)(nil)
var _ TimeFetcher = (*Service)(nil) var _ TimeFetcher = (*Service)(nil)
var _ ForkFetcher = (*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) { func TestHeadRoot_Nil(t *testing.T) {
beaconDB := testDB.SetupDB(t) beaconDB := testDB.SetupDB(t)
c := setupBeaconChain(t, beaconDB) c := setupBeaconChain(t, beaconDB)
@@ -53,7 +48,9 @@ func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
c := setupBeaconChain(t, beaconDB) c := setupBeaconChain(t, beaconDB)
c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'}) 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) { func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
@@ -64,17 +61,22 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
c := setupBeaconChain(t, beaconDB) c := setupBeaconChain(t, beaconDB)
c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'}) c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'})
c.originBlockRoot = genesisRoot 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) { func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
beaconDB := testDB.SetupDB(t) beaconDB := testDB.SetupDB(t)
c := setupBeaconChain(t, beaconDB) 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 := &ethpb.Checkpoint{Epoch: 6, Root: bytesutil.PadTo([]byte("foo"), 32)} cp := &ethpb.Checkpoint{Epoch: 6, Root: bytesutil.PadTo([]byte("foo"), 32)}
c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{}) 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) { func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
@@ -85,7 +87,9 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
cp := &ethpb.Checkpoint{Root: genesisRoot[:]} cp := &ethpb.Checkpoint{Root: genesisRoot[:]}
c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{}) c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{})
c.originBlockRoot = genesisRoot 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) { func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
@@ -93,9 +97,12 @@ func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
cp := &ethpb.Checkpoint{Epoch: 7, Root: bytesutil.PadTo([]byte("foo"), 32)} cp := &ethpb.Checkpoint{Epoch: 7, Root: bytesutil.PadTo([]byte("foo"), 32)}
c := setupBeaconChain(t, beaconDB) 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) 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) { func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
@@ -106,7 +113,9 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
c := setupBeaconChain(t, beaconDB) c := setupBeaconChain(t, beaconDB)
c.store.SetPrevJustifiedCheckpt(cp) c.store.SetPrevJustifiedCheckpt(cp)
c.originBlockRoot = genesisRoot 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) { func TestHeadSlot_CanRetrieve(t *testing.T) {

View File

@@ -3,10 +3,6 @@ package blockchain
import "github.com/pkg/errors" import "github.com/pkg/errors"
var ( 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 is returned when a nil finalized checkpt is returned from store.
errNilFinalizedInStore = errors.New("nil finalized checkpoint returned from store") errNilFinalizedInStore = errors.New("nil finalized checkpoint returned from store")
// errInvalidNilSummary is returned when a nil summary is returned from the DB. // errInvalidNilSummary is returned when a nil summary is returned from the DB.

View File

@@ -27,9 +27,9 @@ import (
// UpdateAndSaveHeadWithBalances updates the beacon state head after getting justified balanced from cache. // 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. // This function is only used in spec-tests, it does save the head after updating it.
func (s *Service) UpdateAndSaveHeadWithBalances(ctx context.Context) error { func (s *Service) UpdateAndSaveHeadWithBalances(ctx context.Context) error {
cp := s.store.JustifiedCheckpt() cp, err := s.store.JustifiedCheckpt()
if cp == nil { if err != nil {
return errors.New("no justified checkpoint") return err
} }
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(cp.Root)) balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(cp.Root))
if err != nil { if err != nil {
@@ -66,13 +66,13 @@ func (s *Service) updateHead(ctx context.Context, balances []uint64) ([32]byte,
defer span.End() defer span.End()
// Get head from the fork choice service. // Get head from the fork choice service.
f := s.store.FinalizedCheckpt() f, err := s.store.FinalizedCheckpt()
if f == nil { if err != nil {
return [32]byte{}, errNilFinalizedInStore return [32]byte{}, errors.Wrap(err, "could not get finalized checkpoint")
} }
j := s.store.JustifiedCheckpt() j, err := s.store.JustifiedCheckpt()
if j == nil { if err != nil {
return [32]byte{}, errNilJustifiedInStore 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 // To get head before the first justified epoch, the fork choice will start with origin root
// instead of zero hashes. // instead of zero hashes.

View File

@@ -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 // Update store.justified_checkpoint if a better checkpoint on the store.finalized_checkpoint chain
bj := s.store.BestJustifiedCheckpt() bj, err := s.store.BestJustifiedCheckpt()
if bj == nil { if err != nil {
return errNilBestJustifiedInStore return errors.Wrap(err, "could not get best justified checkpoint")
} }
j := s.store.JustifiedCheckpt() j, err := s.store.JustifiedCheckpt()
if j == nil { if err != nil {
return errNilJustifiedInStore return errors.Wrap(err, "could not get justified checkpoint")
} }
f := s.store.FinalizedCheckpt() f, err := s.store.FinalizedCheckpt()
if f == nil { if err != nil {
return errNilFinalizedInStore return errors.Wrap(err, "could not get finalized checkpoint")
} }
if bj.Epoch > j.Epoch { if bj.Epoch > j.Epoch {
finalizedSlot, err := slots.EpochStart(f.Epoch) finalizedSlot, err := slots.EpochStart(f.Epoch)

View File

@@ -103,9 +103,17 @@ func TestService_newSlot(t *testing.T) {
require.NoError(t, service.NewSlot(ctx, test.args.slot)) require.NoError(t, service.NewSlot(ctx, test.args.slot))
if test.args.shouldEqual { 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 { } 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)
} }
} }
} }

View File

@@ -176,9 +176,9 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
} }
// Update justified check point. // Update justified check point.
justified := s.store.JustifiedCheckpt() justified, err := s.store.JustifiedCheckpt()
if justified == nil { if err != nil {
return errNilJustifiedInStore return errors.Wrap(err, "could not get justified checkpoint")
} }
currJustifiedEpoch := justified.Epoch currJustifiedEpoch := justified.Epoch
if postState.CurrentJustifiedCheckpoint().Epoch > currJustifiedEpoch { 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 { if finalized == nil {
return errNilFinalizedInStore return errNilFinalizedInStore
} }
@@ -473,9 +476,9 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf
s.clearInitSyncBlocks() s.clearInitSyncBlocks()
} }
justified := s.store.JustifiedCheckpt() justified, err := s.store.JustifiedCheckpt()
if justified == nil { if err != nil {
return errNilJustifiedInStore return errors.Wrap(err, "could not get justified checkpoint")
} }
if jCheckpoint.Epoch > justified.Epoch { if jCheckpoint.Epoch > justified.Epoch {
if err := s.updateJustifiedInitSync(ctx, jCheckpoint); err != nil { 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 { if finalized == nil {
return errNilFinalizedInStore return errNilFinalizedInStore
} }

View File

@@ -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 { func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byte) error {
ctx, span := trace.StartSpan(ctx, "blockChain.VerifyFinalizedBlkDescendant") ctx, span := trace.StartSpan(ctx, "blockChain.VerifyFinalizedBlkDescendant")
defer span.End() defer span.End()
finalized := s.store.FinalizedCheckpt() finalized, err := s.store.FinalizedCheckpt()
if finalized == nil { if err != nil {
return errNilFinalizedInStore return errors.Wrap(err, "could not get finalized checkpoint")
} }
fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root)) fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
finalizedBlkSigned, err := s.getBlock(ctx, fRoot) 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 // verifyBlkFinalizedSlot validates input block is not less than or equal
// to current finalized slot. // to current finalized slot.
func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error { func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error {
finalized := s.store.FinalizedCheckpt() finalized, err := s.store.FinalizedCheckpt()
if finalized == nil { if err != nil {
return errNilFinalizedInStore return errors.Wrap(err, "could not get finalized checkpoint")
} }
finalizedSlot, err := slots.EpochStart(finalized.Epoch) finalizedSlot, err := slots.EpochStart(finalized.Epoch)
if err != nil { if err != nil {
@@ -166,7 +166,10 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
if slots.SinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified { if slots.SinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified {
return true, nil 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) jSlot, err := slots.EpochStart(justified.Epoch)
if err != nil { if err != nil {
return false, err return false, err
@@ -188,9 +191,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
defer span.End() defer span.End()
cpt := state.CurrentJustifiedCheckpoint() cpt := state.CurrentJustifiedCheckpoint()
bestJustified := s.store.BestJustifiedCheckpt() bestJustified, err := s.store.BestJustifiedCheckpt()
if bestJustified == nil { if err != nil {
return errNilBestJustifiedInStore return errors.Wrap(err, "could not get best justified checkpoint")
} }
if cpt.Epoch > bestJustified.Epoch { if cpt.Epoch > bestJustified.Epoch {
s.store.SetBestJustifiedCheckpt(cpt) s.store.SetBestJustifiedCheckpt(cpt)
@@ -201,9 +204,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
} }
if canUpdate { if canUpdate {
justified := s.store.JustifiedCheckpt() justified, err := s.store.JustifiedCheckpt()
if justified == nil { if err != nil {
return errNilJustifiedInStore return errors.Wrap(err, "could not get justified checkpoint")
} }
s.store.SetPrevJustifiedCheckpt(justified) s.store.SetPrevJustifiedCheckpt(justified)
h, err := s.getPayloadHash(ctx, cpt.Root) 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. // 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. // 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 { func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpoint) error {
justified := s.store.JustifiedCheckpt() justified, err := s.store.JustifiedCheckpt()
if justified == nil { if err != nil {
return errNilJustifiedInStore return errors.Wrap(err, "could not get justified checkpoint")
} }
s.store.SetPrevJustifiedCheckpt(justified) s.store.SetPrevJustifiedCheckpt(justified)
@@ -345,9 +348,9 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
parentRoot := bytesutil.ToBytes32(blk.ParentRoot()) parentRoot := bytesutil.ToBytes32(blk.ParentRoot())
slot := blk.Slot() slot := blk.Slot()
// Fork choice only matters from last finalized slot. // Fork choice only matters from last finalized slot.
finalized := s.store.FinalizedCheckpt() finalized, err := s.store.FinalizedCheckpt()
if finalized == nil { if err != nil {
return errNilFinalizedInStore return err
} }
fSlot, err := slots.EpochStart(finalized.Epoch) fSlot, err := slots.EpochStart(finalized.Epoch)
if err != nil { if err != nil {

View File

@@ -709,13 +709,17 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
require.NoError(t, s.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: r[:]})) require.NoError(t, s.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: r[:]}))
require.NoError(t, service.updateJustified(context.Background(), s)) 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 // Could not update
service.store.SetBestJustifiedCheckpt(&ethpb.Checkpoint{Root: []byte{'A'}, Epoch: 2}) service.store.SetBestJustifiedCheckpt(&ethpb.Checkpoint{Root: []byte{'A'}, Epoch: 2})
require.NoError(t, service.updateJustified(context.Background(), s)) 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) { func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) {
@@ -1394,9 +1398,13 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
require.NoError(t, service.updateJustifiedInitSync(ctx, newCp)) require.NoError(t, service.updateJustifiedInitSync(ctx, newCp))
assert.DeepSSZEqual(t, currentCp, service.PreviousJustifiedCheckpt(), "Incorrect previous justified checkpoint") cp, err := service.PreviousJustifiedCheckpt()
assert.DeepSSZEqual(t, newCp, service.CurrentJustifiedCheckpt(), "Incorrect current justified checkpoint in cache") require.NoError(t, err)
cp, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx) 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) require.NoError(t, err)
assert.DeepSSZEqual(t, newCp, cp, "Incorrect current justified checkpoint in db") 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) testState, err = service.cfg.StateGen.StateByRoot(ctx, r)
require.NoError(t, err) require.NoError(t, err)
} }
require.Equal(t, types.Epoch(3), service.CurrentJustifiedCheckpt().Epoch) cp, err := service.CurrentJustifiedCheckpt()
require.Equal(t, types.Epoch(2), service.FinalizedCheckpt().Epoch) 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. // The update should persist in DB.
j, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx) j, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx)
require.NoError(t, err) 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) f, err := service.cfg.BeaconDB.FinalizedCheckpoint(ctx)
require.NoError(t, err) 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) { func TestOnBlock_NilBlock(t *testing.T) {

View File

@@ -71,9 +71,9 @@ func (s *Service) VerifyFinalizedConsistency(ctx context.Context, root []byte) e
return nil return nil
} }
f := s.FinalizedCheckpt() f, err := s.FinalizedCheckpt()
if f == nil { if err != nil {
return errNilFinalizedInStore return err
} }
ss, err := slots.EpochStart(f.Epoch) ss, err := slots.EpochStart(f.Epoch)
if err != nil { if err != nil {
@@ -152,9 +152,9 @@ func (s *Service) UpdateHead(ctx context.Context) error {
s.processAttestations(ctx) s.processAttestations(ctx)
justified := s.store.JustifiedCheckpt() justified, err := s.store.JustifiedCheckpt()
if justified == nil { if err != nil {
return errNilJustifiedInStore return err
} }
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(justified.Root)) balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(justified.Root))
if err != nil { if err != nil {

View File

@@ -59,9 +59,9 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaco
} }
// Reports on block and fork choice metrics. // Reports on block and fork choice metrics.
finalized := s.store.FinalizedCheckpt() finalized, err := s.store.FinalizedCheckpt()
if finalized == nil { if err != nil {
return errNilFinalizedInStore return errors.Wrap(err, "could not get finalized checkpoint")
} }
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized) 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. // Reports on blockCopy and fork choice metrics.
finalized := s.store.FinalizedCheckpt() finalized, err := s.store.FinalizedCheckpt()
if finalized == nil { if err != nil {
return errNilFinalizedInStore return errors.Wrap(err, "could not get finalized checkpoint")
} }
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized) 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 { if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
return err 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 { if finalized == nil {
return errNilFinalizedInStore return errNilFinalizedInStore
} }
@@ -169,7 +172,10 @@ func (s *Service) checkSaveHotStateDB(ctx context.Context) error {
currentEpoch := slots.ToEpoch(s.CurrentSlot()) currentEpoch := slots.ToEpoch(s.CurrentSlot())
// Prevent `sinceFinality` going underflow. // Prevent `sinceFinality` going underflow.
var sinceFinality types.Epoch var sinceFinality types.Epoch
finalized := s.store.FinalizedCheckpt() finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return err
}
if finalized == nil { if finalized == nil {
return errNilFinalizedInStore return errNilFinalizedInStore
} }

View File

@@ -277,8 +277,12 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
// Test the start function. // Test the start function.
chainService.Start() chainService.Start()
require.DeepEqual(t, blkRoot[:], chainService.store.FinalizedCheckpt().Root, "Finalize Checkpoint root is incorrect") cp, err := chainService.store.FinalizedCheckpt()
require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], chainService.store.JustifiedCheckpt().Root, "Justified Checkpoint root is incorrect") 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") require.NoError(t, chainService.Stop(), "Unable to stop chain service")

View File

@@ -10,7 +10,10 @@ go_library(
], ],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store", importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store",
visibility = ["//beacon-chain:__subpackages__"], 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( go_test(

View File

@@ -17,9 +17,19 @@ func TestNew(t *testing.T) {
Root: []byte("hello"), Root: []byte("hello"),
} }
s := New(j, f) s := New(j, f)
require.DeepSSZEqual(t, s.JustifiedCheckpt(), j) cp, err := s.JustifiedCheckpt()
require.DeepSSZEqual(t, s.BestJustifiedCheckpt(), j) require.NoError(t, err)
require.DeepSSZEqual(t, s.PrevJustifiedCheckpt(), j) require.DeepSSZEqual(t, j, cp)
require.DeepSSZEqual(t, s.FinalizedCheckpt(), f) cp, err = s.BestJustifiedCheckpt()
require.DeepSSZEqual(t, s.PrevFinalizedCheckpt(), f) 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)
} }

View File

@@ -1,26 +1,42 @@
package store 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. // PrevJustifiedCheckpt returns the previous justified checkpoint in the Store.
func (s *Store) PrevJustifiedCheckpt() *ethpb.Checkpoint { func (s *Store) PrevJustifiedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock() s.RLock()
defer s.RUnlock() 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. // BestJustifiedCheckpt returns the best justified checkpoint in the Store.
func (s *Store) BestJustifiedCheckpt() *ethpb.Checkpoint { func (s *Store) BestJustifiedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock() s.RLock()
defer s.RUnlock() 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. // JustifiedCheckpt returns the justified checkpoint in the Store.
func (s *Store) JustifiedCheckpt() *ethpb.Checkpoint { func (s *Store) JustifiedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock() s.RLock()
defer s.RUnlock() 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. // 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. // PrevFinalizedCheckpt returns the previous finalized checkpoint in the Store.
func (s *Store) PrevFinalizedCheckpt() *ethpb.Checkpoint { func (s *Store) PrevFinalizedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock() s.RLock()
defer s.RUnlock() 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. // FinalizedCheckpt returns the finalized checkpoint in the Store.
func (s *Store) FinalizedCheckpt() *ethpb.Checkpoint { func (s *Store) FinalizedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock() s.RLock()
defer s.RUnlock() 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. // FinalizedPayloadBlockHash returns the finalized payload block hash reflecting finalized check point.

View File

@@ -10,48 +10,63 @@ import (
func Test_store_PrevJustifiedCheckpt(t *testing.T) { func Test_store_PrevJustifiedCheckpt(t *testing.T) {
s := &Store{} s := &Store{}
var cp *ethpb.Checkpoint var cp *ethpb.Checkpoint
require.Equal(t, cp, s.PrevJustifiedCheckpt()) _, err := s.PrevJustifiedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
s.SetPrevJustifiedCheckpt(cp) 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) { func Test_store_BestJustifiedCheckpt(t *testing.T) {
s := &Store{} s := &Store{}
var cp *ethpb.Checkpoint var cp *ethpb.Checkpoint
require.Equal(t, cp, s.BestJustifiedCheckpt()) _, err := s.BestJustifiedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
s.SetBestJustifiedCheckpt(cp) 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) { func Test_store_JustifiedCheckpt(t *testing.T) {
s := &Store{} s := &Store{}
var cp *ethpb.Checkpoint var cp *ethpb.Checkpoint
require.Equal(t, cp, s.JustifiedCheckpt()) _, err := s.JustifiedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
h := [32]byte{'b'} h := [32]byte{'b'}
s.SetJustifiedCheckptAndPayloadHash(cp, h) 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()) require.Equal(t, h, s.JustifiedPayloadBlockHash())
} }
func Test_store_FinalizedCheckpt(t *testing.T) { func Test_store_FinalizedCheckpt(t *testing.T) {
s := &Store{} s := &Store{}
var cp *ethpb.Checkpoint var cp *ethpb.Checkpoint
require.Equal(t, cp, s.FinalizedCheckpt()) _, err := s.FinalizedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
h := [32]byte{'b'} h := [32]byte{'b'}
s.SetFinalizedCheckptAndPayloadHash(cp, h) 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()) require.Equal(t, h, s.FinalizedPayloadBlockHash())
} }
func Test_store_PrevFinalizedCheckpt(t *testing.T) { func Test_store_PrevFinalizedCheckpt(t *testing.T) {
s := &Store{} s := &Store{}
var cp *ethpb.Checkpoint var cp *ethpb.Checkpoint
require.Equal(t, cp, s.PrevFinalizedCheckpt()) _, err := s.PrevFinalizedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}} cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
s.SetPrevFinalizedCheckpt(cp) s.SetPrevFinalizedCheckpt(cp)
require.Equal(t, cp, s.PrevFinalizedCheckpt()) got, err := s.PrevFinalizedCheckpt()
require.NoError(t, err)
require.Equal(t, cp, got)
} }

View File

@@ -282,18 +282,18 @@ func (s *ChainService) CurrentFork() *ethpb.Fork {
} }
// FinalizedCheckpt mocks FinalizedCheckpt method in chain service. // FinalizedCheckpt mocks FinalizedCheckpt method in chain service.
func (s *ChainService) FinalizedCheckpt() *ethpb.Checkpoint { func (s *ChainService) FinalizedCheckpt() (*ethpb.Checkpoint, error) {
return s.FinalizedCheckPoint return s.FinalizedCheckPoint, nil
} }
// CurrentJustifiedCheckpt mocks CurrentJustifiedCheckpt method in chain service. // CurrentJustifiedCheckpt mocks CurrentJustifiedCheckpt method in chain service.
func (s *ChainService) CurrentJustifiedCheckpt() *ethpb.Checkpoint { func (s *ChainService) CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) {
return s.CurrentJustifiedCheckPoint return s.CurrentJustifiedCheckPoint, nil
} }
// PreviousJustifiedCheckpt mocks PreviousJustifiedCheckpt method in chain service. // PreviousJustifiedCheckpt mocks PreviousJustifiedCheckpt method in chain service.
func (s *ChainService) PreviousJustifiedCheckpt() *ethpb.Checkpoint { func (s *ChainService) PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) {
return s.PreviousJustifiedCheckPoint return s.PreviousJustifiedCheckPoint, nil
} }
// ReceiveAttestation mocks ReceiveAttestation method in chain service. // ReceiveAttestation mocks ReceiveAttestation method in chain service.

View File

@@ -80,7 +80,9 @@ func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
wsVerifier: wv, wsVerifier: wv,
} }
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: tt.finalizedEpoch}, [32]byte{}) s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.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 { if tt.wantErr == nil {
require.NoError(t, err) require.NoError(t, err)
} else { } else {

View File

@@ -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") return nil, status.Errorf(codes.NotFound, "No head root was found")
} }
case "finalized": 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 root = finalized.Root
case "genesis": case "genesis":
blk, err := bs.BeaconDB.GenesisBlock(ctx) 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") return nil, errors.Wrap(err, "could not retrieve head block")
} }
case "finalized": 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) finalizedRoot := bytesutil.ToBytes32(finalized.Root)
blk, err = bs.BeaconDB.Block(ctx, finalizedRoot) blk, err = bs.BeaconDB.Block(ctx, finalizedRoot)
if err != nil { if err != nil {

View File

@@ -425,17 +425,26 @@ func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, err
return nil 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 { if err := validateCP(finalizedCheckpoint, "finalized"); err != nil {
return nil, err 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 { if err := validateCP(justifiedCheckpoint, "justified"); err != nil {
return nil, err 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 { if err := validateCP(prevJustifiedCheckpoint, "prev justified"); err != nil {
return nil, err return nil, err
} }

View File

@@ -540,10 +540,13 @@ func (bs *Server) GetValidatorParticipation(
default: default:
return nil, status.Errorf(codes.Internal, "Invalid state type retrieved with a version of %d", beaconState.Version()) 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 := &ethpb.ValidatorParticipationResponse{ p := &ethpb.ValidatorParticipationResponse{
Epoch: requestedEpoch, Epoch: requestedEpoch,
Finalized: requestedEpoch <= bs.FinalizationFetcher.FinalizedCheckpt().Epoch, Finalized: requestedEpoch <= cp.Epoch,
Participation: &ethpb.ValidatorParticipation{ Participation: &ethpb.ValidatorParticipation{
// TODO(7130): Remove these three deprecated fields. // TODO(7130): Remove these three deprecated fields.
GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch), GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch),

View File

@@ -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") return nil, errors.Wrap(err, "could not get genesis state")
} }
case "finalized": 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)) s, err = p.StateGenService.StateByRoot(ctx, bytesutil.ToBytes32(checkpoint.Root))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get finalized state") return nil, errors.Wrap(err, "could not get finalized state")
} }
case "justified": 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)) s, err = p.StateGenService.StateByRoot(ctx, bytesutil.ToBytes32(checkpoint.Root))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get justified state") return nil, errors.Wrap(err, "could not get justified state")

View File

@@ -73,7 +73,11 @@ func (f *blocksFetcher) waitForMinimumPeers(ctx context.Context) ([]peer.ID, err
} }
var peers []peer.ID var peers []peer.ID
if f.mode == modeStopOnFinalizedEpoch { 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) _, peers = f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
} else { } else {
headEpoch := slots.ToEpoch(f.chain.HeadSlot()) headEpoch := slots.ToEpoch(f.chain.HeadSlot())

View File

@@ -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, // The current slot's epoch must be after the finalization epoch,
// triggering backtracking on earlier epochs is unnecessary. // 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) epoch := slots.ToEpoch(slot)
if epoch <= finalizedEpoch { if epoch <= finalizedEpoch {
return nil, errors.New("slot is not after the finalized epoch, no backtracking is necessary") 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). // 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 { if err != nil {
return nil, err 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. // bestFinalizedSlot returns the highest finalized slot of the majority of connected peers.
func (f *blocksFetcher) bestFinalizedSlot() types.Slot { 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( finalizedEpoch, _ := f.p2p.Peers().BestFinalized(
params.BeaconConfig().MaxPeersToSync, f.chain.FinalizedCheckpt().Epoch) params.BeaconConfig().MaxPeersToSync, cp.Epoch)
return params.BeaconConfig().SlotsPerEpoch.Mul(uint64(finalizedEpoch)) 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. // epoch. For the latter peers supporting that target epoch are returned as well.
func (f *blocksFetcher) calculateHeadAndTargetEpochs() (headEpoch, targetEpoch types.Epoch, peers []peer.ID) { func (f *blocksFetcher) calculateHeadAndTargetEpochs() (headEpoch, targetEpoch types.Epoch, peers []peer.ID) {
if f.mode == modeStopOnFinalizedEpoch { 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) targetEpoch, peers = f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
} else { } else {
headEpoch = slots.ToEpoch(f.chain.HeadSlot()) headEpoch = slots.ToEpoch(f.chain.HeadSlot())

View File

@@ -1321,7 +1321,9 @@ func TestBlocksQueue_stuckWhenHeadIsSetToOrphanedBlock(t *testing.T) {
require.NoError(t, queue.start()) require.NoError(t, queue.start())
isProcessedBlock := func(ctx context.Context, blk interfaces.SignedBeaconBlock, blkRoot [32]byte) bool { 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 { if err != nil {
return false return false
} }

View File

@@ -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. // 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 { 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 { if err != nil {
return false return false
} }

View File

@@ -173,7 +173,12 @@ func (s *Service) waitForMinimumPeers() {
required = flags.Get().MinimumSyncPeers required = flags.Get().MinimumSyncPeers
} }
for { 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 { if len(peers) >= required {
break break
} }

View File

@@ -210,8 +210,11 @@ func (s *Service) sendBatchRootRequest(ctx context.Context, roots [][32]byte, ra
if len(roots) == 0 { if len(roots) == 0 {
return nil return nil
} }
cp, err := s.cfg.chain.FinalizedCheckpt()
_, bestPeers := s.cfg.p2p.Peers().BestFinalized(maxPeerRequest, s.cfg.chain.FinalizedCheckpt().Epoch) if err != nil {
return err
}
_, bestPeers := s.cfg.p2p.Peers().BestFinalized(maxPeerRequest, cp.Epoch)
if len(bestPeers) == 0 { if len(bestPeers) == 0 {
return nil return nil
} }
@@ -272,7 +275,11 @@ func (s *Service) validatePendingSlots() error {
defer s.pendingQueueLock.Unlock() defer s.pendingQueueLock.Unlock()
oldBlockRoots := make(map[[32]byte]bool) 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 { if s.slotToPendingBlocks == nil {
return errors.New("slotToPendingBlocks cache can't be nil") return errors.New("slotToPendingBlocks cache can't be nil")
} }

View File

@@ -131,10 +131,14 @@ func (s *Service) sendRPCStatusRequest(ctx context.Context, id peer.ID) error {
if err != nil { if err != nil {
return err return err
} }
cp, err := s.cfg.chain.FinalizedCheckpt()
if err != nil {
return err
}
resp := &pb.Status{ resp := &pb.Status{
ForkDigest: forkDigest[:], ForkDigest: forkDigest[:],
FinalizedRoot: s.cfg.chain.FinalizedCheckpt().Root, FinalizedRoot: cp.Root,
FinalizedEpoch: s.cfg.chain.FinalizedCheckpt().Epoch, FinalizedEpoch: cp.Epoch,
HeadRoot: headRoot, HeadRoot: headRoot,
HeadSlot: s.cfg.chain.HeadSlot(), HeadSlot: s.cfg.chain.HeadSlot(),
} }
@@ -260,10 +264,14 @@ func (s *Service) respondWithStatus(ctx context.Context, stream network.Stream)
if err != nil { if err != nil {
return err return err
} }
cp, err := s.cfg.chain.FinalizedCheckpt()
if err != nil {
return err
}
resp := &pb.Status{ resp := &pb.Status{
ForkDigest: forkDigest[:], ForkDigest: forkDigest[:],
FinalizedRoot: s.cfg.chain.FinalizedCheckpt().Root, FinalizedRoot: cp.Root,
FinalizedEpoch: s.cfg.chain.FinalizedCheckpt().Epoch, FinalizedEpoch: cp.Epoch,
HeadRoot: headRoot, HeadRoot: headRoot,
HeadSlot: s.cfg.chain.HeadSlot(), HeadSlot: s.cfg.chain.HeadSlot(),
} }
@@ -284,7 +292,11 @@ func (s *Service) validateStatusMessage(ctx context.Context, msg *pb.Status) err
return p2ptypes.ErrWrongForkDigestVersion return p2ptypes.ErrWrongForkDigestVersion
} }
genesis := s.cfg.chain.GenesisTime() 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) maxEpoch := slots.EpochsSinceGenesis(genesis)
// It would take a minimum of 2 epochs to finalize a // It would take a minimum of 2 epochs to finalize a
// previous epoch // previous epoch

View File

@@ -131,7 +131,11 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms
return pubsub.ValidationIgnore, nil 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 { if err != nil {
log.WithError(err).WithFields(getBlockFields(blk)).Debug("Ignored block: could not calculate epoch start slot") log.WithError(err).WithFields(getBlockFields(blk)).Debug("Ignored block: could not calculate epoch start slot")
return pubsub.ValidationIgnore, nil return pubsub.ValidationIgnore, nil

View File

@@ -103,21 +103,27 @@ func (bb *Builder) Check(t testing.TB, c *Check) {
Epoch: types.Epoch(c.JustifiedCheckPoint.Epoch), Epoch: types.Epoch(c.JustifiedCheckPoint.Epoch),
Root: common.FromHex(c.JustifiedCheckPoint.Root), 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 { if c.BestJustifiedCheckPoint != nil {
cp := &ethpb.Checkpoint{ cp := &ethpb.Checkpoint{
Epoch: types.Epoch(c.BestJustifiedCheckPoint.Epoch), Epoch: types.Epoch(c.BestJustifiedCheckPoint.Epoch),
Root: common.FromHex(c.BestJustifiedCheckPoint.Root), 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 { if c.FinalizedCheckPoint != nil {
cp := &ethpb.Checkpoint{ cp := &ethpb.Checkpoint{
Epoch: types.Epoch(c.FinalizedCheckPoint.Epoch), Epoch: types.Epoch(c.FinalizedCheckPoint.Epoch),
Root: common.FromHex(c.FinalizedCheckPoint.Root), 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 { if c.ProposerBoostRoot != nil {
want := fmt.Sprintf("%#x", common.FromHex(*c.ProposerBoostRoot)) want := fmt.Sprintf("%#x", common.FromHex(*c.ProposerBoostRoot))