Skip to content

Commit

Permalink
Update validator reporting logs and metrics for Altair (#9589)
Browse files Browse the repository at this point in the history
* Mark fields as deprecated due to Altair

* Only print inclusion distance fields before Altair fork

* Report phase0 and altair metrics respectively

* only set phase0 fields in phase0, only set altair fields in altair

* better use of fields

* Update go pbs

* Update individual votes method

* regen go proto files

* formatting

* Feedback from @potuz

* Annotate metrics per @potuz suggestion

* Set previous release e2e to end 1 epoch before altair. Add some out of bounds checks for validator metrics reporting and a panic catch

* gofmt

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 29, 2021
1 parent df33ce3 commit 520bc9d
Show file tree
Hide file tree
Showing 9 changed files with 530 additions and 339 deletions.
18 changes: 13 additions & 5 deletions beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,7 @@ func (bs *Server) GetValidatorPerformance(
correctlyVotedSource := make([]bool, 0, responseCap)
correctlyVotedTarget := make([]bool, 0, responseCap)
correctlyVotedHead := make([]bool, 0, responseCap)
inactivityScores := make([]uint64, 0, responseCap)
// Append performance summaries.
// Also track missing validators using public keys.
for _, idx := range validatorIndices {
Expand All @@ -786,24 +787,30 @@ func (bs *Server) GetValidatorPerformance(
effectiveBalances = append(effectiveBalances, summary.CurrentEpochEffectiveBalance)
beforeTransitionBalances = append(beforeTransitionBalances, summary.BeforeEpochTransitionBalance)
afterTransitionBalances = append(afterTransitionBalances, summary.AfterEpochTransitionBalance)
inclusionSlots = append(inclusionSlots, summary.InclusionSlot)
inclusionDistances = append(inclusionDistances, summary.InclusionDistance)
correctlyVotedSource = append(correctlyVotedSource, summary.IsPrevEpochAttester)
correctlyVotedTarget = append(correctlyVotedTarget, summary.IsPrevEpochTargetAttester)
correctlyVotedHead = append(correctlyVotedHead, summary.IsPrevEpochHeadAttester)

if headState.Version() == version.Phase0 {
inclusionSlots = append(inclusionSlots, summary.InclusionSlot)
inclusionDistances = append(inclusionDistances, summary.InclusionDistance)
} else {
inactivityScores = append(inactivityScores, summary.InactivityScore)
}
}

return &ethpb.ValidatorPerformanceResponse{
PublicKeys: pubKeys,
InclusionSlots: inclusionSlots,
InclusionDistances: inclusionDistances,
CorrectlyVotedSource: correctlyVotedSource,
CorrectlyVotedTarget: correctlyVotedTarget,
CorrectlyVotedTarget: correctlyVotedTarget, // In altair, when this is true then the attestation was definitely included.
CorrectlyVotedHead: correctlyVotedHead,
CurrentEffectiveBalances: effectiveBalances,
BalancesBeforeEpochTransition: beforeTransitionBalances,
BalancesAfterEpochTransition: afterTransitionBalances,
MissingValidators: missingValidators,
InclusionSlots: inclusionSlots, // Only populated in phase0
InclusionDistances: inclusionDistances, // Only populated in phase 0
InactivityScores: inactivityScores, // Only populated in Altair
}, nil
}

Expand Down Expand Up @@ -889,6 +896,7 @@ func (bs *Server) GetIndividualVotes(
CurrentEpochEffectiveBalanceGwei: v[index].CurrentEpochEffectiveBalance,
InclusionSlot: v[index].InclusionSlot,
InclusionDistance: v[index].InclusionDistance,
InactivityScore: v[index].InactivityScore,
})
}

Expand Down
5 changes: 3 additions & 2 deletions beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2032,14 +2032,15 @@ func TestGetValidatorPerformanceAltair_OK(t *testing.T) {
want := &ethpb.ValidatorPerformanceResponse{
PublicKeys: [][]byte{publicKey2[:], publicKey3[:]},
CurrentEffectiveBalances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance},
InclusionSlots: []types.Slot{0, 0},
InclusionDistances: []types.Slot{0, 0},
InclusionSlots: nil,
InclusionDistances: nil,
CorrectlyVotedSource: []bool{false, false},
CorrectlyVotedTarget: []bool{false, false},
CorrectlyVotedHead: []bool{false, false},
BalancesBeforeEpochTransition: []uint64{101, 102},
BalancesAfterEpochTransition: []uint64{0, 0},
MissingValidators: [][]byte{publicKey1[:]},
InactivityScores: []uint64{0, 0},
}

