From 497fa6ed50ef9a298e3214472a7bec13e689d97e Mon Sep 17 00:00:00 2001 From: terence tsao Date: Wed, 15 Apr 2020 08:15:23 -0700 Subject: [PATCH] Modify `ListBeaconCommittees ` to use new state service (#5411) --- beacon-chain/rpc/beacon/BUILD.bazel | 1 - beacon-chain/rpc/beacon/attestations_test.go | 17 +- beacon-chain/rpc/beacon/committees.go | 106 +++------- beacon-chain/rpc/beacon/committees_test.go | 197 ++----------------- 4 files changed, 64 insertions(+), 257 deletions(-) diff --git a/beacon-chain/rpc/beacon/BUILD.bazel b/beacon-chain/rpc/beacon/BUILD.bazel index 10da690b81e..255efd72dcb 100644 --- a/beacon-chain/rpc/beacon/BUILD.bazel +++ b/beacon-chain/rpc/beacon/BUILD.bazel @@ -103,6 +103,5 @@ go_test( "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", "@com_github_prysmaticlabs_go_ssz//:go_default_library", - "@in_gopkg_d4l3k_messagediff_v1//:go_default_library", ], ) diff --git a/beacon-chain/rpc/beacon/attestations_test.go b/beacon-chain/rpc/beacon/attestations_test.go index f4ee65754fe..5397238d551 100644 --- a/beacon-chain/rpc/beacon/attestations_test.go +++ b/beacon-chain/rpc/beacon/attestations_test.go @@ -889,6 +889,7 @@ func TestServer_StreamIndexedAttestations_ContextCanceled(t *testing.T) { } func TestServer_StreamIndexedAttestations_OK(t *testing.T) { + params.UseMainnetConfig() db := dbTest.SetupDB(t) defer dbTest.TeardownDB(t, db) exitRoutine := make(chan bool) @@ -898,11 +899,18 @@ func TestServer_StreamIndexedAttestations_OK(t *testing.T) { numValidators := 64 headState, privKeys := testutil.DeterministicGenesisState(t, uint64(numValidators)) - randaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector) - for i := 0; i < len(randaoMixes); i++ { - randaoMixes[i] = make([]byte, 32) + b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}} + if err := db.SaveBlock(ctx, b); err != nil { + t.Fatal(err) + } + gRoot, err := ssz.HashTreeRoot(b.Block) + if err != nil { + t.Fatal(err) + } + if err := db.SaveGenesisBlockRoot(ctx, gRoot); err != nil { + t.Fatal(err) } - if err := headState.SetRandaoMixes(randaoMixes); err != nil { + if err := db.SaveState(ctx, headState, gRoot); err != nil { t.Fatal(err) } @@ -995,6 +1003,7 @@ func TestServer_StreamIndexedAttestations_OK(t *testing.T) { }, AttestationNotifier: chainService.OperationNotifier(), CollectedAttestationsBuffer: make(chan []*ethpb.Attestation, 1), + StateGen: stategen.New(db, cache.NewStateSummaryCache()), } mockStream := mockRPC.NewMockBeaconChain_StreamIndexedAttestationsServer(ctrl) diff --git a/beacon-chain/rpc/beacon/committees.go b/beacon-chain/rpc/beacon/committees.go index e0ef93130b3..eac93ed705f 100644 --- a/beacon-chain/rpc/beacon/committees.go +++ b/beacon-chain/rpc/beacon/committees.go @@ -5,7 +5,6 @@ import ( ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" - "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/params" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -20,31 +19,39 @@ func (bs *Server) ListBeaconCommittees( req *ethpb.ListCommitteesRequest, ) (*ethpb.BeaconCommittees, error) { - var requestingGenesis bool - var startSlot uint64 - headSlot := bs.GenesisTimeFetcher.CurrentSlot() + currentSlot := bs.GenesisTimeFetcher.CurrentSlot() + var requestedSlot uint64 switch q := req.QueryFilter.(type) { case *ethpb.ListCommitteesRequest_Epoch: - startSlot = helpers.StartSlot(q.Epoch) + requestedSlot = helpers.StartSlot(q.Epoch) case *ethpb.ListCommitteesRequest_Genesis: - requestingGenesis = q.Genesis - if !requestingGenesis { - startSlot = headSlot - } + requestedSlot = 0 default: - startSlot = headSlot + requestedSlot = currentSlot + } + + requestedEpoch := helpers.SlotToEpoch(requestedSlot) + currentEpoch := helpers.SlotToEpoch(currentSlot) + if requestedEpoch > currentEpoch { + return nil, status.Errorf( + codes.InvalidArgument, + "Cannot retrieve information for an future epoch, current epoch %d, requesting %d", + currentEpoch, + requestedEpoch, + ) } - committees, activeIndices, err := bs.retrieveCommitteesForEpoch(ctx, helpers.SlotToEpoch(startSlot)) + + committees, activeIndices, err := bs.retrieveCommitteesForEpoch(ctx, requestedEpoch) if err != nil { return nil, status.Errorf( codes.Internal, "Could not retrieve committees for epoch %d: %v", - helpers.SlotToEpoch(startSlot), + requestedEpoch, err, ) } return ðpb.BeaconCommittees{ - Epoch: helpers.SlotToEpoch(startSlot), + Epoch: requestedEpoch, Committees: committees, ActiveValidatorCount: uint64(len(activeIndices)), }, nil @@ -54,70 +61,21 @@ func (bs *Server) retrieveCommitteesForEpoch( ctx context.Context, epoch uint64, ) (map[uint64]*ethpb.BeaconCommittees_CommitteesList, []uint64, error) { - var attesterSeed [32]byte - var activeIndices []uint64 - var err error startSlot := helpers.StartSlot(epoch) - currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) - if helpers.SlotToEpoch(startSlot)+1 < currentEpoch { - activeIndices, err = bs.HeadFetcher.HeadValidatorsIndices(helpers.SlotToEpoch(startSlot)) - if err != nil { - return nil, nil, status.Errorf( - codes.Internal, - "Could not retrieve active indices for epoch %d: %v", - helpers.SlotToEpoch(startSlot), - err, - ) - } - archivedCommitteeInfo, err := bs.BeaconDB.ArchivedCommitteeInfo(ctx, helpers.SlotToEpoch(startSlot)) - if err != nil { - return nil, nil, status.Errorf( - codes.Internal, - "Could not request archival data for epoch %d: %v", - helpers.SlotToEpoch(startSlot), - err, - ) - } - if archivedCommitteeInfo == nil { - return nil, nil, status.Errorf( - codes.NotFound, - "Could not retrieve data for epoch %d, perhaps --archive in the running beacon node is disabled", - helpers.SlotToEpoch(startSlot), - ) - } - attesterSeed = bytesutil.ToBytes32(archivedCommitteeInfo.AttesterSeed) - } else if helpers.SlotToEpoch(startSlot)+1 == currentEpoch || helpers.SlotToEpoch(startSlot) == currentEpoch { - // Otherwise, we use current beacon state to calculate the committees. - requestedEpoch := helpers.SlotToEpoch(startSlot) - activeIndices, err = bs.HeadFetcher.HeadValidatorsIndices(requestedEpoch) - if err != nil { - return nil, nil, status.Errorf( - codes.Internal, - "Could not retrieve active indices for requested epoch %d: %v", - requestedEpoch, - err, - ) - } - attesterSeed, err = bs.HeadFetcher.HeadSeed(requestedEpoch) - if err != nil { - return nil, nil, status.Errorf( - codes.Internal, - "Could not retrieve attester seed for requested epoch %d: %v", - requestedEpoch, - err, - ) - } - } else { - // Otherwise, we are requesting data from the future and we return an error. - return nil, nil, status.Errorf( - codes.InvalidArgument, - "Cannot retrieve information about an epoch in the future, current epoch %d, requesting %d", - currentEpoch, - helpers.SlotToEpoch(startSlot), - ) + requestedState, err := bs.StateGen.StateBySlot(ctx, startSlot) + if err != nil { + return nil, nil, status.Error(codes.Internal, "Could not get state") + } + seed, err := helpers.Seed(requestedState, epoch, params.BeaconConfig().DomainBeaconAttester) + if err != nil { + return nil, nil, status.Error(codes.Internal, "Could not get seed") + } + activeIndices, err := helpers.ActiveValidatorIndices(requestedState, epoch) + if err != nil { + return nil, nil, status.Error(codes.Internal, "Could not get active indices") } - committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, attesterSeed) + committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, seed) if err != nil { return nil, nil, status.Errorf( codes.InvalidArgument, diff --git a/beacon-chain/rpc/beacon/committees_test.go b/beacon-chain/rpc/beacon/committees_test.go index d7fababdb64..5f56ce2bd00 100644 --- a/beacon-chain/rpc/beacon/committees_test.go +++ b/beacon-chain/rpc/beacon/committees_test.go @@ -3,22 +3,22 @@ package beacon import ( "context" "encoding/binary" - "reflect" "testing" "time" "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/go-ssz" mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" + "github.com/prysmaticlabs/prysm/beacon-chain/cache" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/db" dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/roughtime" "github.com/prysmaticlabs/prysm/shared/testutil" - "gopkg.in/d4l3k/messagediff.v1" ) func TestServer_ListBeaconCommittees_CurrentEpoch(t *testing.T) { @@ -27,23 +27,30 @@ func TestServer_ListBeaconCommittees_CurrentEpoch(t *testing.T) { helpers.ClearCache() numValidators := 128 + ctx := context.Background() headState := setupActiveValidators(t, db, numValidators) - randaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector) - for i := 0; i < len(randaoMixes); i++ { - randaoMixes[i] = make([]byte, 32) - } - if err := headState.SetRandaoMixes(randaoMixes); err != nil { - t.Fatal(err) - } - m := &mock.ChainService{ - State: headState, Genesis: roughtime.Now().Add(time.Duration(-1*int64((headState.Slot()*params.BeaconConfig().SecondsPerSlot))) * time.Second), } bs := &Server{ HeadFetcher: m, GenesisTimeFetcher: m, + StateGen: stategen.New(db, cache.NewStateSummaryCache()), + } + b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}} + if err := db.SaveBlock(ctx, b); err != nil { + t.Fatal(err) + } + gRoot, err := ssz.HashTreeRoot(b.Block) + if err != nil { + t.Fatal(err) + } + if err := db.SaveGenesisBlockRoot(ctx, gRoot); err != nil { + t.Fatal(err) + } + if err := db.SaveState(ctx, headState, gRoot); err != nil { + t.Fatal(err) } activeIndices, err := helpers.ActiveValidatorIndices(headState, 0) @@ -75,172 +82,6 @@ func TestServer_ListBeaconCommittees_CurrentEpoch(t *testing.T) { } } -func TestServer_ListBeaconCommittees_PreviousEpoch(t *testing.T) { - db := dbTest.SetupDB(t) - defer dbTest.TeardownDB(t, db) - helpers.ClearCache() - - numValidators := 128 - headState := setupActiveValidators(t, db, numValidators) - - mixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector) - for i := 0; i < len(mixes); i++ { - mixes[i] = make([]byte, 32) - } - if err := headState.SetRandaoMixes(mixes); err != nil { - t.Fatal(err) - } - if err := headState.SetSlot(params.BeaconConfig().SlotsPerEpoch * 2); err != nil { - t.Fatal(err) - } - - m := &mock.ChainService{ - State: headState, - Genesis: roughtime.Now().Add(time.Duration(-1*int64((headState.Slot()*params.BeaconConfig().SecondsPerSlot))) * time.Second), - } - bs := &Server{ - HeadFetcher: m, - GenesisTimeFetcher: m, - } - - activeIndices, err := helpers.ActiveValidatorIndices(headState, 1) - if err != nil { - t.Fatal(err) - } - attesterSeed, err := helpers.Seed(headState, 1, params.BeaconConfig().DomainBeaconAttester) - if err != nil { - t.Fatal(err) - } - startSlot := helpers.StartSlot(1) - wanted, err := computeCommittees(startSlot, activeIndices, attesterSeed) - if err != nil { - t.Fatal(err) - } - - tests := []struct { - req *ethpb.ListCommitteesRequest - res *ethpb.BeaconCommittees - }{ - { - req: ðpb.ListCommitteesRequest{ - QueryFilter: ðpb.ListCommitteesRequest_Epoch{Epoch: 1}, - }, - res: ðpb.BeaconCommittees{ - Epoch: 1, - Committees: wanted, - ActiveValidatorCount: uint64(numValidators), - }, - }, - } - helpers.ClearCache() - for i, test := range tests { - res, err := bs.ListBeaconCommittees(context.Background(), test.req) - if err != nil { - t.Fatal(err) - } - if !proto.Equal(res, test.res) { - diff, _ := messagediff.PrettyDiff(res, test.res) - t.Errorf("%d/ Diff between responses %s", i, diff) - } - } -} - -func TestServer_ListBeaconCommittees_FromArchive(t *testing.T) { - db := dbTest.SetupDB(t) - defer dbTest.TeardownDB(t, db) - helpers.ClearCache() - ctx := context.Background() - - numValidators := 128 - balances := make([]uint64, numValidators) - validators := make([]*ethpb.Validator, 0, numValidators) - for i := 0; i < numValidators; i++ { - pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength) - binary.LittleEndian.PutUint64(pubKey, uint64(i)) - balances[i] = uint64(i) - validators = append(validators, ðpb.Validator{ - PublicKey: pubKey, - ActivationEpoch: 0, - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - WithdrawalCredentials: make([]byte, 32), - }) - } - headState, err := stateTrie.InitializeFromProto(&pbp2p.BeaconState{Validators: validators, Balances: balances}) - if err != nil { - t.Fatal(err) - } - - randaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector) - for i := 0; i < len(randaoMixes); i++ { - randaoMixes[i] = make([]byte, 32) - } - if err := headState.SetRandaoMixes(randaoMixes); err != nil { - t.Fatal(err) - } - - if err := headState.SetSlot(params.BeaconConfig().SlotsPerEpoch * 10); err != nil { - t.Fatal(err) - } - - // Store the genesis seed. - seed, err := helpers.Seed(headState, 0, params.BeaconConfig().DomainBeaconAttester) - if err != nil { - t.Fatal(err) - } - if err := db.SaveArchivedCommitteeInfo(ctx, 0, &pbp2p.ArchivedCommitteeInfo{ - AttesterSeed: seed[:], - }); err != nil { - t.Fatal(err) - } - - m := &mock.ChainService{ - State: headState, - } - bs := &Server{ - BeaconDB: db, - HeadFetcher: m, - GenesisTimeFetcher: m, - } - - activeIndices, err := helpers.ActiveValidatorIndices(headState, 0) - if err != nil { - t.Fatal(err) - } - - wanted, err := computeCommittees(0, activeIndices, seed) - if err != nil { - t.Fatal(err) - } - res1, err := bs.ListBeaconCommittees(context.Background(), ðpb.ListCommitteesRequest{ - QueryFilter: ðpb.ListCommitteesRequest_Genesis{ - Genesis: true, - }, - }) - if err != nil { - t.Fatal(err) - } - res2, err := bs.ListBeaconCommittees(context.Background(), ðpb.ListCommitteesRequest{ - QueryFilter: ðpb.ListCommitteesRequest_Epoch{ - Epoch: 0, - }, - }) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(res1, res2) { - t.Fatal(err) - } - wantedRes := ðpb.BeaconCommittees{ - Epoch: 0, - Committees: wanted, - ActiveValidatorCount: uint64(numValidators), - } - if !reflect.DeepEqual(wantedRes, res1) { - t.Errorf("Wanted %v", wantedRes) - t.Errorf("Received %v", res1) - } -} - func setupActiveValidators(t *testing.T, db db.Database, count int) *stateTrie.BeaconState { balances := make([]uint64, count) validators := make([]*ethpb.Validator, 0, count)