2020-05-29 02:51:00 +00:00
package evaluators
import (
2020-10-19 19:35:34 +00:00
"bytes"
2020-05-29 02:51:00 +00:00
"context"
"fmt"
2020-06-11 06:38:15 +00:00
"math"
2022-11-19 03:40:32 +00:00
"strings"
log "github.com/sirupsen/logrus"
2020-05-29 02:51:00 +00:00
"github.com/pkg/errors"
2022-08-16 12:20:13 +00:00
corehelpers "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/endtoend/helpers"
e2e "github.com/prysmaticlabs/prysm/v3/testing/endtoend/params"
"github.com/prysmaticlabs/prysm/v3/testing/endtoend/policies"
e2etypes "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/v3/testing/util"
2020-05-29 02:51:00 +00:00
"golang.org/x/exp/rand"
"google.golang.org/grpc"
2021-05-17 18:32:04 +00:00
"google.golang.org/protobuf/types/known/emptypb"
2020-05-29 02:51:00 +00:00
)
2022-11-19 03:40:32 +00:00
var exitedVals = make ( map [ [ 48 ] byte ] bool )
2020-05-29 02:51:00 +00:00
2021-09-15 22:04:13 +00:00
// churnLimit is normally 4 unless the validator set is extremely large.
2022-11-19 03:40:32 +00:00
var churnLimit = 4
2020-08-01 17:22:53 +00:00
var depositValCount = e2e . DepositCount
// Deposits should be processed in twice the length of the epochs per eth1 voting period.
2021-02-09 10:05:22 +00:00
var depositsInBlockStart = types . Epoch ( math . Floor ( float64 ( params . E2ETestConfig ( ) . EpochsPerEth1VotingPeriod ) * 2 ) )
2020-08-02 21:30:59 +00:00
// deposits included + finalization + MaxSeedLookahead for activation.
var depositActivationStartEpoch = depositsInBlockStart + 2 + params . E2ETestConfig ( ) . MaxSeedLookahead
2021-02-09 10:05:22 +00:00
var depositEndEpoch = depositActivationStartEpoch + types . Epoch ( math . Ceil ( float64 ( depositValCount ) / float64 ( churnLimit ) ) )
2020-08-01 17:22:53 +00:00
// ProcessesDepositsInBlocks ensures the expected amount of deposits are accepted into blocks.
2021-02-09 10:05:22 +00:00
var ProcessesDepositsInBlocks = e2etypes . Evaluator {
2020-08-01 17:22:53 +00:00
Name : "processes_deposits_in_blocks_epoch_%d" ,
2020-10-19 19:35:34 +00:00
Policy : policies . OnEpoch ( depositsInBlockStart ) , // We expect all deposits to enter in one epoch.
2020-08-01 17:22:53 +00:00
Evaluation : processesDepositsInBlocks ,
}
2020-06-11 06:38:15 +00:00
2020-12-04 23:15:12 +00:00
// VerifyBlockGraffiti ensures the block graffiti is one of the random list.
2021-02-09 10:05:22 +00:00
var VerifyBlockGraffiti = e2etypes . Evaluator {
2020-12-04 23:15:12 +00:00
Name : "verify_graffiti_in_blocks_epoch_%d" ,
Policy : policies . AfterNthEpoch ( 0 ) ,
Evaluation : verifyGraffitiInBlocks ,
}
2020-08-01 17:22:53 +00:00
// ActivatesDepositedValidators ensures the expected amount of validator deposits are activated into the state.
2021-02-09 10:05:22 +00:00
var ActivatesDepositedValidators = e2etypes . Evaluator {
2020-05-29 02:51:00 +00:00
Name : "processes_deposit_validators_epoch_%d" ,
2020-10-19 19:35:34 +00:00
Policy : policies . BetweenEpochs ( depositActivationStartEpoch , depositEndEpoch ) ,
2020-08-01 17:22:53 +00:00
Evaluation : activatesDepositedValidators ,
2020-05-29 02:51:00 +00:00
}
// DepositedValidatorsAreActive ensures the expected amount of validators are active after their deposits are processed.
2021-02-09 10:05:22 +00:00
var DepositedValidatorsAreActive = e2etypes . Evaluator {
2020-05-29 02:51:00 +00:00
Name : "deposited_validators_are_active_epoch_%d" ,
2020-10-19 19:35:34 +00:00
Policy : policies . AfterNthEpoch ( depositEndEpoch ) ,
2020-05-29 02:51:00 +00:00
Evaluation : depositedValidatorsAreActive ,
}
// ProposeVoluntaryExit sends a voluntary exit from randomly selected validator in the genesis set.
2021-02-09 10:05:22 +00:00
var ProposeVoluntaryExit = e2etypes . Evaluator {
2020-05-29 02:51:00 +00:00
Name : "propose_voluntary_exit_epoch_%d" ,
2020-10-19 19:35:34 +00:00
Policy : policies . OnEpoch ( 7 ) ,
2020-05-29 02:51:00 +00:00
Evaluation : proposeVoluntaryExit ,
}
2022-11-19 03:40:32 +00:00
// ValidatorsHaveExited checks the beacon state for the exited validator and ensures its marked as exited.
var ValidatorsHaveExited = e2etypes . Evaluator {
2020-05-29 02:51:00 +00:00
Name : "voluntary_has_exited_%d" ,
2020-10-19 19:35:34 +00:00
Policy : policies . OnEpoch ( 8 ) ,
2022-11-19 03:40:32 +00:00
Evaluation : validatorsHaveExited ,
2020-05-29 02:51:00 +00:00
}
2020-10-19 19:35:34 +00:00
// ValidatorsVoteWithTheMajority verifies whether validator vote for eth1data using the majority algorithm.
2021-02-09 10:05:22 +00:00
var ValidatorsVoteWithTheMajority = e2etypes . Evaluator {
2020-10-19 19:35:34 +00:00
Name : "validators_vote_with_the_majority_%d" ,
Policy : policies . AfterNthEpoch ( 0 ) ,
Evaluation : validatorsVoteWithTheMajority ,
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
type mismatch struct {
k [ 48 ] byte
e uint64
o uint64
}
func ( m mismatch ) String ( ) string {
return fmt . Sprintf ( "(%#x:%d:%d)" , m . k , m . e , m . o )
}
func processesDepositsInBlocks ( ec e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
expected := ec . Balances ( e2etypes . PostGenesisDepositBatch )
2020-08-01 17:22:53 +00:00
conn := conns [ 0 ]
2021-09-10 19:59:43 +00:00
client := ethpb . NewBeaconChainClient ( conn )
2021-05-17 18:32:04 +00:00
chainHead , err := client . GetChainHead ( context . Background ( ) , & emptypb . Empty { } )
2020-08-01 17:22:53 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get chain head" )
}
2021-09-10 19:59:43 +00:00
req := & ethpb . ListBlocksRequest { QueryFilter : & ethpb . ListBlocksRequest_Epoch { Epoch : chainHead . HeadEpoch - 1 } }
2021-09-07 15:17:50 +00:00
blks , err := client . ListBeaconBlocks ( context . Background ( ) , req )
2020-08-01 17:22:53 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get blocks from beacon-chain" )
}
2022-11-19 03:40:32 +00:00
observed := make ( map [ [ 48 ] byte ] uint64 )
2020-08-01 17:22:53 +00:00
for _ , blk := range blks . BlockContainers {
2022-11-19 03:40:32 +00:00
sb , err := blocks . BeaconBlockContainerToSignedBeaconBlock ( blk )
if err != nil {
return errors . Wrap ( err , "failed to convert api response type to SignedBeaconBlock interface" )
2021-09-07 15:17:50 +00:00
}
2022-11-19 03:40:32 +00:00
b := sb . Block ( )
slot := b . Slot ( )
eth1Data := b . Body ( ) . Eth1Data ( )
deposits := b . Body ( ) . Deposits ( )
2020-08-01 17:22:53 +00:00
fmt . Printf (
"Slot: %d with %d deposits, Eth1 block %#x with %d deposits\n" ,
2021-09-07 15:17:50 +00:00
slot ,
len ( deposits ) ,
eth1Data . BlockHash , eth1Data . DepositCount ,
2020-08-01 17:22:53 +00:00
)
2022-11-19 03:40:32 +00:00
for _ , d := range deposits {
k := bytesutil . ToBytes48 ( d . Data . PublicKey )
v := observed [ k ]
observed [ k ] = v + d . Data . Amount
}
}
mismatches := [ ] string { }
for k , ev := range expected {
ov := observed [ k ]
if ev != ov {
mismatches = append ( mismatches , mismatch { k : k , e : ev , o : ov } . String ( ) )
}
2020-08-01 17:22:53 +00:00
}
2022-11-19 03:40:32 +00:00
if len ( mismatches ) != 0 {
return fmt . Errorf ( "not all expected deposits observed on chain, len(expected)=%d, len(observed)=%d, mismatches=%d; details(key:expected:observed): %s" , len ( expected ) , len ( observed ) , len ( mismatches ) , strings . Join ( mismatches , "," ) )
2020-08-01 17:22:53 +00:00
}
return nil
}
2022-11-19 03:40:32 +00:00
func verifyGraffitiInBlocks ( _ e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
2020-12-04 23:15:12 +00:00
conn := conns [ 0 ]
2021-09-10 19:59:43 +00:00
client := ethpb . NewBeaconChainClient ( conn )
2021-05-17 18:32:04 +00:00
chainHead , err := client . GetChainHead ( context . Background ( ) , & emptypb . Empty { } )
2020-12-04 23:15:12 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get chain head" )
}
2022-01-31 16:44:17 +00:00
req := & ethpb . ListBlocksRequest { QueryFilter : & ethpb . ListBlocksRequest_Epoch { Epoch : chainHead . HeadEpoch . Sub ( 1 ) } }
2021-09-07 15:17:50 +00:00
blks , err := client . ListBeaconBlocks ( context . Background ( ) , req )
2020-12-04 23:15:12 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get blocks from beacon-chain" )
}
2021-09-10 19:59:43 +00:00
for _ , ctr := range blks . BlockContainers {
2022-11-19 03:40:32 +00:00
blk , err := blocks . BeaconBlockContainerToSignedBeaconBlock ( ctr )
2021-09-10 19:59:43 +00:00
if err != nil {
return err
2021-09-07 15:17:50 +00:00
}
2021-09-10 19:59:43 +00:00
var e bool
slot := blk . Block ( ) . Slot ( )
graffitiInBlock := blk . Block ( ) . Body ( ) . Graffiti ( )
2020-12-04 23:15:12 +00:00
for _ , graffiti := range helpers . Graffiti {
2022-09-06 14:30:16 +00:00
if bytes . Equal ( bytesutil . PadTo ( [ ] byte ( graffiti ) , 32 ) , graffitiInBlock [ : ] ) {
2020-12-04 23:15:12 +00:00
e = true
break
}
}
2021-09-07 15:17:50 +00:00
if ! e && slot != 0 {
2020-12-04 23:15:12 +00:00
return errors . New ( "could not get graffiti from the list" )
}
}
return nil
}
2022-11-19 03:40:32 +00:00
func activatesDepositedValidators ( ec e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
2020-05-29 02:51:00 +00:00
conn := conns [ 0 ]
2021-09-10 19:59:43 +00:00
client := ethpb . NewBeaconChainClient ( conn )
2020-06-11 06:38:15 +00:00
2021-05-17 18:32:04 +00:00
chainHead , err := client . GetChainHead ( context . Background ( ) , & emptypb . Empty { } )
2020-06-11 06:38:15 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get chain head" )
}
2022-11-19 03:40:32 +00:00
epoch := chainHead . HeadEpoch
2020-06-11 06:38:15 +00:00
2022-11-19 03:40:32 +00:00
validators , err := getAllValidators ( client )
2020-05-29 02:51:00 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get validators" )
}
2022-11-19 03:40:32 +00:00
expected := ec . Balances ( e2etypes . PostGenesisDepositBatch )
2020-05-29 02:51:00 +00:00
2022-11-19 03:40:32 +00:00
var deposits , lowBalance , wrongExit , wrongWithdraw int
for _ , v := range validators {
key := bytesutil . ToBytes48 ( v . PublicKey )
if _ , ok := expected [ key ] ; ! ok {
continue
}
delete ( expected , key )
if v . ActivationEpoch != epoch {
continue
}
deposits ++
if v . EffectiveBalance < params . BeaconConfig ( ) . MaxEffectiveBalance {
lowBalance ++
}
if v . ExitEpoch != params . BeaconConfig ( ) . FarFutureEpoch {
wrongExit ++
}
if v . WithdrawableEpoch != params . BeaconConfig ( ) . FarFutureEpoch {
wrongWithdraw ++
}
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
// Make sure every post-genesis deposit has been proecssed, resulting in a validator.
if len ( expected ) > 0 {
return fmt . Errorf ( "missing %d validators for post-genesis deposits" , len ( expected ) )
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
if deposits != churnLimit {
return fmt . Errorf ( "expected %d deposits to be processed in epoch %d, received %d" , churnLimit , epoch , deposits )
2020-06-11 06:38:15 +00:00
}
2020-05-29 02:51:00 +00:00
2022-11-19 03:40:32 +00:00
if lowBalance > 0 {
2020-05-29 02:51:00 +00:00
return fmt . Errorf (
"%d validators did not have genesis validator effective balance of %d" ,
2022-11-19 03:40:32 +00:00
lowBalance ,
2020-05-29 02:51:00 +00:00
params . BeaconConfig ( ) . MaxEffectiveBalance ,
)
2022-11-19 03:40:32 +00:00
} else if wrongExit > 0 {
return fmt . Errorf ( "%d validators did not have an exit epoch of far future epoch" , wrongExit )
} else if wrongWithdraw > 0 {
return fmt . Errorf ( "%d validators did not have a withdrawable epoch of far future epoch" , wrongWithdraw )
2020-05-29 02:51:00 +00:00
}
return nil
}
2022-11-19 03:40:32 +00:00
func getAllValidators ( c ethpb . BeaconChainClient ) ( [ ] * ethpb . Validator , error ) {
vals := make ( [ ] * ethpb . Validator , 0 )
pageToken := "0"
for pageToken != "" {
validatorRequest := & ethpb . ListValidatorsRequest {
PageSize : 100 ,
PageToken : pageToken ,
}
validators , err := c . ListValidators ( context . Background ( ) , validatorRequest )
if err != nil {
return nil , errors . Wrap ( err , "failed to get validators" )
}
for _ , v := range validators . ValidatorList {
vals = append ( vals , v . Validator )
}
pageToken = validators . NextPageToken
log . WithField ( "len" , len ( vals ) ) . WithField ( "pageToken" , pageToken ) . Info ( "getAllValidators" )
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
return vals , nil
}
2020-05-29 02:51:00 +00:00
2022-11-19 03:40:32 +00:00
func depositedValidatorsAreActive ( ec e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
conn := conns [ 0 ]
client := ethpb . NewBeaconChainClient ( conn )
2020-05-29 02:51:00 +00:00
2021-05-17 18:32:04 +00:00
chainHead , err := client . GetChainHead ( context . Background ( ) , & emptypb . Empty { } )
2020-05-29 02:51:00 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get chain head" )
}
2022-11-19 03:40:32 +00:00
vals , err := getAllValidators ( client )
if err != nil {
return errors . Wrap ( err , "error retrieving validator list from API" )
}
inactive := 0
lowBalance := 0
nexits := 0
expected := ec . Balances ( e2etypes . PostGenesisDepositBatch )
nexpected := len ( expected )
for _ , v := range vals {
key := bytesutil . ToBytes48 ( v . PublicKey )
if _ , ok := expected [ key ] ; ! ok {
continue // we aren't checking for this validator
}
// ignore voluntary exits when checking balance and active status
exited := exitedVals [ key ]
if exited {
nexits ++
delete ( expected , key )
continue
}
if ! corehelpers . IsActiveValidator ( v , chainHead . HeadEpoch ) {
inactive ++
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
if v . EffectiveBalance < params . BeaconConfig ( ) . MaxEffectiveBalance {
lowBalance ++
2020-08-01 17:22:53 +00:00
}
2022-11-19 03:40:32 +00:00
delete ( expected , key )
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
if len ( expected ) > 0 {
mk := make ( [ ] string , 0 )
for k := range expected {
mk = append ( mk , fmt . Sprintf ( "%#x" , k ) )
}
return fmt . Errorf ( "API response missing %d validators, based on deposits; keys=%s" , len ( expected ) , strings . Join ( mk , "," ) )
2020-05-29 02:51:00 +00:00
}
2022-11-19 03:40:32 +00:00
if inactive != 0 || lowBalance != 0 {
return fmt . Errorf ( "active validator set does not match %d total deposited. %d exited, %d inactive, %d low balance" , nexpected , nexits , inactive , lowBalance )
2020-08-01 17:22:53 +00:00
}
2022-11-19 03:40:32 +00:00
2020-05-29 02:51:00 +00:00
return nil
}
2022-11-19 03:40:32 +00:00
func proposeVoluntaryExit ( _ e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
2020-05-29 02:51:00 +00:00
conn := conns [ 0 ]
2022-11-11 17:33:48 +00:00
valClient := ethpb . NewBeaconNodeValidatorClient ( conn )
2021-09-10 19:59:43 +00:00
beaconClient := ethpb . NewBeaconChainClient ( conn )
2020-05-29 02:51:00 +00:00
ctx := context . Background ( )
2021-05-17 18:32:04 +00:00
chainHead , err := beaconClient . GetChainHead ( ctx , & emptypb . Empty { } )
2020-05-29 02:51:00 +00:00
if err != nil {
return errors . Wrap ( err , "could not get chain head" )
}
2022-11-19 03:40:32 +00:00
deposits , privKeys , err := util . DeterministicDepositsAndKeys ( params . BeaconConfig ( ) . MinGenesisActiveValidatorCount )
2020-05-29 02:51:00 +00:00
if err != nil {
return err
}
2022-11-19 03:40:32 +00:00
exitedIndex := types . ValidatorIndex ( rand . Uint64 ( ) % params . BeaconConfig ( ) . MinGenesisActiveValidatorCount )
2020-05-29 02:51:00 +00:00
2021-09-10 19:59:43 +00:00
voluntaryExit := & ethpb . VoluntaryExit {
2020-05-29 02:51:00 +00:00
Epoch : chainHead . HeadEpoch ,
2021-02-23 00:14:50 +00:00
ValidatorIndex : exitedIndex ,
2020-05-29 02:51:00 +00:00
}
2021-09-10 19:59:43 +00:00
req := & ethpb . DomainRequest {
2020-05-29 02:51:00 +00:00
Epoch : chainHead . HeadEpoch ,
Domain : params . BeaconConfig ( ) . DomainVoluntaryExit [ : ] ,
}
domain , err := valClient . DomainData ( ctx , req )
if err != nil {
return err
}
2021-09-27 16:19:20 +00:00
signingData , err := signing . ComputeSigningRoot ( voluntaryExit , domain . SignatureDomain )
2020-05-29 02:51:00 +00:00
if err != nil {
return err
}
2021-02-23 00:14:50 +00:00
signature := privKeys [ exitedIndex ] . Sign ( signingData [ : ] )
2021-09-10 19:59:43 +00:00
signedExit := & ethpb . SignedVoluntaryExit {
2020-05-29 02:51:00 +00:00
Exit : voluntaryExit ,
Signature : signature . Marshal ( ) ,
}
if _ , err = valClient . ProposeExit ( ctx , signedExit ) ; err != nil {
return errors . Wrap ( err , "could not propose exit" )
}
2022-11-19 03:40:32 +00:00
pubk := bytesutil . ToBytes48 ( deposits [ exitedIndex ] . Data . PublicKey )
exitedVals [ pubk ] = true
2020-05-29 02:51:00 +00:00
return nil
}
2022-11-19 03:40:32 +00:00
func validatorsHaveExited ( _ e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
2020-05-29 02:51:00 +00:00
conn := conns [ 0 ]
2021-09-10 19:59:43 +00:00
client := ethpb . NewBeaconChainClient ( conn )
2022-11-19 03:40:32 +00:00
for k := range exitedVals {
validatorRequest := & ethpb . GetValidatorRequest {
QueryFilter : & ethpb . GetValidatorRequest_PublicKey {
PublicKey : k [ : ] ,
} ,
}
validator , err := client . GetValidator ( context . Background ( ) , validatorRequest )
if err != nil {
return errors . Wrap ( err , "failed to get validators" )
}
if validator . ExitEpoch == params . BeaconConfig ( ) . FarFutureEpoch {
return fmt . Errorf ( "expected validator %#x to be submitted for exit" , k )
}
2020-05-29 02:51:00 +00:00
}
return nil
}
2020-10-19 19:35:34 +00:00
2022-11-19 03:40:32 +00:00
func validatorsVoteWithTheMajority ( _ e2etypes . EvaluationContext , conns ... * grpc . ClientConn ) error {
2020-10-19 19:35:34 +00:00
conn := conns [ 0 ]
2021-09-10 19:59:43 +00:00
client := ethpb . NewBeaconChainClient ( conn )
2021-05-17 18:32:04 +00:00
chainHead , err := client . GetChainHead ( context . Background ( ) , & emptypb . Empty { } )
2020-10-19 19:35:34 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get chain head" )
}
2022-01-31 16:44:17 +00:00
req := & ethpb . ListBlocksRequest { QueryFilter : & ethpb . ListBlocksRequest_Epoch { Epoch : chainHead . HeadEpoch . Sub ( 1 ) } }
2021-09-10 19:59:43 +00:00
blks , err := client . ListBeaconBlocks ( context . Background ( ) , req )
2020-10-19 19:35:34 +00:00
if err != nil {
return errors . Wrap ( err , "failed to get blocks from beacon-chain" )
}
for _ , blk := range blks . BlockContainers {
2021-09-07 15:17:50 +00:00
var slot types . Slot
var vote [ ] byte
switch blk . Block . ( type ) {
2021-09-10 19:59:43 +00:00
case * ethpb . BeaconBlockContainer_Phase0Block :
2021-09-07 15:17:50 +00:00
b := blk . GetPhase0Block ( ) . Block
slot = b . Slot
vote = b . Body . Eth1Data . BlockHash
2021-09-10 19:59:43 +00:00
case * ethpb . BeaconBlockContainer_AltairBlock :
2021-09-07 15:17:50 +00:00
b := blk . GetAltairBlock ( ) . Block
slot = b . Slot
vote = b . Body . Eth1Data . BlockHash
2022-04-05 14:02:46 +00:00
case * ethpb . BeaconBlockContainer_BellatrixBlock :
b := blk . GetBellatrixBlock ( ) . Block
slot = b . Slot
vote = b . Body . Eth1Data . BlockHash
2022-08-15 14:16:20 +00:00
case * ethpb . BeaconBlockContainer_BlindedBellatrixBlock :
b := blk . GetBlindedBellatrixBlock ( ) . Block
slot = b . Slot
vote = b . Body . Eth1Data . BlockHash
2021-09-07 15:17:50 +00:00
default :
2022-08-15 14:16:20 +00:00
return errors . New ( "block neither phase0,altair or bellatrix" )
2021-09-07 15:17:50 +00:00
}
2021-02-16 07:45:34 +00:00
slotsPerVotingPeriod := params . E2ETestConfig ( ) . SlotsPerEpoch . Mul ( uint64 ( params . E2ETestConfig ( ) . EpochsPerEth1VotingPeriod ) )
2020-10-19 19:35:34 +00:00
// We treat epoch 1 differently from other epoch for two reasons:
// - this evaluator is not executed for epoch 0 so we have to calculate the first slot differently
// - for some reason the vote for the first slot in epoch 1 is 0x000... so we skip this slot
var isFirstSlotInVotingPeriod bool
2022-02-02 19:13:52 +00:00
if chainHead . HeadEpoch == 1 && slot % params . BeaconConfig ( ) . SlotsPerEpoch == 0 {
2020-10-19 19:35:34 +00:00
continue
}
// We skipped the first slot so we treat the second slot as the starting slot of epoch 1.
if chainHead . HeadEpoch == 1 {
2022-02-02 19:13:52 +00:00
isFirstSlotInVotingPeriod = slot % params . BeaconConfig ( ) . SlotsPerEpoch == 1
2020-10-19 19:35:34 +00:00
} else {
isFirstSlotInVotingPeriod = slot % slotsPerVotingPeriod == 0
}
if isFirstSlotInVotingPeriod {
expectedEth1DataVote = vote
return nil
}
if ! bytes . Equal ( vote , expectedEth1DataVote ) {
return fmt . Errorf ( "incorrect eth1data vote for slot %d; expected: %#x vs voted: %#x" ,
slot , expectedEth1DataVote , vote )
}
}
return nil
}
var expectedEth1DataVote [ ] byte