res, err := bs.GetValidatorPerformance(ctx, &ethpb.ValidatorPerformanceRequest{
Expand Down
576 changes: 303 additions & 273 deletions proto/prysm/v1alpha1/beacon_chain.pb.go

Large diffs are not rendered by default.

26 changes: 16 additions & 10 deletions proto/prysm/v1alpha1/beacon_chain.proto
Original file line number Diff line number Diff line change
Expand Up @@ -680,14 +680,16 @@ message ValidatorPerformanceRequest {

message ValidatorPerformanceResponse {
// A list of validator effective balances mapped 1-to-1 with the request's
// public keys.
// public keys.
repeated uint64 current_effective_balances = 1;
// The slot of when validator's attestation got included in the chain at previous epoch, the slot
// is mapped 1-to-1 with the request's public keys.
repeated uint64 inclusion_slots = 2 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot"];
// Deprecated: This field can no longer be fetched from the beacon state after the Altair hard fork.
repeated uint64 inclusion_slots = 2 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot", deprecated = true];
// The distance of when validator submitted and got included in the chain, the distance
// is mapped 1-to-1 with the request's public keys.
repeated uint64 inclusion_distances = 3 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot"];
// Deprecated: This field can no longer be fetched from the beacon state after the Altair hard fork.
repeated uint64 inclusion_distances = 3 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot", deprecated = true];
// Whether the list of validator recently correctly voted for source at previous epoch, the result
// is mapped 1-to-1 with the request's public keys.
repeated bool correctly_voted_source = 4;
Expand All @@ -697,19 +699,21 @@ message ValidatorPerformanceResponse {
// Whether the list of validator recently correctly voted for head at previous epoch, the result
// is mapped 1-to-1 with the request's public keys.
repeated bool correctly_voted_head = 6;
// The balance of validators before epoch transition, the balance is mapped 1-to-1 with the requests's
// The balance of validators before epoch transition, the balance is mapped 1-to-1 with the requests'
// public keys.
repeated uint64 balances_before_epoch_transition = 7;
// The balance of validators after epoch transition, the balance is mapped 1-to-1 with the requests's
// The balance of validators after epoch transition, the balance is mapped 1-to-1 with the requests'
// public keys.
repeated uint64 balances_after_epoch_transition = 8;
// The total number of validators from the request not found in
// in the beacon chain.
repeated bytes missing_validators = 9;
// The average active validator balance in the beacon chain.
// The average active validator balance in the beacon chain.
float average_active_validator_balance = 10;
// The public keys in the order they are in of the response.
repeated bytes public_keys = 11 [(ethereum.eth.ext.ssz_size) = "?,48"];
// The inactivity score of the validator tracks validator participation. [New in Altair]
repeated uint64 inactivity_scores = 12;
}

message ValidatorQueue {
Expand Down Expand Up @@ -891,10 +895,12 @@ message IndividualVotesRespond {
bool is_previous_epoch_head_attester = 12;
// The current effective balance of the validator.
uint64 current_epoch_effective_balance_gwei = 13;
// The slots of when the validator's attestation got included in the block.
uint64 inclusion_slot = 14 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot"];
// How many slots have passed until the validator's attestation got included in the block.
uint64 inclusion_distance = 15 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot"];
// The slots of when the validator's attestation got included in the block. Only available in phase0.
uint64 inclusion_slot = 14 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot", deprecated = true];
// How many slots have passed until the validator's attestation got included in the block. Only available in phase0.
uint64 inclusion_distance = 15 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/eth2-types.Slot", deprecated = true];
// The inactivity score of the validator tracks validator participation. [New in Altair]
uint64 inactivity_score = 16;
}

repeated IndividualVote individual_votes = 1;
Expand Down
1 change: 1 addition & 0 deletions testing/endtoend/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ go_test(
"//testing/endtoend/params:go_default_library",
"//testing/endtoend/types:go_default_library",
"//testing/require:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_golang_google_grpc//:go_default_library",
Expand Down
44 changes: 31 additions & 13 deletions testing/endtoend/endtoend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package endtoend

import (
"context"
"errors"
"fmt"
"os"
"path"
Expand All @@ -15,6 +14,7 @@ import (
"testing"
"time"

"github.com/pkg/errors"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/config/params"
Expand Down Expand Up @@ -79,38 +79,53 @@ func (r *testRunner) run() {
// ETH1 node.
eth1Node := components.NewEth1Node()
g.Go(func() error {
return eth1Node.Start(ctx)
if err := eth1Node.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start eth1node")
}
return nil
})
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{eth1Node}); err != nil {
return fmt.Errorf("sending and mining deposits require ETH1 node to run: %w", err)
return errors.Wrap(err, "sending and mining deposits require ETH1 node to run")
}
if err := components.SendAndMineDeposits(eth1Node.KeystorePath(), minGenesisActiveCount, 0, true /* partial */); err != nil {
return errors.Wrap(err, "failed to send and mine deposits")
}
return components.SendAndMineDeposits(eth1Node.KeystorePath(), minGenesisActiveCount, 0, true /* partial */)
return nil
})

// Boot node.
bootNode := components.NewBootNode()
g.Go(func() error {
return bootNode.Start(ctx)
if err := bootNode.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start bootnode")
}
return nil
})

// Beacon nodes.
beaconNodes := components.NewBeaconNodes(config)
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{eth1Node, bootNode}); err != nil {
return fmt.Errorf("beacon nodes require ETH1 and boot node to run: %w", err)
return errors.Wrap(err, "beacon nodes require ETH1 and boot node to run")
}
beaconNodes.SetENR(bootNode.ENR())
return beaconNodes.Start(ctx)
if err := beaconNodes.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start beacon nodes")
}
return nil
})

