mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 23:48:06 -05:00
Handle nil head block in cache (#4888)
* Nil check * Fixed tests * Covered rest of the codebase * Race tests Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
@@ -32,7 +32,7 @@ type TimeFetcher interface {
|
|||||||
type HeadFetcher interface {
|
type HeadFetcher interface {
|
||||||
HeadSlot() uint64
|
HeadSlot() uint64
|
||||||
HeadRoot(ctx context.Context) ([]byte, error)
|
HeadRoot(ctx context.Context) ([]byte, error)
|
||||||
HeadBlock() *ethpb.SignedBeaconBlock
|
HeadBlock(ctx context.Context) (*ethpb.SignedBeaconBlock, error)
|
||||||
HeadState(ctx context.Context) (*state.BeaconState, error)
|
HeadState(ctx context.Context) (*state.BeaconState, error)
|
||||||
HeadValidatorsIndices(epoch uint64) ([]uint64, error)
|
HeadValidatorsIndices(epoch uint64) ([]uint64, error)
|
||||||
HeadSeed(epoch uint64) ([32]byte, error)
|
HeadSeed(epoch uint64) ([32]byte, error)
|
||||||
@@ -135,23 +135,25 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HeadBlock returns the head block of the chain.
|
// HeadBlock returns the head block of the chain.
|
||||||
func (s *Service) HeadBlock() *ethpb.SignedBeaconBlock {
|
// If the head state is nil from service struct,
|
||||||
return s.headBlock()
|
// it will attempt to get the head block from DB.
|
||||||
|
func (s *Service) HeadBlock(ctx context.Context) (*ethpb.SignedBeaconBlock, error) {
|
||||||
|
if s.hasHeadState() {
|
||||||
|
return s.headBlock(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.beaconDB.HeadBlock(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadState returns the head state of the chain.
|
// HeadState returns the head state of the chain.
|
||||||
// If the head state is nil from service struct,
|
// If the head state is nil from service struct,
|
||||||
// it will attempt to get from DB and error if nil again.
|
// it will attempt to get the head state from DB.
|
||||||
func (s *Service) HeadState(ctx context.Context) (*state.BeaconState, error) {
|
func (s *Service) HeadState(ctx context.Context) (*state.BeaconState, error) {
|
||||||
if s.hasHeadState() {
|
if s.hasHeadState() {
|
||||||
return s.headState(), nil
|
return s.headState(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
headState, err := s.beaconDB.HeadState(ctx)
|
return s.beaconDB.HeadState(ctx)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return headState, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadValidatorsIndices returns a list of active validator indices from the head view of a given epoch.
|
// HeadValidatorsIndices returns a list of active validator indices from the head view of a given epoch.
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func TestHeadBlock_DataRace(t *testing.T) {
|
|||||||
[32]byte{},
|
[32]byte{},
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
s.HeadBlock()
|
s.HeadBlock(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHeadState_DataRace(t *testing.T) {
|
func TestHeadState_DataRace(t *testing.T) {
|
||||||
|
|||||||
@@ -145,10 +145,16 @@ func TestHeadRoot_CanRetrieve(t *testing.T) {
|
|||||||
|
|
||||||
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||||
|
s, _ := state.InitializeFromProto(&pb.BeaconState{})
|
||||||
c := &Service{}
|
c := &Service{}
|
||||||
c.head = &head{block: b}
|
c.head = &head{block: b, state: s}
|
||||||
|
|
||||||
if !reflect.DeepEqual(b, c.HeadBlock()) {
|
recevied, err := c.HeadBlock(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(b, recevied) {
|
||||||
t.Error("incorrect head block received")
|
t.Error("incorrect head block received")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,7 +305,11 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
|||||||
if _, err := bc.HeadState(ctx); err != nil {
|
if _, err := bc.HeadState(ctx); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if bc.HeadBlock() == nil {
|
headBlk, err := bc.HeadBlock(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if headBlk == nil {
|
||||||
t.Error("Head state can't be nil after initialize beacon chain")
|
t.Error("Head state can't be nil after initialize beacon chain")
|
||||||
}
|
}
|
||||||
if bc.headRoot() == params.BeaconConfig().ZeroHash {
|
if bc.headRoot() == params.BeaconConfig().ZeroHash {
|
||||||
@@ -356,7 +360,11 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
|||||||
if err := c.initializeChainInfo(ctx); err != nil {
|
if err := c.initializeChainInfo(ctx); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(c.HeadBlock(), headBlock) {
|
headBlk, err := c.HeadBlock(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(headBlk, headBlock) {
|
||||||
t.Error("head block incorrect")
|
t.Error("head block incorrect")
|
||||||
}
|
}
|
||||||
s, err := c.HeadState(ctx)
|
s, err := c.HeadState(ctx)
|
||||||
|
|||||||
@@ -160,8 +160,8 @@ func (ms *ChainService) HeadRoot(ctx context.Context) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HeadBlock mocks HeadBlock method in chain service.
|
// HeadBlock mocks HeadBlock method in chain service.
|
||||||
func (ms *ChainService) HeadBlock() *ethpb.SignedBeaconBlock {
|
func (ms *ChainService) HeadBlock(context.Context) (*ethpb.SignedBeaconBlock, error) {
|
||||||
return ms.Block
|
return ms.Block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadState mocks HeadState method in chain service.
|
// HeadState mocks HeadState method in chain service.
|
||||||
|
|||||||
@@ -237,7 +237,10 @@ func (bs *Server) StreamChainHead(_ *ptypes.Empty, stream ethpb.BeaconChain_Stre
|
|||||||
|
|
||||||
// Retrieve chain head information from the DB and the current beacon state.
|
// Retrieve chain head information from the DB and the current beacon state.
|
||||||
func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, error) {
|
func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, error) {
|
||||||
headBlock := bs.HeadFetcher.HeadBlock()
|
headBlock, err := bs.HeadFetcher.HeadBlock(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.Internal, "Could not get head block")
|
||||||
|
}
|
||||||
if headBlock == nil {
|
if headBlock == nil {
|
||||||
return nil, status.Error(codes.Internal, "Head block of chain was nil")
|
return nil, status.Error(codes.Internal, "Head block of chain was nil")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,11 @@ func (vs *Server) DomainData(ctx context.Context, request *ethpb.DomainRequest)
|
|||||||
// CanonicalHead of the current beacon chain. This method is requested on-demand
|
// CanonicalHead of the current beacon chain. This method is requested on-demand
|
||||||
// by a validator when it is their time to propose or attest.
|
// by a validator when it is their time to propose or attest.
|
||||||
func (vs *Server) CanonicalHead(ctx context.Context, req *ptypes.Empty) (*ethpb.SignedBeaconBlock, error) {
|
func (vs *Server) CanonicalHead(ctx context.Context, req *ptypes.Empty) (*ethpb.SignedBeaconBlock, error) {
|
||||||
return vs.HeadFetcher.HeadBlock(), nil
|
headBlk, err := vs.HeadFetcher.HeadBlock(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not get head block: %v", err)
|
||||||
|
}
|
||||||
|
return headBlk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitForChainStart queries the logs of the Deposit Contract in order to verify the beacon chain
|
// WaitForChainStart queries the logs of the Deposit Contract in order to verify the beacon chain
|
||||||
|
|||||||
Reference in New Issue
Block a user