mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
ValidatorStatus Estimating Activation RPC Server (#2469)
* fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename
This commit is contained in:
@@ -20,6 +20,7 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -80,3 +83,27 @@ func (db *BeaconDB) AllDeposits(ctx context.Context, beforeBlk *big.Int) []*pb.D
|
||||
|
||||
return deposits
|
||||
}
|
||||
|
||||
// DepositByPubkey looks through historical deposits and finds one which contains
|
||||
// a certain public key within its deposit data.
|
||||
func (db *BeaconDB) DepositByPubkey(ctx context.Context, pubKey []byte) (*pb.Deposit, *big.Int, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.DepositByPubkey")
|
||||
defer span.End()
|
||||
db.depositsLock.RLock()
|
||||
defer db.depositsLock.RUnlock()
|
||||
|
||||
var deposit *pb.Deposit
|
||||
var blockNum *big.Int
|
||||
for _, ctnr := range db.deposits {
|
||||
depositInput, err := helpers.DecodeDepositInput(ctnr.deposit.DepositData)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not decode deposit input: %v", err)
|
||||
}
|
||||
if bytes.Equal(depositInput.Pubkey, pubKey) {
|
||||
deposit = ctnr.deposit
|
||||
blockNum = ctnr.block
|
||||
break
|
||||
}
|
||||
}
|
||||
return deposit, blockNum, nil
|
||||
}
|
||||
|
||||
3
beacon-chain/internal/validator_service_mock.go
generated
3
beacon-chain/internal/validator_service_mock.go
generated
@@ -6,10 +6,11 @@ package internal
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
metadata "google.golang.org/grpc/metadata"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockValidatorServiceServer is a mock of ValidatorServiceServer interface
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
@@ -214,14 +215,69 @@ func (vs *ValidatorServer) ValidatorStatus(
|
||||
return nil, fmt.Errorf("could not fetch beacon state: %v", err)
|
||||
}
|
||||
|
||||
_, eth1BlockNumBigInt, err := vs.beaconDB.DepositByPubkey(ctx, req.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if eth1BlockNumBigInt == nil {
|
||||
return &pb.ValidatorStatusResponse{
|
||||
Status: pb.ValidatorStatus_UNKNOWN_STATUS,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Eth1DepositBlockNumber: eth1BlockNumBigInt.Uint64(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
currEpoch := helpers.CurrentEpoch(beaconState)
|
||||
eth1BlockNum := eth1BlockNumBigInt.Uint64()
|
||||
timeToInclusion := (eth1BlockNum + params.BeaconConfig().Eth1FollowDistance) * params.BeaconConfig().GoerliBlockTime
|
||||
votingPeriodSlots := helpers.StartSlot(params.BeaconConfig().EpochsPerEth1VotingPeriod)
|
||||
depositBlockSlot := (timeToInclusion / params.BeaconConfig().SecondsPerSlot) + votingPeriodSlots
|
||||
|
||||
var validatorInState *pbp2p.Validator
|
||||
var validatorIndex uint64
|
||||
for idx, val := range beaconState.ValidatorRegistry {
|
||||
if bytes.Equal(val.Pubkey, req.PublicKey) {
|
||||
if helpers.IsActiveValidator(val, currEpoch) {
|
||||
return &pb.ValidatorStatusResponse{
|
||||
Status: pb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: val.ActivationEpoch,
|
||||
Eth1DepositBlockNumber: eth1BlockNum,
|
||||
DepositInclusionSlot: depositBlockSlot,
|
||||
}, nil
|
||||
}
|
||||
validatorInState = val
|
||||
validatorIndex = uint64(idx)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var positionInQueue uint64
|
||||
// If the validator has deposited and has been added to the state:
|
||||
if validatorInState != nil {
|
||||
var lastActivatedValidatorIdx uint64
|
||||
for j := len(beaconState.ValidatorRegistry) - 1; j >= 0; j-- {
|
||||
if helpers.IsActiveValidator(beaconState.ValidatorRegistry[j], currEpoch) {
|
||||
lastActivatedValidatorIdx = uint64(j)
|
||||
break
|
||||
}
|
||||
}
|
||||
// Our position in the activation queue is the above index - our validator index.
|
||||
positionInQueue = lastActivatedValidatorIdx - validatorIndex
|
||||
}
|
||||
|
||||
status, err := vs.validatorStatus(req.PublicKey, beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &pb.ValidatorStatusResponse{
|
||||
Status: status,
|
||||
Eth1DepositBlockNumber: eth1BlockNum,
|
||||
PositionInActivationQueue: positionInQueue,
|
||||
DepositInclusionSlot: depositBlockSlot,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
|
||||
return &pb.ValidatorStatusResponse{
|
||||
Status: status,
|
||||
}, nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (vs *ValidatorServer) validatorStatus(pubkey []byte, beaconState *pbp2p.BeaconState) (pb.ValidatorStatus, error) {
|
||||
@@ -274,7 +330,11 @@ func (vs *ValidatorServer) filterActivePublicKeys(beaconState *pbp2p.BeaconState
|
||||
return activeKeys
|
||||
}
|
||||
|
||||
func (vs *ValidatorServer) addNonActivePublicKeysAssignmentStatus(beaconState *pbp2p.BeaconState, pubkeys [][]byte, assignments []*pb.CommitteeAssignmentResponse_CommitteeAssignment) []*pb.CommitteeAssignmentResponse_CommitteeAssignment {
|
||||
func (vs *ValidatorServer) addNonActivePublicKeysAssignmentStatus(
|
||||
beaconState *pbp2p.BeaconState,
|
||||
pubkeys [][]byte,
|
||||
assignments []*pb.CommitteeAssignmentResponse_CommitteeAssignment,
|
||||
) []*pb.CommitteeAssignmentResponse_CommitteeAssignment {
|
||||
// Generate a map for O(1) lookup of existence of pub keys in request.
|
||||
validatorMap := make(map[string]*pbp2p.Validator)
|
||||
for _, v := range beaconState.ValidatorRegistry {
|
||||
|
||||
@@ -5,12 +5,15 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@@ -306,26 +309,6 @@ func TestCommitteeAssignment_multipleKeys_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorStatus_CantFindValidatorIdx(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
if err := db.SaveState(ctx, &pbp2p.BeaconState{ValidatorRegistry: []*pbp2p.Validator{}}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
}
|
||||
req := &pb.ValidatorIndexRequest{
|
||||
PublicKey: []byte{'B'},
|
||||
}
|
||||
want := fmt.Sprintf("validator %#x does not exist", req.PublicKey)
|
||||
if _, err := vs.ValidatorStatus(context.Background(), req); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %v, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorStatus_PendingActive(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
@@ -342,6 +325,20 @@ func TestValidatorStatus_PendingActive(t *testing.T) {
|
||||
}}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
@@ -368,6 +365,21 @@ func TestValidatorStatus_Active(t *testing.T) {
|
||||
t.Fatalf("Could not save validator index: %v", err)
|
||||
}
|
||||
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
|
||||
// Active because activation epoch <= current epoch < exit epoch.
|
||||
if err := db.SaveState(ctx, &pbp2p.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
@@ -389,9 +401,24 @@ func TestValidatorStatus_Active(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get validator status %v", err)
|
||||
}
|
||||
if resp.Status != pb.ValidatorStatus_ACTIVE {
|
||||
t.Errorf("Wanted %v, got %v", pb.ValidatorStatus_ACTIVE, resp.Status)
|
||||
|
||||
timeToInclusion := params.BeaconConfig().Eth1FollowDistance * params.BeaconConfig().GoerliBlockTime
|
||||
votingPeriodSlots := helpers.StartSlot(params.BeaconConfig().EpochsPerEth1VotingPeriod)
|
||||
depositBlockSlot := (timeToInclusion / params.BeaconConfig().SecondsPerSlot) + votingPeriodSlots
|
||||
|
||||
expected := &pb.ValidatorStatusResponse{
|
||||
Status: pb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
DepositInclusionSlot: depositBlockSlot,
|
||||
Eth1DepositBlockNumber: 0,
|
||||
}
|
||||
if !proto.Equal(resp, expected) {
|
||||
t.Errorf("Wanted %v, got %v", expected, resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorStatus_PendingStateActivation(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestValidatorStatus_InitiatedExit(t *testing.T) {
|
||||
@@ -413,7 +440,20 @@ func TestValidatorStatus_InitiatedExit(t *testing.T) {
|
||||
}}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
}
|
||||
@@ -448,7 +488,20 @@ func TestValidatorStatus_Withdrawable(t *testing.T) {
|
||||
}}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
}
|
||||
@@ -482,7 +535,20 @@ func TestValidatorStatus_ExitedSlashed(t *testing.T) {
|
||||
}}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
}
|
||||
@@ -517,7 +583,20 @@ func TestValidatorStatus_Exited(t *testing.T) {
|
||||
}}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
}
|
||||
@@ -553,6 +632,20 @@ func TestValidatorStatus_UnknownStatus(t *testing.T) {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
|
||||
depositInput := &pbp2p.DepositInput{
|
||||
Pubkey: pubKey,
|
||||
ProofOfPossession: []byte("hi"),
|
||||
WithdrawalCredentialsHash32: []byte("hey"),
|
||||
}
|
||||
depData, err := helpers.EncodeDepositData(depositInput, params.BeaconConfig().MaxDepositAmount, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deposit := &pbp2p.Deposit{
|
||||
DepositData: depData,
|
||||
}
|
||||
db.InsertDeposit(ctx, deposit, big.NewInt(0))
|
||||
vs := &ValidatorServer{
|
||||
beaconDB: db,
|
||||
}
|
||||
|
||||
3
proto/beacon/p2p/v1/messages.pb.go
generated
3
proto/beacon/p2p/v1/messages.pb.go
generated
@@ -5,9 +5,10 @@ package ethereum_beacon_p2p_v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/beacon/p2p/v1/types.pb.go
generated
5
proto/beacon/p2p/v1/types.pb.go
generated
@@ -5,10 +5,11 @@ package ethereum_beacon_p2p_v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
_ "github.com/prysmaticlabs/prysm/proto/common"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
_ "github.com/prysmaticlabs/prysm/proto/common"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
@@ -88,6 +88,7 @@ type BeaconChainConfig struct {
|
||||
LogBlockDelay int64 // Number of blocks to wait from the current head before processing logs from the deposit contract.
|
||||
RPCSyncCheck time.Duration // Number of seconds to query the sync service, to find out if the node is synced or not.
|
||||
TestnetContractEndpoint string // TestnetContractEndpoint to fetch the contract address of the Prysmatic Labs testnet.
|
||||
GoerliBlockTime uint64 // GoerliBlockTime is the number of seconds on avg a Goerli block is created.
|
||||
}
|
||||
|
||||
// DepositContractConfig contains the deposits for
|
||||
@@ -178,6 +179,7 @@ var defaultBeaconConfig = &BeaconChainConfig{
|
||||
MaxNumLog2Validators: 24,
|
||||
LogBlockDelay: 2, //
|
||||
RPCSyncCheck: 1,
|
||||
GoerliBlockTime: 14, // 14 seconds on average for a goerli block to be created.
|
||||
|
||||
// Testnet misc values.
|
||||
TestnetContractEndpoint: "https://beta.prylabs.net/contract", // defines an http endpoint to fetch the testnet contract addr.
|
||||
|
||||
3
validator/internal/attester_service_mock.go
generated
3
validator/internal/attester_service_mock.go
generated
@@ -6,11 +6,12 @@ package internal
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
v10 "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockAttesterServiceClient is a mock of AttesterServiceClient interface
|
||||
|
||||
3
validator/internal/beacon_service_mock.go
generated
3
validator/internal/beacon_service_mock.go
generated
@@ -6,13 +6,14 @@ package internal
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
types "github.com/gogo/protobuf/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
v10 "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
metadata "google.golang.org/grpc/metadata"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockBeaconServiceClient is a mock of BeaconServiceClient interface
|
||||
|
||||
3
validator/internal/proposer_service_mock.go
generated
3
validator/internal/proposer_service_mock.go
generated
@@ -6,11 +6,12 @@ package internal
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
v10 "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockProposerServiceClient is a mock of ProposerServiceClient interface
|
||||
|
||||
3
validator/internal/validator_service_mock.go
generated
3
validator/internal/validator_service_mock.go
generated
@@ -6,11 +6,12 @@ package internal
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
metadata "google.golang.org/grpc/metadata"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockValidatorServiceClient is a mock of ValidatorServiceClient interface
|
||||
|
||||
Reference in New Issue
Block a user