From 26da7c41143bd81d6af43089876dd9b683ff7245 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Tue, 19 Nov 2019 08:12:50 -0800 Subject: [PATCH] Nil state fallback in Blockchain.HeadState() (#4042) * Can build * All tests pass * Update beacon-chain/blockchain/chain_info.go * Fix context --- beacon-chain/archiver/service.go | 6 +- beacon-chain/blockchain/chain_info.go | 21 ++++++- .../blockchain/chain_info_norace_test.go | 2 +- beacon-chain/blockchain/chain_info_test.go | 6 +- beacon-chain/blockchain/service_test.go | 12 ++-- beacon-chain/blockchain/testing/mock.go | 4 +- beacon-chain/rpc/attester/server.go | 13 ++-- beacon-chain/rpc/beacon/assignments.go | 5 +- beacon-chain/rpc/beacon/blocks.go | 10 +++- beacon-chain/rpc/beacon/committees.go | 7 ++- beacon-chain/rpc/beacon/validators.go | 29 +++++++-- beacon-chain/rpc/proposer/server.go | 27 ++++++--- beacon-chain/rpc/validator/assignments.go | 15 +---- .../rpc/validator/assignments_test.go | 60 ------------------- beacon-chain/rpc/validator/server.go | 6 +- beacon-chain/rpc/validator/status.go | 13 ++-- beacon-chain/sync/initial-sync/service.go | 9 ++- beacon-chain/sync/subscriber_beacon_blocks.go | 6 +- .../sync/validate_attester_slashing.go | 5 +- .../sync/validate_proposer_slashing.go | 5 +- beacon-chain/sync/validate_voluntary_exit.go | 6 +- 21 files changed, 142 insertions(+), 125 deletions(-) diff --git a/beacon-chain/archiver/service.go b/beacon-chain/archiver/service.go index f05feb84b7..b8301a16e5 100644 --- a/beacon-chain/archiver/service.go +++ b/beacon-chain/archiver/service.go @@ -141,7 +141,11 @@ func (s *Service) run(ctx context.Context) { case statefeed.BlockProcessed: data := event.Data.(*statefeed.BlockProcessedData) log.WithField("headRoot", fmt.Sprintf("%#x", data.BlockRoot)).Debug("Received block processed event") - headState := s.headFetcher.HeadState() + headState, err := s.headFetcher.HeadState(ctx) + if err != nil { + log.WithError(err).Error("Head state is not available") + continue + } if !helpers.IsEpochEnd(headState.Slot) { continue } diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index 036ea9880b..db5bfa4255 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -1,6 +1,8 @@ package blockchain import ( + "context" + "errors" "time" "github.com/gogo/protobuf/proto" @@ -28,7 +30,7 @@ type HeadFetcher interface { HeadSlot() uint64 HeadRoot() []byte HeadBlock() *ethpb.BeaconBlock - HeadState() *pb.BeaconState + HeadState(ctx context.Context) (*pb.BeaconState, error) } // CanonicalRootFetcher defines a common interface for methods in blockchain service which @@ -88,11 +90,24 @@ func (s *Service) HeadBlock() *ethpb.BeaconBlock { } // HeadState returns the head state of the chain. -func (s *Service) HeadState() *pb.BeaconState { +// If the head state is nil from service struct, +// it will attempt to get from DB and error if nil again. +func (s *Service) HeadState(ctx context.Context) (*pb.BeaconState, error) { s.headLock.RLock() defer s.headLock.RUnlock() - return proto.Clone(s.headState).(*pb.BeaconState) + if s.headState == nil { + h, err := s.beaconDB.HeadState(ctx) + if err != nil { + return nil, err + } + if h == nil { + return nil, errors.New("head state does not exist") + } + return h, nil + } + + return proto.Clone(s.headState).(*pb.BeaconState), nil } // CanonicalRoot returns the canonical root of a given slot. diff --git a/beacon-chain/blockchain/chain_info_norace_test.go b/beacon-chain/blockchain/chain_info_norace_test.go index fd971c5561..032a357c93 100644 --- a/beacon-chain/blockchain/chain_info_norace_test.go +++ b/beacon-chain/blockchain/chain_info_norace_test.go @@ -73,5 +73,5 @@ func TestHeadState_DataRace(t *testing.T) { [32]byte{}, ) }() - s.HeadState() + s.HeadState(context.Background()) } diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index 568d90e546..01dab1543f 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -76,7 +76,11 @@ func TestHeadBlock_CanRetrieve(t *testing.T) { func TestHeadState_CanRetrieve(t *testing.T) { s := &pb.BeaconState{Slot: 2} c := &Service{headState: s} - if !reflect.DeepEqual(s, c.HeadState()) { + headState, err := c.HeadState(context.Background()) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(s, headState) { t.Error("incorrect head state received") } } diff --git a/beacon-chain/blockchain/service_test.go b/beacon-chain/blockchain/service_test.go index 81b438d3af..a5bdd685d1 100644 --- a/beacon-chain/blockchain/service_test.go +++ b/beacon-chain/blockchain/service_test.go @@ -343,8 +343,8 @@ func TestChainService_InitializeBeaconChain(t *testing.T) { } } - if bc.HeadState() == nil { - t.Error("Head state can't be nil after initialize beacon chain") + if _, err := bc.HeadState(ctx); err != nil { + t.Error(err) } if bc.HeadBlock() == nil { t.Error("Head state can't be nil after initialize beacon chain") @@ -397,8 +397,12 @@ func TestChainService_InitializeChainInfo(t *testing.T) { if !reflect.DeepEqual(c.HeadBlock(), headBlock) { t.Error("head block incorrect") } - if !reflect.DeepEqual(c.HeadState(), headState) { - t.Error("head block incorrect") + s, err := c.HeadState(ctx) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(s, headState) { + t.Error("head state incorrect") } if headBlock.Slot != c.HeadSlot() { t.Error("head slot incorrect") diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index aea1657498..b2b7f08176 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -86,8 +86,8 @@ func (ms *ChainService) HeadBlock() *ethpb.BeaconBlock { } // HeadState mocks HeadState method in chain service. -func (ms *ChainService) HeadState() *pb.BeaconState { - return ms.State +func (ms *ChainService) HeadState(context.Context) (*pb.BeaconState, error) { + return ms.State, nil } // CurrentFork mocks HeadState method in chain service. diff --git a/beacon-chain/rpc/attester/server.go b/beacon-chain/rpc/attester/server.go index 94015a0bb7..e1242f4945 100644 --- a/beacon-chain/rpc/attester/server.go +++ b/beacon-chain/rpc/attester/server.go @@ -105,16 +105,11 @@ func (as *Server) RequestAttestation(ctx context.Context, req *pb.AttestationReq } }() - headState := as.HeadFetcher.HeadState() - headRoot := as.HeadFetcher.HeadRoot() - - // Safe guard against head state is nil in chain service. This should not happen. - if headState == nil { - headState, err = as.BeaconDB.HeadState(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not retrieve head state: %v", err) - } + headState, err := as.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not retrieve head state: %v", err) } + headRoot := as.HeadFetcher.HeadRoot() headState, err = state.ProcessSlots(ctx, headState, req.Slot) if err != nil { diff --git a/beacon-chain/rpc/beacon/assignments.go b/beacon-chain/rpc/beacon/assignments.go index 814d99ad06..0196eac1e0 100644 --- a/beacon-chain/rpc/beacon/assignments.go +++ b/beacon-chain/rpc/beacon/assignments.go @@ -27,7 +27,10 @@ func (bs *Server) ListValidatorAssignments( } var res []*ethpb.ValidatorAssignments_CommitteeAssignment - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } filtered := map[uint64]bool{} // track filtered validators to prevent duplication in the response. filteredIndices := make([]uint64, 0) requestedEpoch := helpers.CurrentEpoch(headState) diff --git a/beacon-chain/rpc/beacon/blocks.go b/beacon-chain/rpc/beacon/blocks.go index ebc9f71f55..8ed48f699d 100644 --- a/beacon-chain/rpc/beacon/blocks.go +++ b/beacon-chain/rpc/beacon/blocks.go @@ -146,9 +146,13 @@ func (bs *Server) ListBlocks( // This includes the head block slot and root as well as information about // the most recent finalized and justified slots. func (bs *Server) GetChainHead(ctx context.Context, _ *ptypes.Empty) (*ethpb.ChainHead, error) { - finalizedCheckpoint := bs.HeadFetcher.HeadState().FinalizedCheckpoint - justifiedCheckpoint := bs.HeadFetcher.HeadState().CurrentJustifiedCheckpoint - prevJustifiedCheckpoint := bs.HeadFetcher.HeadState().PreviousJustifiedCheckpoint + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "Could not get head state") + } + finalizedCheckpoint := headState.FinalizedCheckpoint + justifiedCheckpoint := headState.CurrentJustifiedCheckpoint + prevJustifiedCheckpoint := headState.PreviousJustifiedCheckpoint return ðpb.ChainHead{ BlockRoot: bs.HeadFetcher.HeadRoot(), diff --git a/beacon-chain/rpc/beacon/committees.go b/beacon-chain/rpc/beacon/committees.go index 5188221310..96ea0441c1 100644 --- a/beacon-chain/rpc/beacon/committees.go +++ b/beacon-chain/rpc/beacon/committees.go @@ -30,7 +30,11 @@ func (bs *Server) ListBeaconCommittees( ) } - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } + var requestingGenesis bool var startSlot uint64 switch q := req.QueryFilter.(type) { @@ -44,7 +48,6 @@ func (bs *Server) ListBeaconCommittees( var attesterSeed [32]byte var activeIndices []uint64 - var err error // This is the archival condition, if the requested epoch is < current epoch or if we are // requesting data from the genesis epoch. if requestingGenesis || helpers.SlotToEpoch(startSlot) < helpers.SlotToEpoch(headState.Slot) { diff --git a/beacon-chain/rpc/beacon/validators.go b/beacon-chain/rpc/beacon/validators.go index d254ad1409..a18c8d297c 100644 --- a/beacon-chain/rpc/beacon/validators.go +++ b/beacon-chain/rpc/beacon/validators.go @@ -32,7 +32,11 @@ func (bs *Server) ListValidatorBalances( res := make([]*ethpb.ValidatorBalances_Balance, 0) filtered := map[uint64]bool{} // track filtered validators to prevent duplication in the response. - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } + var requestingGenesis bool var epoch uint64 switch q := req.QueryFilter.(type) { @@ -45,7 +49,6 @@ func (bs *Server) ListValidatorBalances( } var balances []uint64 - var err error validators := headState.Validators if requestingGenesis || epoch < helpers.CurrentEpoch(headState) { balances, err = bs.BeaconDB.ArchivedBalances(ctx, epoch) @@ -168,9 +171,13 @@ func (bs *Server) GetValidators( req.PageSize, params.BeaconConfig().MaxPageSize) } - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } currentEpoch := helpers.CurrentEpoch(headState) requestedEpoch := currentEpoch + switch q := req.QueryFilter.(type) { case *ethpb.GetValidatorsRequest_Genesis: if q.Genesis { @@ -236,10 +243,14 @@ func (bs *Server) GetValidators( func (bs *Server) GetValidatorActiveSetChanges( ctx context.Context, req *ethpb.GetValidatorActiveSetChangesRequest, ) (*ethpb.ActiveSetChanges, error) { - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } currentEpoch := helpers.CurrentEpoch(headState) requestedEpoch := currentEpoch requestingGenesis := false + switch q := req.QueryFilter.(type) { case *ethpb.GetValidatorActiveSetChangesRequest_Genesis: requestingGenesis = q.Genesis @@ -314,7 +325,10 @@ func (bs *Server) GetValidatorActiveSetChanges( func (bs *Server) GetValidatorParticipation( ctx context.Context, req *ethpb.GetValidatorParticipationRequest, ) (*ethpb.ValidatorParticipationResponse, error) { - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } currentEpoch := helpers.SlotToEpoch(headState.Slot) prevEpoch := helpers.PrevEpoch(headState) @@ -376,7 +390,10 @@ func (bs *Server) GetValidatorParticipation( func (bs *Server) GetValidatorQueue( ctx context.Context, _ *ptypes.Empty, ) (*ethpb.ValidatorQueue, error) { - headState := bs.HeadFetcher.HeadState() + headState, err := bs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } // Queue the validators whose eligible to activate and sort them by activation eligibility epoch number. // Additionally, determine those validators queued to exit awaitingExit := make([]uint64, 0) diff --git a/beacon-chain/rpc/proposer/server.go b/beacon-chain/rpc/proposer/server.go index ca2320e408..b289bd3fff 100644 --- a/beacon-chain/rpc/proposer/server.go +++ b/beacon-chain/rpc/proposer/server.go @@ -149,11 +149,11 @@ func (ps *Server) ProposeBlock(ctx context.Context, blk *ethpb.BeaconBlock) (*pb // - This is the eth1block to use for the block proposal. func (ps *Server) eth1Data(ctx context.Context, slot uint64) (*ethpb.Eth1Data, error) { if ps.MockEth1Votes { - return ps.mockETH1DataVote(slot) + return ps.mockETH1DataVote(ctx, slot) } if !ps.Eth1InfoFetcher.IsConnectedToETH1() { - return ps.randomETH1DataVote() + return ps.randomETH1DataVote(ctx) } eth1VotingPeriodStartTime, _ := ps.Eth1InfoFetcher.Eth2GenesisPowchainInfo() @@ -168,7 +168,7 @@ func (ps *Server) eth1Data(ctx context.Context, slot uint64) (*ethpb.Eth1Data, e return ps.defaultEth1DataResponse(ctx, blockNumber) } -func (ps *Server) mockETH1DataVote(slot uint64) (*ethpb.Eth1Data, error) { +func (ps *Server) mockETH1DataVote(ctx context.Context, slot uint64) (*ethpb.Eth1Data, error) { log.Warn("Beacon Node is no longer connected to an ETH1 Chain, so " + "ETH1 Data votes are now mocked.") // If a mock eth1 data votes is specified, we use the following for the @@ -181,7 +181,10 @@ func (ps *Server) mockETH1DataVote(slot uint64) (*ethpb.Eth1Data, error) { // BlockHash = hash(hash(current_epoch + slot_in_voting_period)), // ) slotInVotingPeriod := slot % params.BeaconConfig().SlotsPerEth1VotingPeriod - headState := ps.HeadFetcher.HeadState() + headState, err := ps.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, err + } enc, err := ssz.Marshal(helpers.SlotToEpoch(slot) + slotInVotingPeriod) if err != nil { return nil, err @@ -195,10 +198,13 @@ func (ps *Server) mockETH1DataVote(slot uint64) (*ethpb.Eth1Data, error) { }, nil } -func (ps *Server) randomETH1DataVote() (*ethpb.Eth1Data, error) { +func (ps *Server) randomETH1DataVote(ctx context.Context) (*ethpb.Eth1Data, error) { log.Warn("Beacon Node is no longer connected to an ETH1 Chain, so " + "ETH1 Data votes are now random.") - headState := ps.HeadFetcher.HeadState() + headState, err := ps.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, err + } // set random roots and block hashes to prevent a majority from being // built if the eth1 node is offline depRoot := hashutil.Hash(bytesutil.Bytes32(rand.Uint64())) @@ -242,8 +248,11 @@ func (ps *Server) deposits(ctx context.Context, currentVote *ethpb.Eth1Data) ([] } // Need to fetch if the deposits up to the state's latest eth 1 data matches // the number of all deposits in this RPC call. If not, then we return nil. - beaconState := ps.HeadFetcher.HeadState() - canonicalEth1Data, latestEth1DataHeight, err := ps.canonicalEth1Data(ctx, beaconState, currentVote) + headState, err := ps.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } + canonicalEth1Data, latestEth1DataHeight, err := ps.canonicalEth1Data(ctx, headState, currentVote) if err != nil { return nil, err } @@ -274,7 +283,7 @@ func (ps *Server) deposits(ctx context.Context, currentVote *ethpb.Eth1Data) ([] // deposits are sorted from lowest to highest. var pendingDeps []*depositcache.DepositContainer for _, dep := range allPendingContainers { - if uint64(dep.Index) >= beaconState.Eth1DepositIndex && uint64(dep.Index) < canonicalEth1Data.DepositCount { + if uint64(dep.Index) >= headState.Eth1DepositIndex && uint64(dep.Index) < canonicalEth1Data.DepositCount { pendingDeps = append(pendingDeps, dep) } } diff --git a/beacon-chain/rpc/validator/assignments.go b/beacon-chain/rpc/validator/assignments.go index 5467c73f19..46e36277f6 100644 --- a/beacon-chain/rpc/validator/assignments.go +++ b/beacon-chain/rpc/validator/assignments.go @@ -23,18 +23,9 @@ func (vs *Server) CommitteeAssignment(ctx context.Context, req *pb.AssignmentReq return nil, status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond") } - var err error - s := vs.HeadFetcher.HeadState() - - // if the head state is nil, retrieve it from DB. - if s == nil { - s, err = vs.BeaconDB.HeadState(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) - } - if s == nil { - return nil, status.Error(codes.Internal, "Head state does not exist") - } + s, err := vs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) } // Advance state with empty transitions up to the requested epoch start slot. diff --git a/beacon-chain/rpc/validator/assignments_test.go b/beacon-chain/rpc/validator/assignments_test.go index 33801d56b0..a4e90f5b01 100644 --- a/beacon-chain/rpc/validator/assignments_test.go +++ b/beacon-chain/rpc/validator/assignments_test.go @@ -288,63 +288,3 @@ func TestCommitteeAssignment_SyncNotReady(t *testing.T) { t.Error("Did not get wanted error") } } - -func TestCommitteeAssignment_NilHeadState(t *testing.T) { - helpers.ClearAllCaches() - db := dbutil.SetupDB(t) - defer dbutil.TeardownDB(t, db) - ctx := context.Background() - - genesis := blk.NewGenesisBlock([]byte{}) - depChainStart := uint64(64) - - deposits, _, _ := testutil.SetupInitialDeposits(t, depChainStart) - state, err := state.GenesisBeaconState(deposits, 0, ðpb.Eth1Data{BlockHash: make([]byte, 32)}) - if err != nil { - t.Fatalf("Could not setup genesis state: %v", err) - } - genesisRoot, err := ssz.SigningRoot(genesis) - if err != nil { - t.Fatalf("Could not get signing root %v", err) - } - - var wg sync.WaitGroup - numOfValidators := int(depChainStart) - errs := make(chan error, numOfValidators) - for i := 0; i < len(deposits); i++ { - wg.Add(1) - go func(index int) { - errs <- db.SaveValidatorIndex(ctx, bytesutil.ToBytes48(deposits[index].Data.PublicKey), uint64(index)) - wg.Done() - }(i) - } - wg.Wait() - close(errs) - for err := range errs { - if err != nil { - t.Fatalf("Could not save validator index: %v", err) - } - } - - vs := &Server{ - BeaconDB: db, - HeadFetcher: &mockChain.ChainService{Root: genesisRoot[:]}, - SyncChecker: &mockSync.Sync{IsSyncing: false}, - } - vs.BeaconDB.SaveState(ctx, state, genesisRoot) - vs.BeaconDB.SaveHeadBlockRoot(ctx, genesisRoot) - - // Test the first validator in registry. - req := &pb.AssignmentRequest{ - PublicKeys: [][]byte{deposits[0].Data.PublicKey}, - EpochStart: 0, - } - res, err := vs.CommitteeAssignment(context.Background(), req) - if err != nil { - t.Fatalf("Could not call epoch committee assignment %v", err) - } - if res.ValidatorAssignment[0].AttesterSlot > state.Slot+params.BeaconConfig().SlotsPerEpoch { - t.Errorf("Assigned slot %d can't be higher than %d", - res.ValidatorAssignment[0].AttesterSlot, state.Slot+params.BeaconConfig().SlotsPerEpoch) - } -} diff --git a/beacon-chain/rpc/validator/server.go b/beacon-chain/rpc/validator/server.go index 30bbba93ba..a5a9760f2f 100644 --- a/beacon-chain/rpc/validator/server.go +++ b/beacon-chain/rpc/validator/server.go @@ -108,7 +108,11 @@ func (vs *Server) ValidatorPerformance( ctx context.Context, req *pb.ValidatorPerformanceRequest, ) (*pb.ValidatorPerformanceResponse, error) { var err error - headState := vs.HeadFetcher.HeadState() + headState, err := vs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } + // Advance state with empty transitions up to the requested epoch start slot. if req.Slot > headState.Slot { headState, err = state.ProcessSlots(ctx, headState, req.Slot) diff --git a/beacon-chain/rpc/validator/status.go b/beacon-chain/rpc/validator/status.go index cadf017e0e..aab6a50ea2 100644 --- a/beacon-chain/rpc/validator/status.go +++ b/beacon-chain/rpc/validator/status.go @@ -13,6 +13,8 @@ import ( "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/traceutil" "go.opencensus.io/trace" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var errPubkeyDoesNotExist = errors.New("pubkey does not exist") @@ -28,7 +30,10 @@ var errPubkeyDoesNotExist = errors.New("pubkey does not exist") func (vs *Server) ValidatorStatus( ctx context.Context, req *pb.ValidatorIndexRequest) (*pb.ValidatorStatusResponse, error) { - headState := vs.HeadFetcher.HeadState() + headState, err := vs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Error(codes.Internal, "Could not get head state") + } return vs.validatorStatus(ctx, req.PublicKey, headState), nil } @@ -38,9 +43,9 @@ func (vs *Server) multipleValidatorStatus( ctx context.Context, pubkeys [][]byte, ) (bool, []*pb.ValidatorActivationResponse_Status, error) { - headState := vs.HeadFetcher.HeadState() - if headState == nil { - return false, nil, nil + headState, err := vs.HeadFetcher.HeadState(ctx) + if err != nil { + return false, nil, err } activeValidatorExists := false statusResponses := make([]*pb.ValidatorActivationResponse_Status, len(pubkeys)) diff --git a/beacon-chain/sync/initial-sync/service.go b/beacon-chain/sync/initial-sync/service.go index d5fab504dc..b9e76ff04c 100644 --- a/beacon-chain/sync/initial-sync/service.go +++ b/beacon-chain/sync/initial-sync/service.go @@ -1,6 +1,7 @@ package initialsync import ( + "context" "errors" "fmt" "time" @@ -62,11 +63,15 @@ func (s *InitialSync) Start() { ch := make(chan time.Time) sub := s.chain.StateInitializedFeed().Subscribe(ch) defer sub.Unsubscribe() - if s.chain.HeadState() == nil { + if _, err := s.chain.HeadState(context.TODO()); err != nil { // Wait until chain start. genesis = <-ch } else { - genesis = time.Unix(int64(s.chain.HeadState().GenesisTime), 0) + headState, err := s.chain.HeadState(context.TODO()) + if err != nil { + panic(err) + } + genesis = time.Unix(int64(headState.GenesisTime), 0) } if genesis.After(roughtime.Now()) { diff --git a/beacon-chain/sync/subscriber_beacon_blocks.go b/beacon-chain/sync/subscriber_beacon_blocks.go index ec7ae8d2c3..ac8d46e841 100644 --- a/beacon-chain/sync/subscriber_beacon_blocks.go +++ b/beacon-chain/sync/subscriber_beacon_blocks.go @@ -14,7 +14,11 @@ import ( func (r *RegularSync) beaconBlockSubscriber(ctx context.Context, msg proto.Message) error { block := msg.(*ethpb.BeaconBlock) - headState := r.chain.HeadState() + headState, err := r.chain.HeadState(ctx) + if err != nil { + log.Errorf("Head state is not available: %v", err) + return nil + } // Ignore block older than last finalized checkpoint. if block.Slot < helpers.StartSlot(headState.FinalizedCheckpoint.Epoch) { log.Debugf("Received a block older than finalized checkpoint, %d < %d", diff --git a/beacon-chain/sync/validate_attester_slashing.go b/beacon-chain/sync/validate_attester_slashing.go index e737c9687e..9c754ecbc3 100644 --- a/beacon-chain/sync/validate_attester_slashing.go +++ b/beacon-chain/sync/validate_attester_slashing.go @@ -51,7 +51,10 @@ func (r *RegularSync) validateAttesterSlashing(ctx context.Context, msg proto.Me } // Retrieve head state, advance state to the epoch slot used specified in slashing message. - s := r.chain.HeadState() + s, err := r.chain.HeadState(ctx) + if err != nil { + return false, err + } slashSlot := slashing.Attestation_1.Data.Target.Epoch * params.BeaconConfig().SlotsPerEpoch if s.Slot < slashSlot { if ctx.Err() != nil { diff --git a/beacon-chain/sync/validate_proposer_slashing.go b/beacon-chain/sync/validate_proposer_slashing.go index d059e31d22..1881fc9fc9 100644 --- a/beacon-chain/sync/validate_proposer_slashing.go +++ b/beacon-chain/sync/validate_proposer_slashing.go @@ -50,7 +50,10 @@ func (r *RegularSync) validateProposerSlashing(ctx context.Context, msg proto.Me } // Retrieve head state, advance state to the epoch slot used specified in slashing message. - s := r.chain.HeadState() + s, err := r.chain.HeadState(ctx) + if err != nil { + return false, errors.Wrap(err, "Could not get head state") + } slashSlot := slashing.Header_1.Slot if s.Slot < slashSlot { if ctx.Err() != nil { diff --git a/beacon-chain/sync/validate_voluntary_exit.go b/beacon-chain/sync/validate_voluntary_exit.go index 616311b7fe..11e8a948f6 100644 --- a/beacon-chain/sync/validate_voluntary_exit.go +++ b/beacon-chain/sync/validate_voluntary_exit.go @@ -43,7 +43,11 @@ func (r *RegularSync) validateVoluntaryExit(ctx context.Context, msg proto.Messa } // Retrieve head state, advance state to the epoch slot used specified in exit message. - s := r.chain.HeadState() + s, err := r.chain.HeadState(ctx) + if err != nil { + return false, err + } + exitedEpochSlot := exit.Epoch * params.BeaconConfig().SlotsPerEpoch if s.Slot < exitedEpochSlot { var err error