// Validator nodes.
validatorNodes := components.NewValidatorNodeSet(config)
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{beaconNodes}); err != nil {
return fmt.Errorf("validator nodes require beacon nodes to run: %w", err)
return errors.Wrap(err, "validator nodes require beacon nodes to run")
}
if err := validatorNodes.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start validator nodes")
}
return validatorNodes.Start(ctx)
return nil
})

// Run E2E evaluators and tests.
Expand All @@ -129,7 +144,7 @@ func (r *testRunner) run() {
ctxAllNodesReady, cancel := context.WithTimeout(ctx, allNodesStartTimeout)
defer cancel()
if err := helpers.ComponentsStarted(ctxAllNodesReady, requiredComponents); err != nil {
return fmt.Errorf("components take too long to start: %w", err)
return errors.Wrap(err, "components take too long to start")
}

// Since defer unwraps in LIFO order, parent context will be closed only after logs are written.
Expand Down Expand Up @@ -169,17 +184,20 @@ func (r *testRunner) run() {

// Run assigned evaluators.
if err := r.runEvaluators(conns, tickingStartTime); err != nil {
return err
return errors.Wrap(err, "one or more evaluators failed")
}

// If requested, run sync test.
if !config.TestSync {
return nil
}
if err := r.testBeaconChainSync(ctx, g, conns, tickingStartTime, bootNode.ENR()); err != nil {
return err
return errors.Wrap(err, "beacon chain sync test failed")
}
if err := r.testDoppelGangerProtection(ctx); err != nil {
return errors.Wrap(err, "doppel ganger protection check failed")
}
return r.testDoppelGangerProtection(ctx)
return nil
})

if err := g.Wait(); err != nil && !errors.Is(err, context.Canceled) {
Expand Down
3 changes: 2 additions & 1 deletion testing/endtoend/minimal_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/prysmaticlabs/prysm/config/params"
ev "github.com/prysmaticlabs/prysm/testing/endtoend/evaluators"
"github.com/prysmaticlabs/prysm/testing/endtoend/helpers"
e2eParams "github.com/prysmaticlabs/prysm/testing/endtoend/params"
"github.com/prysmaticlabs/prysm/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/testing/require"
Expand Down Expand Up @@ -37,7 +38,7 @@ func e2eMinimal(t *testing.T, usePrysmSh bool) {
if usePrysmSh {
// If using prysm.sh, run for only 6 epochs.
// TODO(#9166): remove this block once v2 changes are live.
epochsToRun = 6
epochsToRun = helpers.AltairE2EForkEpoch - 1
}
const tracingEndpoint = "127.0.0.1:9411"
evals := []types.Evaluator{
Expand Down
Loading

0 comments on commit 520bc9d

Please sign in to comment.