From 456ac5f9a3ac05c8860ea1435c9df6fddc79e3c4 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Sat, 15 Feb 2020 11:57:49 -0700 Subject: [PATCH] Better `head` object coupling for chain service (#4869) * Done * Fixed lock * Fixed all the tests * Comments * Fixed more tests * Merge branch 'master' into better-head-obj * Fixed more tests * Merge branch 'better-head-obj' of git+ssh://github.com/prysmaticlabs/prysm into better-head-obj * Prestons feedback & fixed test * Nishant's feedback * Participation edge case * Gaz * Merge branch 'master' into better-head-obj * Merge branch 'master' of git+ssh://github.com/prysmaticlabs/prysm into better-head-obj * Raul's feedback * Merge branch 'better-head-obj' of git+ssh://github.com/prysmaticlabs/prysm into better-head-obj --- beacon-chain/blockchain/BUILD.bazel | 1 - beacon-chain/blockchain/chain_info.go | 76 +++++----- .../blockchain/chain_info_norace_test.go | 15 +- beacon-chain/blockchain/chain_info_test.go | 55 ++++---- beacon-chain/blockchain/head.go | 132 +++++++++++++++--- beacon-chain/blockchain/head_test.go | 22 ++- beacon-chain/blockchain/info.go | 56 +------- beacon-chain/blockchain/metrics/BUILD.bazel | 1 + beacon-chain/blockchain/metrics/metrics.go | 12 +- .../blockchain/process_block_helpers.go | 1 + beacon-chain/blockchain/receive_block.go | 8 +- beacon-chain/blockchain/service.go | 57 ++------ .../blockchain/service_norace_test.go | 3 +- beacon-chain/blockchain/service_test.go | 15 +- beacon-chain/node/node.go | 1 - beacon-chain/p2p/peers/status_test.go | 10 +- beacon-chain/rpc/beacon/server.go | 1 + beacon-chain/rpc/beacon/slashings.go | 2 +- beacon-chain/rpc/beacon/slashings_test.go | 2 +- beacon-chain/rpc/beacon/validators.go | 2 +- beacon-chain/rpc/service.go | 1 + validator/client/validator_metrics.go | 3 +- 22 files changed, 232 insertions(+), 244 deletions(-) diff --git a/beacon-chain/blockchain/BUILD.bazel b/beacon-chain/blockchain/BUILD.bazel index c860910b7ae..c780acb27b5 100644 --- a/beacon-chain/blockchain/BUILD.bazel +++ b/beacon-chain/blockchain/BUILD.bazel @@ -45,7 +45,6 @@ go_library( "//shared/slotutil:go_default_library", "//shared/traceutil:go_default_library", "@com_github_emicklei_dot//:go_default_library", - "@com_github_gogo_protobuf//proto:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_prysmaticlabs_go_ssz//:go_default_library", diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index ba93a79eae9..406ce96d815 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -5,7 +5,6 @@ import ( "context" "time" - "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/go-ssz" "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" @@ -60,67 +59,63 @@ type ParticipationFetcher interface { // FinalizedCheckpt returns the latest finalized checkpoint from head state. func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint { - if s.headState == nil || s.headState.FinalizedCheckpoint() == nil { + if s.finalizedCheckpt == nil { return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} } - cpt := s.headState.FinalizedCheckpoint() + // If head state exists but there hasn't been a finalized check point, // the check point's root should refer to genesis block root. - if bytes.Equal(cpt.Root, params.BeaconConfig().ZeroHash[:]) { + if bytes.Equal(s.finalizedCheckpt.Root, params.BeaconConfig().ZeroHash[:]) { return ðpb.Checkpoint{Root: s.genesisRoot[:]} } - return cpt + + return state.CopyCheckpoint(s.finalizedCheckpt) } // CurrentJustifiedCheckpt returns the current justified checkpoint from head state. func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint { - if s.headState == nil || s.headState.CurrentJustifiedCheckpoint() == nil { + if s.justifiedCheckpt == nil { return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} } - cpt := s.headState.CurrentJustifiedCheckpoint() // If head state exists but there hasn't been a justified check point, // the check point root should refer to genesis block root. - if bytes.Equal(cpt.Root, params.BeaconConfig().ZeroHash[:]) { + if bytes.Equal(s.justifiedCheckpt.Root, params.BeaconConfig().ZeroHash[:]) { return ðpb.Checkpoint{Root: s.genesisRoot[:]} } - return cpt + return state.CopyCheckpoint(s.justifiedCheckpt) } // PreviousJustifiedCheckpt returns the previous justified checkpoint from head state. func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint { - - if s.headState == nil || s.headState.PreviousJustifiedCheckpoint() == nil { + if s.prevJustifiedCheckpt == nil { return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} } - cpt := s.headState.PreviousJustifiedCheckpoint() // If head state exists but there hasn't been a justified check point, // the check point root should refer to genesis block root. - if bytes.Equal(cpt.Root, params.BeaconConfig().ZeroHash[:]) { + if bytes.Equal(s.prevJustifiedCheckpt.Root, params.BeaconConfig().ZeroHash[:]) { return ðpb.Checkpoint{Root: s.genesisRoot[:]} } - return cpt + return state.CopyCheckpoint(s.prevJustifiedCheckpt) } // HeadSlot returns the slot of the head of the chain. func (s *Service) HeadSlot() uint64 { - s.headLock.RLock() - defer s.headLock.RUnlock() + if !s.hasHeadState() { + return 0 + } - return s.headSlot + return s.headSlot() } // HeadRoot returns the root of the head of the chain. func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) { - s.headLock.RLock() - defer s.headLock.RUnlock() - - root := s.canonicalRoots[s.headSlot] - if len(root) != 0 { - return root, nil + if s.headRoot() != params.BeaconConfig().ZeroHash { + r := s.headRoot() + return r[:], nil } b, err := s.beaconDB.HeadBlock(ctx) @@ -141,46 +136,39 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) { // HeadBlock returns the head block of the chain. func (s *Service) HeadBlock() *ethpb.SignedBeaconBlock { - s.headLock.RLock() - defer s.headLock.RUnlock() - - return proto.Clone(s.headBlock).(*ethpb.SignedBeaconBlock) + return s.headBlock() } // HeadState returns the head state of the chain. // 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) (*state.BeaconState, error) { - s.headLock.RLock() - defer s.headLock.RUnlock() - - if s.headState == nil { - headState, err := s.beaconDB.HeadState(ctx) - if err != nil { - return nil, err - } - s.headState = headState - return headState, nil + if s.hasHeadState() { + return s.headState(), nil } - return s.headState.Copy(), nil + headState, err := 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. func (s *Service) HeadValidatorsIndices(epoch uint64) ([]uint64, error) { - if s.headState == nil { + if !s.hasHeadState() { return []uint64{}, nil } - return helpers.ActiveValidatorIndices(s.headState, epoch) + return helpers.ActiveValidatorIndices(s.headState(), epoch) } // HeadSeed returns the seed from the head view of a given epoch. func (s *Service) HeadSeed(epoch uint64) ([32]byte, error) { - if s.headState == nil { + if !s.hasHeadState() { return [32]byte{}, nil } - return helpers.Seed(s.headState, epoch, params.BeaconConfig().DomainBeaconAttester) + return helpers.Seed(s.headState(), epoch, params.BeaconConfig().DomainBeaconAttester) } // GenesisTime returns the genesis time of beacon chain. @@ -190,13 +178,13 @@ func (s *Service) GenesisTime() time.Time { // CurrentFork retrieves the latest fork information of the beacon chain. func (s *Service) CurrentFork() *pb.Fork { - if s.headState == nil { + if !s.hasHeadState() { return &pb.Fork{ PreviousVersion: params.BeaconConfig().GenesisForkVersion, CurrentVersion: params.BeaconConfig().GenesisForkVersion, } } - return s.headState.Fork() + return s.headState().Fork() } // Participation returns the participation stats of a given epoch. diff --git a/beacon-chain/blockchain/chain_info_norace_test.go b/beacon-chain/blockchain/chain_info_norace_test.go index 91115c73199..0cf8633e3fb 100644 --- a/beacon-chain/blockchain/chain_info_norace_test.go +++ b/beacon-chain/blockchain/chain_info_norace_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" ) @@ -11,8 +12,7 @@ func TestHeadSlot_DataRace(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) s := &Service{ - beaconDB: db, - canonicalRoots: make(map[uint64][]byte), + beaconDB: db, } go func() { s.saveHead( @@ -27,8 +27,8 @@ func TestHeadRoot_DataRace(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) s := &Service{ - beaconDB: db, - canonicalRoots: make(map[uint64][]byte), + beaconDB: db, + head: &head{root: [32]byte{'A'}}, } go func() { s.saveHead( @@ -45,8 +45,8 @@ func TestHeadBlock_DataRace(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) s := &Service{ - beaconDB: db, - canonicalRoots: make(map[uint64][]byte), + beaconDB: db, + head: &head{block: ðpb.SignedBeaconBlock{}}, } go func() { s.saveHead( @@ -61,8 +61,7 @@ func TestHeadState_DataRace(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) s := &Service{ - beaconDB: db, - canonicalRoots: make(map[uint64][]byte), + beaconDB: db, } go func() { s.saveHead( diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index 16e1d44a9f5..f7618160a03 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -13,7 +13,6 @@ import ( "github.com/prysmaticlabs/prysm/beacon-chain/state" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" - "github.com/prysmaticlabs/prysm/shared/testutil" ) // Ensure Service implements chain info interface. @@ -25,7 +24,6 @@ func TestFinalizedCheckpt_Nil(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) c := setupBeaconChain(t, db) - c.headState, _ = testutil.DeterministicGenesisState(t, 1) if !bytes.Equal(c.FinalizedCheckpt().Root, params.BeaconConfig().ZeroHash[:]) { t.Error("Incorrect pre chain start value") } @@ -50,7 +48,7 @@ func TestFinalizedCheckpt_CanRetrieve(t *testing.T) { cp := ðpb.Checkpoint{Epoch: 5, Root: []byte("foo")} c := setupBeaconChain(t, db) - c.headState, _ = state.InitializeFromProto(&pb.BeaconState{FinalizedCheckpoint: cp}) + c.finalizedCheckpt = cp if c.FinalizedCheckpt().Epoch != cp.Epoch { t.Errorf("Finalized epoch at genesis should be %d, got: %d", cp.Epoch, c.FinalizedCheckpt().Epoch) @@ -61,10 +59,11 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) - cp := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} + genesisRoot := [32]byte{'A'} + cp := ðpb.Checkpoint{Root: genesisRoot[:]} c := setupBeaconChain(t, db) - c.headState, _ = state.InitializeFromProto(&pb.BeaconState{FinalizedCheckpoint: cp}) - c.genesisRoot = [32]byte{'A'} + c.finalizedCheckpt = cp + c.genesisRoot = genesisRoot if !bytes.Equal(c.FinalizedCheckpt().Root, c.genesisRoot[:]) { t.Errorf("Got: %v, wanted: %v", c.FinalizedCheckpt().Root, c.genesisRoot[:]) @@ -77,7 +76,7 @@ func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) { cp := ðpb.Checkpoint{Epoch: 6, Root: []byte("foo")} c := setupBeaconChain(t, db) - c.headState, _ = state.InitializeFromProto(&pb.BeaconState{CurrentJustifiedCheckpoint: cp}) + c.justifiedCheckpt = cp if c.CurrentJustifiedCheckpt().Epoch != cp.Epoch { t.Errorf("Current Justifiied epoch at genesis should be %d, got: %d", cp.Epoch, c.CurrentJustifiedCheckpt().Epoch) @@ -88,10 +87,11 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) - cp := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} + genesisRoot := [32]byte{'B'} + cp := ðpb.Checkpoint{Root: genesisRoot[:]} c := setupBeaconChain(t, db) - c.headState, _ = state.InitializeFromProto(&pb.BeaconState{CurrentJustifiedCheckpoint: cp}) - c.genesisRoot = [32]byte{'B'} + c.justifiedCheckpt = cp + c.genesisRoot = genesisRoot if !bytes.Equal(c.CurrentJustifiedCheckpt().Root, c.genesisRoot[:]) { t.Errorf("Got: %v, wanted: %v", c.CurrentJustifiedCheckpt().Root, c.genesisRoot[:]) @@ -104,7 +104,7 @@ func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) { cp := ðpb.Checkpoint{Epoch: 7, Root: []byte("foo")} c := setupBeaconChain(t, db) - c.headState, _ = state.InitializeFromProto(&pb.BeaconState{PreviousJustifiedCheckpoint: cp}) + c.prevJustifiedCheckpt = cp if c.PreviousJustifiedCheckpt().Epoch != cp.Epoch { t.Errorf("Previous Justifiied epoch at genesis should be %d, got: %d", cp.Epoch, c.PreviousJustifiedCheckpt().Epoch) @@ -115,10 +115,11 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) - cp := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} + genesisRoot := [32]byte{'C'} + cp := ðpb.Checkpoint{Root: genesisRoot[:]} c := setupBeaconChain(t, db) - c.headState, _ = state.InitializeFromProto(&pb.BeaconState{PreviousJustifiedCheckpoint: cp}) - c.genesisRoot = [32]byte{'C'} + c.prevJustifiedCheckpt = cp + c.genesisRoot = genesisRoot if !bytes.Equal(c.PreviousJustifiedCheckpt().Root, c.genesisRoot[:]) { t.Errorf("Got: %v, wanted: %v", c.PreviousJustifiedCheckpt().Root, c.genesisRoot[:]) @@ -127,28 +128,26 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) { func TestHeadSlot_CanRetrieve(t *testing.T) { c := &Service{} - c.headSlot = 100 + s, _ := state.InitializeFromProto(&pb.BeaconState{}) + c.head = &head{slot: 100, state: s} if c.HeadSlot() != 100 { t.Errorf("Wanted head slot: %d, got: %d", 100, c.HeadSlot()) } } func TestHeadRoot_CanRetrieve(t *testing.T) { - c := &Service{canonicalRoots: make(map[uint64][]byte)} - c.headSlot = 100 - c.canonicalRoots[c.headSlot] = []byte{'A'} - headRoot, err := c.HeadRoot(context.Background()) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal([]byte{'A'}, headRoot) { - t.Errorf("Wanted head root: %v, got: %d", []byte{'A'}, headRoot) + c := &Service{} + c.head = &head{root: [32]byte{'A'}} + if [32]byte{'A'} != c.headRoot() { + t.Errorf("Wanted head root: %v, got: %d", []byte{'A'}, c.headRoot()) } } func TestHeadBlock_CanRetrieve(t *testing.T) { b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}} - c := &Service{headBlock: b} + c := &Service{} + c.head = &head{block: b} + if !reflect.DeepEqual(b, c.HeadBlock()) { t.Error("incorrect head block received") } @@ -159,7 +158,8 @@ func TestHeadState_CanRetrieve(t *testing.T) { if err != nil { t.Fatal(err) } - c := &Service{headState: s} + c := &Service{} + c.head = &head{state: s} headState, err := c.HeadState(context.Background()) if err != nil { t.Fatal(err) @@ -183,7 +183,8 @@ func TestCurrentFork_CanRetrieve(t *testing.T) { if err != nil { t.Fatal(err) } - c := &Service{headState: s} + c := &Service{} + c.head = &head{state: s} if !proto.Equal(c.CurrentFork(), f) { t.Error("Received incorrect fork version") } diff --git a/beacon-chain/blockchain/head.go b/beacon-chain/blockchain/head.go index 155edaa5769..87ed1cfb60a 100644 --- a/beacon-chain/blockchain/head.go +++ b/beacon-chain/blockchain/head.go @@ -4,13 +4,23 @@ import ( "context" "github.com/pkg/errors" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/beacon-chain/state" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/params" "go.opencensus.io/trace" ) +// This defines the current chain service's view of head. +type head struct { + slot uint64 // current head slot. + root [32]byte // current head root. + block *ethpb.SignedBeaconBlock // current head block. + state *state.BeaconState // current head state. +} + // This gets head from the fork choice service and saves head related items // (ie root, block, state) to the local service cache. func (s *Service) updateHead(ctx context.Context, balances []uint64) error { @@ -42,12 +52,8 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error { ctx, span := trace.StartSpan(ctx, "blockchain.saveHead") defer span.End() - cachedHeadRoot, err := s.HeadRoot(ctx) - if err != nil { - return err - } // Do nothing if head hasn't changed. - if headRoot == bytesutil.ToBytes32(cachedHeadRoot) { + if headRoot == s.headRoot() { return nil } @@ -59,48 +65,43 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error { } // Get the new head block from DB. - newHead, err := s.beaconDB.Block(ctx, headRoot) + newHeadBlock, err := s.beaconDB.Block(ctx, headRoot) if err != nil { return err } - if newHead == nil || newHead.Block == nil { + if newHeadBlock == nil || newHeadBlock.Block == nil { return errors.New("cannot save nil head block") } // Get the new head state from cached state or DB. - var headState *state.BeaconState + var newHeadState *state.BeaconState var exists bool if featureconfig.Get().InitSyncCacheState { - headState, exists = s.initSyncState[headRoot] + newHeadState, exists = s.initSyncState[headRoot] if !exists { - headState, err = s.beaconDB.State(ctx, headRoot) + newHeadState, err = s.beaconDB.State(ctx, headRoot) if err != nil { return errors.Wrap(err, "could not retrieve head state in DB") } - if headState == nil { + if newHeadState == nil { return errors.New("cannot save nil head state") } } } else { - headState, err = s.beaconDB.State(ctx, headRoot) + newHeadState, err = s.beaconDB.State(ctx, headRoot) if err != nil { return errors.Wrap(err, "could not retrieve head state in DB") } - if headState == nil { + if newHeadState == nil { return errors.New("cannot save nil head state") } } - if headState == nil { + if newHeadState == nil { return errors.New("cannot save nil head state") } - s.headLock.Lock() - defer s.headLock.Unlock() // Cache the new head info. - s.headSlot = newHead.Block.Slot - s.canonicalRoots[newHead.Block.Slot] = headRoot[:] - s.headBlock = stateTrie.CopySignedBeaconBlock(newHead) - s.headState = headState + s.setHead(headRoot, newHeadBlock, newHeadState) // Save the new head root to DB. if err := s.beaconDB.SaveHeadBlockRoot(ctx, headRoot); err != nil { @@ -109,3 +110,94 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error { return nil } + +// This gets called to update canonical root mapping. It does not save head block +// root in DB. With the inception of inital-sync-cache-state flag, it uses finalized +// check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis. +func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock, r [32]byte) error { + if b == nil || b.Block == nil { + return errors.New("cannot save nil head block") + } + + headState, err := s.beaconDB.State(ctx, r) + if err != nil { + return errors.Wrap(err, "could not retrieve head state in DB") + } + if headState == nil { + s.initSyncStateLock.RLock() + cachedHeadState, ok := s.initSyncState[r] + if ok { + headState = cachedHeadState + } + s.initSyncStateLock.RUnlock() + } + + if headState == nil { + return errors.New("nil head state") + } + + s.setHead(r, stateTrie.CopySignedBeaconBlock(b), headState) + + return nil +} + +// This sets head view object which is used to track the head slot, root, block and state. +func (s *Service) setHead(root [32]byte, block *ethpb.SignedBeaconBlock, state *state.BeaconState) { + s.headLock.Lock() + defer s.headLock.Unlock() + + // This does a full copy of the block and state. + s.head = &head{ + slot: block.Block.Slot, + root: root, + block: stateTrie.CopySignedBeaconBlock(block), + state: state.Copy(), + } +} + +// This returns the head slot. +func (s *Service) headSlot() uint64 { + s.headLock.RLock() + defer s.headLock.RUnlock() + + return s.head.slot +} + +// This returns the head root. +// It does a full copy on head root for immutability. +func (s *Service) headRoot() [32]byte { + if s.head == nil { + return params.BeaconConfig().ZeroHash + } + + s.headLock.RLock() + defer s.headLock.RUnlock() + + return s.head.root +} + +// This returns the head block. +// It does a full copy on head block for immutability. +func (s *Service) headBlock() *ethpb.SignedBeaconBlock { + s.headLock.RLock() + defer s.headLock.RUnlock() + + return stateTrie.CopySignedBeaconBlock(s.head.block) +} + +// This returns the head state. +// It does a full copy on head state for immutability. +func (s *Service) headState() *state.BeaconState { + s.headLock.RLock() + defer s.headLock.RUnlock() + + return s.head.state.Copy() +} + +// Returns true if head state exists. +func (s *Service) hasHeadState() bool { + s.headLock.RLock() + defer s.headLock.RUnlock() + + return s.head != nil && s.head.state != nil +} diff --git a/beacon-chain/blockchain/head_test.go b/beacon-chain/blockchain/head_test.go index 85410e6fd7a..ca340608f27 100644 --- a/beacon-chain/blockchain/head_test.go +++ b/beacon-chain/blockchain/head_test.go @@ -18,23 +18,18 @@ func TestSaveHead_Same(t *testing.T) { defer testDB.TeardownDB(t, db) service := setupBeaconChain(t, db) - service.headSlot = 0 r := [32]byte{'A'} - service.canonicalRoots[0] = r[:] + service.head = &head{slot: 0, root: r} if err := service.saveHead(context.Background(), r); err != nil { t.Fatal(err) } - if service.headSlot != 0 { + if service.headSlot() != 0 { t.Error("Head did not stay the same") } - cachedRoot, err := service.HeadRoot(context.Background()) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(cachedRoot, r[:]) { + if service.headRoot() != r { t.Error("Head did not stay the same") } } @@ -44,21 +39,20 @@ func TestSaveHead_Different(t *testing.T) { defer testDB.TeardownDB(t, db) service := setupBeaconChain(t, db) - service.headSlot = 0 oldRoot := [32]byte{'A'} - service.canonicalRoots[0] = oldRoot[:] + service.head = &head{slot: 0, root: oldRoot} newHeadBlock := ðpb.BeaconBlock{Slot: 1} newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock} service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock) newRoot, _ := ssz.HashTreeRoot(newHeadBlock) - headState, _ := state.InitializeFromProto(&pb.BeaconState{}) + headState, _ := state.InitializeFromProto(&pb.BeaconState{Slot: 1}) service.beaconDB.SaveState(context.Background(), headState, newRoot) if err := service.saveHead(context.Background(), newRoot); err != nil { t.Fatal(err) } - if service.headSlot != 1 { + if service.HeadSlot() != 1 { t.Error("Head did not change") } @@ -69,10 +63,10 @@ func TestSaveHead_Different(t *testing.T) { if !bytes.Equal(cachedRoot, newRoot[:]) { t.Error("Head did not change") } - if !reflect.DeepEqual(service.headBlock, newHeadSignedBlock) { + if !reflect.DeepEqual(service.headBlock(), newHeadSignedBlock) { t.Error("Head did not change") } - if !reflect.DeepEqual(service.headState, headState) { + if !reflect.DeepEqual(service.headState().CloneInnerState(), headState.CloneInnerState()) { t.Error("Head did not change") } } diff --git a/beacon-chain/blockchain/info.go b/beacon-chain/blockchain/info.go index 2c56f449594..6bfc0d3da60 100644 --- a/beacon-chain/blockchain/info.go +++ b/beacon-chain/blockchain/info.go @@ -1,50 +1,13 @@ package blockchain import ( - "bytes" - "encoding/hex" "fmt" "net/http" - "sort" "strconv" "github.com/emicklei/dot" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/sirupsen/logrus" ) -const latestSlotCount = 10 - -// HeadsHandler is a handler to serve /heads page in metrics. -func (s *Service) HeadsHandler(w http.ResponseWriter, _ *http.Request) { - buf := new(bytes.Buffer) - - if _, err := fmt.Fprintf(w, "\n %s\t%s\t", "Head slot", "Head root"); err != nil { - logrus.WithError(err).Error("Failed to render chain heads page") - return - } - - if _, err := fmt.Fprintf(w, "\n %s\t%s\t", "---------", "---------"); err != nil { - logrus.WithError(err).Error("Failed to render chain heads page") - return - } - - slots := s.latestHeadSlots() - for _, slot := range slots { - r := hex.EncodeToString(bytesutil.Trunc(s.canonicalRoots[uint64(slot)])) - if _, err := fmt.Fprintf(w, "\n %d\t\t%s\t", slot, r); err != nil { - logrus.WithError(err).Error("Failed to render chain heads page") - return - } - } - - w.WriteHeader(http.StatusOK) - if _, err := w.Write(buf.Bytes()); err != nil { - log.WithError(err).Error("Failed to render chain heads page") - } - -} - const template = ` @@ -70,7 +33,7 @@ const template = ` // TreeHandler is a handler to serve /tree page in metrics. func (s *Service) TreeHandler(w http.ResponseWriter, _ *http.Request) { - if s.headState == nil { + if s.headState() == nil { if _, err := w.Write([]byte("Unavailable during initial syncing")); err != nil { log.WithError(err).Error("Failed to render p2p info page") } @@ -83,7 +46,7 @@ func (s *Service) TreeHandler(w http.ResponseWriter, _ *http.Request) { graph.Attr("labeljust", "l") dotNodes := make([]*dot.Node, len(nodes)) - avgBalance := uint64(averageBalance(s.headState.Balances())) + avgBalance := uint64(averageBalance(s.headState().Balances())) for i := len(nodes) - 1; i >= 0; i-- { // Construct label for each node. @@ -98,7 +61,7 @@ func (s *Service) TreeHandler(w http.ResponseWriter, _ *http.Request) { dotN = graph.Node(index).Box().Attr("label", label) } - if nodes[i].Slot == s.headSlot && + if nodes[i].Slot == s.headSlot() && nodes[i].BestDescendent == ^uint64(0) { dotN = dotN.Attr("color", "green") } @@ -118,16 +81,3 @@ func (s *Service) TreeHandler(w http.ResponseWriter, _ *http.Request) { log.WithError(err).Error("Failed to render p2p info page") } } - -// This returns the latest head slots in a slice and up to latestSlotCount -func (s *Service) latestHeadSlots() []int { - slots := make([]int, 0, len(s.canonicalRoots)) - for k := range s.canonicalRoots { - slots = append(slots, int(k)) - } - sort.Ints(slots) - if (len(slots)) > latestSlotCount { - return slots[len(slots)-latestSlotCount:] - } - return slots -} diff --git a/beacon-chain/blockchain/metrics/BUILD.bazel b/beacon-chain/blockchain/metrics/BUILD.bazel index 713386df630..0bd49b0d767 100644 --- a/beacon-chain/blockchain/metrics/BUILD.bazel +++ b/beacon-chain/blockchain/metrics/BUILD.bazel @@ -12,5 +12,6 @@ go_library( "//shared/params:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", + "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", ], ) diff --git a/beacon-chain/blockchain/metrics/metrics.go b/beacon-chain/blockchain/metrics/metrics.go index 9deb2a6aed4..e00b765857b 100644 --- a/beacon-chain/blockchain/metrics/metrics.go +++ b/beacon-chain/blockchain/metrics/metrics.go @@ -3,6 +3,7 @@ package metrics import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/shared/bytesutil" @@ -82,15 +83,12 @@ var ( ) // ReportSlotMetrics reports slot related metrics. -func ReportSlotMetrics(currentSlot uint64, headSlot uint64, headState *stateTrie.BeaconState) { +func ReportSlotMetrics(currentSlot uint64, headSlot uint64, finalizedCheckpoint *ethpb.Checkpoint) { beaconSlot.Set(float64(currentSlot)) beaconHeadSlot.Set(float64(headSlot)) - if headState != nil { - finalizedCpt := headState.FinalizedCheckpoint() - if finalizedCpt != nil { - headFinalizedEpoch.Set(float64(finalizedCpt.Epoch)) - headFinalizedRoot.Set(float64(bytesutil.ToLowInt64(finalizedCpt.Root))) - } + if finalizedCheckpoint != nil { + headFinalizedEpoch.Set(float64(finalizedCheckpoint.Epoch)) + headFinalizedRoot.Set(float64(bytesutil.ToLowInt64(finalizedCheckpoint.Root))) } } diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index a4a4333dfc7..fc5901a9ff7 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -250,6 +250,7 @@ func (s *Service) updateJustified(ctx context.Context, state *stateTrie.BeaconSt return err } if canUpdate { + s.prevJustifiedCheckpt = s.justifiedCheckpt s.justifiedCheckpt = cpt } diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index 19c31f2c3c0..3614022134e 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -94,7 +94,7 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB return errors.Wrap(err, "could not get signing root on received block") } - if featureconfig.Get().DisableForkChoice && block.Block.Slot > s.headSlot { + if featureconfig.Get().DisableForkChoice && block.Block.Slot > s.headSlot() { if err := s.saveHead(ctx, root); err != nil { return errors.Wrap(err, "could not save head") } @@ -115,7 +115,7 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB }) // Reports on block and fork choice metrics. - metrics.ReportSlotMetrics(blockCopy.Block.Slot, s.headSlot, s.headState) + metrics.ReportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.finalizedCheckpt) // Log state transition data. logStateTransitionData(blockCopy.Block) @@ -165,7 +165,7 @@ func (s *Service) ReceiveBlockNoPubsubForkchoice(ctx context.Context, block *eth }) // Reports on block and fork choice metrics. - metrics.ReportSlotMetrics(blockCopy.Block.Slot, s.headSlot, s.headState) + metrics.ReportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.finalizedCheckpt) // Log state transition data. logStateTransitionData(blockCopy.Block) @@ -231,7 +231,7 @@ func (s *Service) ReceiveBlockNoVerify(ctx context.Context, block *ethpb.SignedB }) // Reports on blockCopy and fork choice metrics. - metrics.ReportSlotMetrics(blockCopy.Block.Slot, s.headSlot, s.headState) + metrics.ReportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.finalizedCheckpt) // Log state transition data. log.WithFields(logrus.Fields{ diff --git a/beacon-chain/blockchain/service.go b/beacon-chain/blockchain/service.go index e506b33a355..822cca3f7c0 100644 --- a/beacon-chain/blockchain/service.go +++ b/beacon-chain/blockchain/service.go @@ -49,10 +49,7 @@ type Service struct { genesisTime time.Time p2p p2p.Broadcaster maxRoutines int64 - headSlot uint64 - headBlock *ethpb.SignedBeaconBlock - headState *stateTrie.BeaconState - canonicalRoots map[uint64][]byte + head *head headLock sync.RWMutex stateNotifier statefeed.Notifier genesisRoot [32]byte @@ -60,6 +57,7 @@ type Service struct { epochParticipationLock sync.RWMutex forkChoiceStore f.ForkChoicer justifiedCheckpt *ethpb.Checkpoint + prevJustifiedCheckpt *ethpb.Checkpoint bestJustifiedCheckpt *ethpb.Checkpoint finalizedCheckpt *ethpb.Checkpoint prevFinalizedCheckpt *ethpb.Checkpoint @@ -98,7 +96,6 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) { attPool: cfg.AttPool, exitPool: cfg.ExitPool, p2p: cfg.P2p, - canonicalRoots: make(map[uint64][]byte), maxRoutines: cfg.MaxRoutines, stateNotifier: cfg.StateNotifier, epochParticipation: make(map[uint64]*precompute.Balance), @@ -150,6 +147,7 @@ func (s *Service) Start() { // Resume fork choice. s.justifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint) + s.prevJustifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint) s.bestJustifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint) s.finalizedCheckpt = stateTrie.CopyCheckpoint(finalizedCheckpoint) s.prevFinalizedCheckpt = stateTrie.CopyCheckpoint(finalizedCheckpoint) @@ -274,32 +272,6 @@ func (s *Service) ClearCachedStates() { s.initSyncState = map[[32]byte]*stateTrie.BeaconState{} } -// This gets called to update canonical root mapping. It does not save head block -// root in DB. With the inception of inital-sync-cache-state flag, it uses finalized -// check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis. -func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock, r [32]byte) error { - s.headLock.Lock() - defer s.headLock.Unlock() - - if b == nil || b.Block == nil { - return errors.New("cannot save nil head block") - } - - s.headSlot = b.Block.Slot - - s.canonicalRoots[b.Block.Slot] = r[:] - - s.headBlock = stateTrie.CopySignedBeaconBlock(b) - - headState, err := s.beaconDB.State(ctx, r) - if err != nil { - return errors.Wrap(err, "could not retrieve head state in DB") - } - s.headState = headState - - return nil -} - // This gets called when beacon chain is first initialized to save validator indices and public keys in db. func (s *Service) saveGenesisValidators(ctx context.Context, state *stateTrie.BeaconState) error { pubkeys := make([][48]byte, state.NumValidators()) @@ -314,9 +286,6 @@ func (s *Service) saveGenesisValidators(ctx context.Context, state *stateTrie.Be // This gets called when beacon chain is first initialized to save genesis data (state, block, and more) in db. func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.BeaconState) error { - s.headLock.Lock() - defer s.headLock.Unlock() - stateRoot, err := genesisState.HashTreeRoot() if err != nil { return err @@ -347,6 +316,7 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B // Add the genesis block to the fork choice store. s.justifiedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint) + s.prevJustifiedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint) s.bestJustifiedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint) s.finalizedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint) s.prevFinalizedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint) @@ -360,19 +330,13 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B log.Fatalf("Could not process genesis block for fork choice: %v", err) } - s.genesisRoot = genesisBlkRoot - s.headBlock = genesisBlk - s.headState = genesisState - s.canonicalRoots[genesisState.Slot()] = genesisBlkRoot[:] + s.setHead(genesisBlkRoot, genesisBlk, genesisState) return nil } // This gets called to initialize chain info variables using the finalized checkpoint stored in DB func (s *Service) initializeChainInfo(ctx context.Context) error { - s.headLock.Lock() - defer s.headLock.Unlock() - genesisBlock, err := s.beaconDB.GenesisBlock(ctx) if err != nil { return errors.Wrap(err, "could not get genesis block from db") @@ -395,19 +359,20 @@ func (s *Service) initializeChainInfo(ctx context.Context) error { // would be the genesis state and block. return errors.New("no finalized epoch in the database") } - s.headState, err = s.beaconDB.State(ctx, bytesutil.ToBytes32(finalized.Root)) + finalizedState, err := s.beaconDB.State(ctx, bytesutil.ToBytes32(finalized.Root)) if err != nil { return errors.Wrap(err, "could not get finalized state from db") } - s.headBlock, err = s.beaconDB.Block(ctx, bytesutil.ToBytes32(finalized.Root)) + finalizedBlock, err := s.beaconDB.Block(ctx, bytesutil.ToBytes32(finalized.Root)) if err != nil { return errors.Wrap(err, "could not get finalized block from db") } - if s.headBlock != nil && s.headBlock.Block != nil { - s.headSlot = s.headBlock.Block.Slot + if finalizedState == nil || finalizedBlock == nil { + return errors.New("finalized state and block can't be nil") } - s.canonicalRoots[s.headSlot] = finalized.Root + + s.setHead(bytesutil.ToBytes32(finalized.Root), finalizedBlock, finalizedState) return nil } diff --git a/beacon-chain/blockchain/service_norace_test.go b/beacon-chain/blockchain/service_norace_test.go index 518b2f63891..d98d032ff8c 100644 --- a/beacon-chain/blockchain/service_norace_test.go +++ b/beacon-chain/blockchain/service_norace_test.go @@ -18,8 +18,7 @@ func TestChainService_SaveHead_DataRace(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) s := &Service{ - beaconDB: db, - canonicalRoots: make(map[uint64][]byte), + beaconDB: db, } go func() { s.saveHead( diff --git a/beacon-chain/blockchain/service_test.go b/beacon-chain/blockchain/service_test.go index d5de66fd350..2f709e5d4a3 100644 --- a/beacon-chain/blockchain/service_test.go +++ b/beacon-chain/blockchain/service_test.go @@ -29,7 +29,6 @@ import ( beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" protodb "github.com/prysmaticlabs/prysm/proto/beacon/db" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/event" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" @@ -292,7 +291,7 @@ func TestChainService_InitializeBeaconChain(t *testing.T) { t.Fatal(err) } - s, err := bc.beaconDB.State(ctx, bytesutil.ToBytes32(bc.canonicalRoots[0])) + s, err := bc.beaconDB.State(ctx, bc.headRoot()) if err != nil { t.Fatal(err) } @@ -309,8 +308,8 @@ func TestChainService_InitializeBeaconChain(t *testing.T) { if bc.HeadBlock() == nil { t.Error("Head state can't be nil after initialize beacon chain") } - if bc.canonicalRoots[0] == nil { - t.Error("Canonical root for slot 0 can't be nil after initialize beacon chain") + if bc.headRoot() == params.BeaconConfig().ZeroHash { + t.Error("Canonical root for slot 0 can't be zeros after initialize beacon chain") } } @@ -353,7 +352,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) { if err := db.SaveBlock(ctx, headBlock); err != nil { t.Fatal(err) } - c := &Service{beaconDB: db, canonicalRoots: make(map[uint64][]byte)} + c := &Service{beaconDB: db} if err := c.initializeChainInfo(ctx); err != nil { t.Fatal(err) } @@ -387,11 +386,13 @@ func TestChainService_SaveHeadNoDB(t *testing.T) { defer testDB.TeardownDB(t, db) ctx := context.Background() s := &Service{ - beaconDB: db, - canonicalRoots: make(map[uint64][]byte), + beaconDB: db, } b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}} r, _ := ssz.HashTreeRoot(b) + state := &pb.BeaconState{} + newState, err := beaconstate.InitializeFromProto(state) + s.beaconDB.SaveState(ctx, newState, r) if err := s.saveHeadNoDB(ctx, b, r); err != nil { t.Fatal(err) } diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index 34493a3be59..e73071ba20c 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -529,7 +529,6 @@ func (b *BeaconNode) registerPrometheusService(ctx *cli.Context) error { if err := b.services.FetchService(&c); err != nil { panic(err) } - additionalHandlers = append(additionalHandlers, prometheus.Handler{Path: "/heads", Handler: c.HeadsHandler}) if featureconfig.Get().EnableBackupWebhook { additionalHandlers = append(additionalHandlers, prometheus.Handler{Path: "/db/backup", Handler: db.BackupHandler(b.db)}) diff --git a/beacon-chain/p2p/peers/status_test.go b/beacon-chain/p2p/peers/status_test.go index 73c3006d371..f5b2aeba02e 100644 --- a/beacon-chain/p2p/peers/status_test.go +++ b/beacon-chain/p2p/peers/status_test.go @@ -353,31 +353,31 @@ func TestTrimmedOrderedPeers(t *testing.T) { pid1 := addPeer(t, p, peers.PeerConnected) p.SetChainState(pid1, &pb.Status{ FinalizedEpoch: 3, - FinalizedRoot: mockroot3[:], + FinalizedRoot: mockroot3[:], }) // Peer 2 pid2 := addPeer(t, p, peers.PeerConnected) p.SetChainState(pid2, &pb.Status{ FinalizedEpoch: 4, - FinalizedRoot: mockroot4[:], + FinalizedRoot: mockroot4[:], }) // Peer 3 pid3 := addPeer(t, p, peers.PeerConnected) p.SetChainState(pid3, &pb.Status{ FinalizedEpoch: 5, - FinalizedRoot: mockroot5[:], + FinalizedRoot: mockroot5[:], }) // Peer 4 pid4 := addPeer(t, p, peers.PeerConnected) p.SetChainState(pid4, &pb.Status{ FinalizedEpoch: 2, - FinalizedRoot: mockroot2[:], + FinalizedRoot: mockroot2[:], }) // Peer 5 pid5 := addPeer(t, p, peers.PeerConnected) p.SetChainState(pid5, &pb.Status{ FinalizedEpoch: 2, - FinalizedRoot: mockroot2[:], + FinalizedRoot: mockroot2[:], }) _, target, pids := p.BestFinalized(maxPeers, 0) diff --git a/beacon-chain/rpc/beacon/server.go b/beacon-chain/rpc/beacon/server.go index 6bfdc9fb02c..2f784d2af4e 100644 --- a/beacon-chain/rpc/beacon/server.go +++ b/beacon-chain/rpc/beacon/server.go @@ -26,6 +26,7 @@ type Server struct { HeadFetcher blockchain.HeadFetcher FinalizationFetcher blockchain.FinalizationFetcher ParticipationFetcher blockchain.ParticipationFetcher + GenesisTimeFetcher blockchain.TimeFetcher StateNotifier statefeed.Notifier BlockNotifier blockfeed.Notifier AttestationsPool attestations.Pool diff --git a/beacon-chain/rpc/beacon/slashings.go b/beacon-chain/rpc/beacon/slashings.go index 7d2d8481399..2df63200732 100644 --- a/beacon-chain/rpc/beacon/slashings.go +++ b/beacon-chain/rpc/beacon/slashings.go @@ -4,9 +4,9 @@ import ( "context" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/shared/sliceutil" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/prysmaticlabs/prysm/shared/sliceutil" ) // SubmitProposerSlashing receives a proposer slashing object via diff --git a/beacon-chain/rpc/beacon/slashings_test.go b/beacon-chain/rpc/beacon/slashings_test.go index 415543f36bd..c068ecb1772 100644 --- a/beacon-chain/rpc/beacon/slashings_test.go +++ b/beacon-chain/rpc/beacon/slashings_test.go @@ -7,10 +7,10 @@ import ( "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" + pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" ) diff --git a/beacon-chain/rpc/beacon/validators.go b/beacon-chain/rpc/beacon/validators.go index ea90212daaa..673be21c01c 100644 --- a/beacon-chain/rpc/beacon/validators.go +++ b/beacon-chain/rpc/beacon/validators.go @@ -410,6 +410,7 @@ func (bs *Server) GetValidatorParticipation( if err != nil { return nil, status.Error(codes.Internal, "Could not get head state") } + currentEpoch := helpers.CurrentEpoch(headState) prevEpoch := helpers.PrevEpoch(headState) @@ -581,7 +582,6 @@ func (bs *Server) GetValidatorQueue( func (bs *Server) GetValidatorPerformance( ctx context.Context, req *ethpb.ValidatorPerformanceRequest, ) (*ethpb.ValidatorPerformanceResponse, error) { - validatorSummary := state.ValidatorSummary beforeTransitionBalances := make([]uint64, 0) diff --git a/beacon-chain/rpc/service.go b/beacon-chain/rpc/service.go index a1d711389b5..0ca8e146324 100644 --- a/beacon-chain/rpc/service.go +++ b/beacon-chain/rpc/service.go @@ -252,6 +252,7 @@ func (s *Service) Start() { ParticipationFetcher: s.participationFetcher, ChainStartFetcher: s.chainStartFetcher, CanonicalStateChan: s.canonicalStateChan, + GenesisTimeFetcher: s.genesisTimeFetcher, StateNotifier: s.stateNotifier, BlockNotifier: s.blockNotifier, SlotTicker: ticker, diff --git a/validator/client/validator_metrics.go b/validator/client/validator_metrics.go index 09ddadc8e7d..165518b6295 100644 --- a/validator/client/validator_metrics.go +++ b/validator/client/validator_metrics.go @@ -29,8 +29,7 @@ var validatorBalancesGaugeVec = promauto.NewGaugeVec( // and penalties over time, percentage gain/loss, and gives the end user a better idea // of how the validator performs with respect to the rest. func (v *validator) LogValidatorGainsAndLosses(ctx context.Context, slot uint64) error { - - if slot%params.BeaconConfig().SlotsPerEpoch != 0 || slot < params.BeaconConfig().SlotsPerEpoch { + if slot%params.BeaconConfig().SlotsPerEpoch != 0 || slot <= params.BeaconConfig().SlotsPerEpoch { // Do nothing if we are not at the start of a new epoch and before the first epoch. return nil }