Add fetching validators by indices and public keys (#5141)

* update ethereumapis with patch
* Add indices and pubkeys to ListValidators request
* Add sorting
* Merge branch 'master' into validators-by-keys-indices
* Rename to index
* Merge branch 'validators-by-keys-indices' of https://github.com/prysmaticlabs/prysm into validators-by-keys-indices
* Add comment
This commit is contained in:
Ivan Martinez 2020-03-19 16:30:40 -04:00 committed by GitHub
parent 271938202e
commit b30a089548
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 116 additions and 20 deletions

View File

@ -1300,7 +1300,7 @@ go_repository(
go_repository( go_repository(
name = "com_github_prysmaticlabs_ethereumapis", name = "com_github_prysmaticlabs_ethereumapis",
commit = "fca4d6f69bedb8615c2fc916d1a68f2692285caa", commit = "25f267e475788bf8e5e01cb9d73cfd0c87020822",
importpath = "github.com/prysmaticlabs/ethereumapis", importpath = "github.com/prysmaticlabs/ethereumapis",
patch_args = ["-p1"], patch_args = ["-p1"],
patches = [ patches = [

View File

@ -81,13 +81,10 @@ func (bs *Server) ListValidatorBalances(
if len(pubKey) == 0 { if len(pubKey) == 0 {
continue continue
} }
pubkeyBytes := bytesutil.ToBytes48(pubKey)
index, ok, err := bs.BeaconDB.ValidatorIndex(ctx, pubKey) index, ok := headState.ValidatorIndexByPubkey(pubkeyBytes)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve validator index: %v", err)
}
if !ok { if !ok {
return nil, status.Errorf(codes.NotFound, "Could not find validator index for public key %#x", pubKey) return nil, status.Errorf(codes.NotFound, "Could not find validator index for public key %#x", pubkeyBytes)
} }
filtered[index] = true filtered[index] = true
@ -124,6 +121,10 @@ func (bs *Server) ListValidatorBalances(
} }
balancesCount = len(res) balancesCount = len(res)
} }
// Depending on the indices and public keys given, results might not be sorted.
sort.Slice(res, func(i, j int) bool {
return res[i].Index < res[j].Index
})
// If there are no balances, we simply return a response specifying this. // If there are no balances, we simply return a response specifying this.
// Otherwise, attempting to paginate 0 balances below would result in an error. // Otherwise, attempting to paginate 0 balances below would result in an error.
@ -199,16 +200,55 @@ func (bs *Server) ListValidators(
} }
validatorList := make([]*ethpb.Validators_ValidatorContainer, 0) validatorList := make([]*ethpb.Validators_ValidatorContainer, 0)
for i := 0; i < headState.NumValidators(); i++ {
val, err := headState.ValidatorAtIndex(uint64(i)) for _, index := range req.Indices {
val, err := headState.ValidatorAtIndex(index)
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, "Could not get validator") return nil, status.Error(codes.Internal, "Could not get validator")
} }
validatorList = append(validatorList, &ethpb.Validators_ValidatorContainer{ validatorList = append(validatorList, &ethpb.Validators_ValidatorContainer{
Index: uint64(i), Index: index,
Validator: val, Validator: val,
}) })
} }
for _, pubKey := range req.PublicKeys {
// Skip empty public key.
if len(pubKey) == 0 {
continue
}
pubkeyBytes := bytesutil.ToBytes48(pubKey)
index, ok := headState.ValidatorIndexByPubkey(pubkeyBytes)
if !ok {
continue
}
val, err := headState.ValidatorAtIndex(index)
if err != nil {
return nil, status.Error(codes.Internal, "Could not get validator")
}
validatorList = append(validatorList, &ethpb.Validators_ValidatorContainer{
Index: index,
Validator: val,
})
}
// Depending on the indices and public keys given, results might not be sorted.
sort.Slice(validatorList, func(i, j int) bool {
return validatorList[i].Index < validatorList[j].Index
})
if len(req.PublicKeys) == 0 && len(req.Indices) == 0 {
for i := 0; i < headState.NumValidators(); i++ {
val, err := headState.ValidatorAtIndex(uint64(i))
if err != nil {
return nil, status.Error(codes.Internal, "Could not get validator")
}
validatorList = append(validatorList, &ethpb.Validators_ValidatorContainer{
Index: uint64(i),
Validator: val,
})
}
}
if requestedEpoch < currentEpoch { if requestedEpoch < currentEpoch {
stopIdx := len(validatorList) stopIdx := len(validatorList)
for idx, item := range validatorList { for idx, item := range validatorList {
@ -611,13 +651,15 @@ func (bs *Server) GetValidatorPerformance(
correctlyVotedHead := make([]bool, 0, reqPubKeysCount) correctlyVotedHead := make([]bool, 0, reqPubKeysCount)
missingValidators := make([][]byte, 0, reqPubKeysCount) missingValidators := make([][]byte, 0, reqPubKeysCount)
headState, err := bs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, status.Error(codes.Internal, "Could not get head state")
}
// Convert the list of validator public keys to list of validator indices. // Convert the list of validator public keys to list of validator indices.
// Also track missing validators using public keys. // Also track missing validators using public keys.
for _, key := range req.PublicKeys { for _, key := range req.PublicKeys {
idx, ok, err := bs.BeaconDB.ValidatorIndex(ctx, key) pubkeyBytes := bytesutil.ToBytes48(key)
if err != nil { idx, ok := headState.ValidatorIndexByPubkey(pubkeyBytes)
return nil, status.Errorf(codes.Internal, "Could not fetch validator idx for public key %#x: %v", key, err)
}
if !ok { if !ok {
missingValidators = append(missingValidators, key) missingValidators = append(missingValidators, key)
continue continue

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"reflect" "reflect"
"sort"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
@ -694,6 +695,59 @@ func TestServer_ListValidators_NoPagination(t *testing.T) {
} }
} }
func TestServer_ListValidators_IndicesPubKeys(t *testing.T) {
db := dbTest.SetupDB(t)
defer dbTest.TeardownDB(t, db)
validators, _ := setupValidators(t, db, 100)
indicesWanted := []uint64{2, 7, 11, 17}
pubkeyIndicesWanted := []uint64{3, 5, 9, 15}
allIndicesWanted := append(indicesWanted, pubkeyIndicesWanted...)
want := make([]*ethpb.Validators_ValidatorContainer, len(allIndicesWanted))
for i, idx := range allIndicesWanted {
want[i] = &ethpb.Validators_ValidatorContainer{
Index: idx,
Validator: validators[idx],
}
}
sort.Slice(want, func(i int, j int) bool {
return want[i].Index < want[j].Index
})
headState, err := db.HeadState(context.Background())
if err != nil {
t.Fatal(err)
}
bs := &Server{
HeadFetcher: &mock.ChainService{
State: headState,
},
FinalizationFetcher: &mock.ChainService{
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 0,
},
},
}
pubKeysWanted := make([][]byte, len(pubkeyIndicesWanted))
for i, indice := range pubkeyIndicesWanted {
pubKeysWanted[i] = pubKey(indice)
}
req := &ethpb.ListValidatorsRequest{
Indices: indicesWanted,
PublicKeys: pubKeysWanted,
}
received, err := bs.ListValidators(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(want, received.ValidatorList) {
t.Fatal("Incorrect respond of validators")
}
}
func TestServer_ListValidators_Pagination(t *testing.T) { func TestServer_ListValidators_Pagination(t *testing.T) {
db := dbTest.SetupDB(t) db := dbTest.SetupDB(t)
defer dbTest.TeardownDB(t, db) defer dbTest.TeardownDB(t, db)

View File

@ -298,7 +298,7 @@ index 2ce5c34..4cbb276 100644
+ bytes signature = 3 [(gogoproto.moretags) = "ssz-size:\"96\""]; + bytes signature = 3 [(gogoproto.moretags) = "ssz-size:\"96\""];
} }
diff --git a/eth/v1alpha1/beacon_chain.proto b/eth/v1alpha1/beacon_chain.proto diff --git a/eth/v1alpha1/beacon_chain.proto b/eth/v1alpha1/beacon_chain.proto
index 0099328..8b8c6eb 100644 index 32d0b16..1679371 100644
--- a/eth/v1alpha1/beacon_chain.proto --- a/eth/v1alpha1/beacon_chain.proto
+++ b/eth/v1alpha1/beacon_chain.proto +++ b/eth/v1alpha1/beacon_chain.proto
@@ -15,6 +15,7 @@ syntax = "proto3"; @@ -15,6 +15,7 @@ syntax = "proto3";
@ -363,7 +363,7 @@ index 0099328..8b8c6eb 100644
// Validator's index in the validator set. // Validator's index in the validator set.
uint64 index = 2; uint64 index = 2;
@@ -552,7 +553,7 @@ message GetValidatorRequest { @@ -560,7 +561,7 @@ message GetValidatorRequest {
uint64 index = 1; uint64 index = 1;
// 48 byte validator public key. // 48 byte validator public key.
@ -372,7 +372,7 @@ index 0099328..8b8c6eb 100644
} }
} }
@@ -594,26 +595,25 @@ message ActiveSetChanges { @@ -602,26 +603,25 @@ message ActiveSetChanges {
uint64 epoch = 1; uint64 epoch = 1;
// 48 byte validator public keys that have been activated in the given epoch. // 48 byte validator public keys that have been activated in the given epoch.
@ -405,7 +405,7 @@ index 0099328..8b8c6eb 100644
// Indices of validators ejected in the given epoch. // Indices of validators ejected in the given epoch.
repeated uint64 ejected_indices = 9; repeated uint64 ejected_indices = 9;
@@ -663,11 +663,11 @@ message ValidatorQueue { @@ -671,11 +671,11 @@ message ValidatorQueue {
// Ordered list of 48 byte public keys awaiting activation. 0th index is the // Ordered list of 48 byte public keys awaiting activation. 0th index is the
// next key to be processed. // next key to be processed.
@ -419,7 +419,7 @@ index 0099328..8b8c6eb 100644
} }
message ListValidatorAssignmentsRequest { message ListValidatorAssignmentsRequest {
@@ -679,7 +679,7 @@ message ListValidatorAssignmentsRequest { @@ -687,7 +687,7 @@ message ListValidatorAssignmentsRequest {
bool genesis = 2; bool genesis = 2;
} }
// 48 byte validator public keys to filter assignments for the given epoch. // 48 byte validator public keys to filter assignments for the given epoch.
@ -428,7 +428,7 @@ index 0099328..8b8c6eb 100644
// Validator indicies to filter assignments for the given epoch. // Validator indicies to filter assignments for the given epoch.
repeated uint64 indices = 4; repeated uint64 indices = 4;
@@ -714,7 +714,7 @@ message ValidatorAssignments { @@ -722,7 +722,7 @@ message ValidatorAssignments {
uint64 proposer_slot = 4; uint64 proposer_slot = 4;
// 48 byte BLS public key. // 48 byte BLS public key.