github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/validators/validator_test.go (about)

     1  package validators
     2  
     3  import (
     4  	"testing"
     5  
     6  	types "github.com/prysmaticlabs/eth2-types"
     7  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
     8  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
     9  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    10  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    11  	"github.com/prysmaticlabs/prysm/shared/params"
    12  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    14  )
    15  
    16  func TestHasVoted_OK(t *testing.T) {
    17  	// Setting bitlist to 11111111.
    18  	pendingAttestation := &ethpb.Attestation{
    19  		AggregationBits: []byte{0xFF, 0x01},
    20  	}
    21  
    22  	for i := uint64(0); i < pendingAttestation.AggregationBits.Len(); i++ {
    23  		assert.Equal(t, true, pendingAttestation.AggregationBits.BitAt(i), "Validator voted but received didn't vote")
    24  	}
    25  
    26  	// Setting bit field to 10101010.
    27  	pendingAttestation = &ethpb.Attestation{
    28  		AggregationBits: []byte{0xAA, 0x1},
    29  	}
    30  
    31  	for i := uint64(0); i < pendingAttestation.AggregationBits.Len(); i++ {
    32  		voted := pendingAttestation.AggregationBits.BitAt(i)
    33  		if i%2 == 0 && voted {
    34  			t.Error("validator didn't vote but received voted")
    35  		}
    36  		if i%2 == 1 && !voted {
    37  			t.Error("validator voted but received didn't vote")
    38  		}
    39  	}
    40  }
    41  
    42  func TestInitiateValidatorExit_AlreadyExited(t *testing.T) {
    43  	exitEpoch := types.Epoch(199)
    44  	base := &pb.BeaconState{Validators: []*ethpb.Validator{{
    45  		ExitEpoch: exitEpoch},
    46  	}}
    47  	state, err := v1.InitializeFromProto(base)
    48  	require.NoError(t, err)
    49  	newState, err := InitiateValidatorExit(state, 0)
    50  	require.NoError(t, err)
    51  	v, err := newState.ValidatorAtIndex(0)
    52  	require.NoError(t, err)
    53  	assert.Equal(t, exitEpoch, v.ExitEpoch, "Already exited")
    54  }
    55  
    56  func TestInitiateValidatorExit_ProperExit(t *testing.T) {
    57  	exitedEpoch := types.Epoch(100)
    58  	idx := types.ValidatorIndex(3)
    59  	base := &pb.BeaconState{Validators: []*ethpb.Validator{
    60  		{ExitEpoch: exitedEpoch},
    61  		{ExitEpoch: exitedEpoch + 1},
    62  		{ExitEpoch: exitedEpoch + 2},
    63  		{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
    64  	}}
    65  	state, err := v1.InitializeFromProto(base)
    66  	require.NoError(t, err)
    67  	newState, err := InitiateValidatorExit(state, idx)
    68  	require.NoError(t, err)
    69  	v, err := newState.ValidatorAtIndex(idx)
    70  	require.NoError(t, err)
    71  	assert.Equal(t, exitedEpoch+2, v.ExitEpoch, "Exit epoch was not the highest")
    72  }
    73  
    74  func TestInitiateValidatorExit_ChurnOverflow(t *testing.T) {
    75  	exitedEpoch := types.Epoch(100)
    76  	idx := types.ValidatorIndex(4)
    77  	base := &pb.BeaconState{Validators: []*ethpb.Validator{
    78  		{ExitEpoch: exitedEpoch + 2},
    79  		{ExitEpoch: exitedEpoch + 2},
    80  		{ExitEpoch: exitedEpoch + 2},
    81  		{ExitEpoch: exitedEpoch + 2}, // overflow here
    82  		{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
    83  	}}
    84  	state, err := v1.InitializeFromProto(base)
    85  	require.NoError(t, err)
    86  	newState, err := InitiateValidatorExit(state, idx)
    87  	require.NoError(t, err)
    88  
    89  	// Because of exit queue overflow,
    90  	// validator who init exited has to wait one more epoch.
    91  	v, err := newState.ValidatorAtIndex(0)
    92  	require.NoError(t, err)
    93  	wantedEpoch := v.ExitEpoch + 1
    94  
    95  	v, err = newState.ValidatorAtIndex(idx)
    96  	require.NoError(t, err)
    97  	assert.Equal(t, wantedEpoch, v.ExitEpoch, "Exit epoch did not cover overflow case")
    98  }
    99  
   100  func TestSlashValidator_OK(t *testing.T) {
   101  	validatorCount := 100
   102  	registry := make([]*ethpb.Validator, 0, validatorCount)
   103  	balances := make([]uint64, 0, validatorCount)
   104  	for i := 0; i < validatorCount; i++ {
   105  		registry = append(registry, &ethpb.Validator{
   106  			ActivationEpoch:  0,
   107  			ExitEpoch:        params.BeaconConfig().FarFutureEpoch,
   108  			EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
   109  		})
   110  		balances = append(balances, params.BeaconConfig().MaxEffectiveBalance)
   111  	}
   112  
   113  	base := &pb.BeaconState{
   114  		Validators:  registry,
   115  		Slashings:   make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
   116  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   117  		Balances:    balances,
   118  	}
   119  	state, err := v1.InitializeFromProto(base)
   120  	require.NoError(t, err)
   121  
   122  	slashedIdx := types.ValidatorIndex(2)
   123  
   124  	proposer, err := helpers.BeaconProposerIndex(state)
   125  	require.NoError(t, err, "Could not get proposer")
   126  	proposerBal, err := state.BalanceAtIndex(proposer)
   127  	require.NoError(t, err)
   128  	slashedState, err := SlashValidator(state, slashedIdx)
   129  	require.NoError(t, err, "Could not slash validator")
   130  	state, ok := slashedState.(*v1.BeaconState)
   131  	require.Equal(t, true, ok)
   132  
   133  	v, err := state.ValidatorAtIndex(slashedIdx)
   134  	require.NoError(t, err)
   135  	assert.Equal(t, true, v.Slashed, "Validator not slashed despite supposed to being slashed")
   136  	assert.Equal(t, helpers.CurrentEpoch(state)+params.BeaconConfig().EpochsPerSlashingsVector, v.WithdrawableEpoch, "Withdrawable epoch not the expected value")
   137  
   138  	maxBalance := params.BeaconConfig().MaxEffectiveBalance
   139  	slashedBalance := state.Slashings()[state.Slot().Mod(uint64(params.BeaconConfig().EpochsPerSlashingsVector))]
   140  	assert.Equal(t, maxBalance, slashedBalance, "Slashed balance isnt the expected amount")
   141  
   142  	whistleblowerReward := slashedBalance / params.BeaconConfig().WhistleBlowerRewardQuotient
   143  	bal, err := state.BalanceAtIndex(proposer)
   144  	require.NoError(t, err)
   145  	// The proposer is the whistleblower in phase 0.
   146  	assert.Equal(t, proposerBal+whistleblowerReward, bal, "Did not get expected balance for proposer")
   147  	bal, err = state.BalanceAtIndex(slashedIdx)
   148  	require.NoError(t, err)
   149  	v, err = state.ValidatorAtIndex(slashedIdx)
   150  	require.NoError(t, err)
   151  	assert.Equal(t, maxBalance-(v.EffectiveBalance/params.BeaconConfig().MinSlashingPenaltyQuotient), bal, "Did not get expected balance for slashed validator")
   152  }
   153  
   154  func TestActivatedValidatorIndices(t *testing.T) {
   155  	tests := []struct {
   156  		state  *pb.BeaconState
   157  		wanted []types.ValidatorIndex
   158  	}{
   159  		{
   160  			state: &pb.BeaconState{
   161  				Validators: []*ethpb.Validator{
   162  					{
   163  						ActivationEpoch: 0,
   164  						ExitEpoch:       1,
   165  					},
   166  					{
   167  						ActivationEpoch: 0,
   168  						ExitEpoch:       1,
   169  					},
   170  					{
   171  						ActivationEpoch: 5,
   172  					},
   173  					{
   174  						ActivationEpoch: 0,
   175  						ExitEpoch:       1,
   176  					},
   177  				},
   178  			},
   179  			wanted: []types.ValidatorIndex{0, 1, 3},
   180  		},
   181  		{
   182  			state: &pb.BeaconState{
   183  				Validators: []*ethpb.Validator{
   184  					{
   185  						ActivationEpoch: helpers.ActivationExitEpoch(10),
   186  					},
   187  				},
   188  			},
   189  			wanted: []types.ValidatorIndex{},
   190  		},
   191  		{
   192  			state: &pb.BeaconState{
   193  				Validators: []*ethpb.Validator{
   194  					{
   195  						ActivationEpoch: 0,
   196  						ExitEpoch:       1,
   197  					},
   198  				},
   199  			},
   200  			wanted: []types.ValidatorIndex{0},
   201  		},
   202  	}
   203  	for _, tt := range tests {
   204  		s, err := v1.InitializeFromProto(tt.state)
   205  		require.NoError(t, err)
   206  		activatedIndices := ActivatedValidatorIndices(helpers.CurrentEpoch(s), tt.state.Validators)
   207  		assert.DeepEqual(t, tt.wanted, activatedIndices)
   208  	}
   209  }
   210  
   211  func TestSlashedValidatorIndices(t *testing.T) {
   212  	tests := []struct {
   213  		state  *pb.BeaconState
   214  		wanted []types.ValidatorIndex
   215  	}{
   216  		{
   217  			state: &pb.BeaconState{
   218  				Validators: []*ethpb.Validator{
   219  					{
   220  						WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector,
   221  						Slashed:           true,
   222  					},
   223  					{
   224  						WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector,
   225  						Slashed:           false,
   226  					},
   227  					{
   228  						WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector,
   229  						Slashed:           true,
   230  					},
   231  				},
   232  			},
   233  			wanted: []types.ValidatorIndex{0, 2},
   234  		},
   235  		{
   236  			state: &pb.BeaconState{
   237  				Validators: []*ethpb.Validator{
   238  					{
   239  						WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector,
   240  					},
   241  				},
   242  			},
   243  			wanted: []types.ValidatorIndex{},
   244  		},
   245  		{
   246  			state: &pb.BeaconState{
   247  				Validators: []*ethpb.Validator{
   248  					{
   249  						WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector,
   250  						Slashed:           true,
   251  					},
   252  				},
   253  			},
   254  			wanted: []types.ValidatorIndex{0},
   255  		},
   256  	}
   257  	for _, tt := range tests {
   258  		s, err := v1.InitializeFromProto(tt.state)
   259  		require.NoError(t, err)
   260  		slashedIndices := SlashedValidatorIndices(helpers.CurrentEpoch(s), tt.state.Validators)
   261  		assert.DeepEqual(t, tt.wanted, slashedIndices)
   262  	}
   263  }
   264  
   265  func TestExitedValidatorIndices(t *testing.T) {
   266  	tests := []struct {
   267  		state  *pb.BeaconState
   268  		wanted []types.ValidatorIndex
   269  	}{
   270  		{
   271  			state: &pb.BeaconState{
   272  				Validators: []*ethpb.Validator{
   273  					{
   274  						EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   275  						ExitEpoch:         0,
   276  						WithdrawableEpoch: params.BeaconConfig().MinValidatorWithdrawabilityDelay,
   277  					},
   278  					{
   279  						EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   280  						ExitEpoch:         0,
   281  						WithdrawableEpoch: 10,
   282  					},
   283  					{
   284  						EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   285  						ExitEpoch:         0,
   286  						WithdrawableEpoch: params.BeaconConfig().MinValidatorWithdrawabilityDelay,
   287  					},
   288  				},
   289  			},
   290  			wanted: []types.ValidatorIndex{0, 2},
   291  		},
   292  		{
   293  			state: &pb.BeaconState{
   294  				Validators: []*ethpb.Validator{
   295  					{
   296  						EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   297  						ExitEpoch:         params.BeaconConfig().FarFutureEpoch,
   298  						WithdrawableEpoch: params.BeaconConfig().MinValidatorWithdrawabilityDelay,
   299  					},
   300  				},
   301  			},
   302  			wanted: []types.ValidatorIndex{},
   303  		},
   304  		{
   305  			state: &pb.BeaconState{
   306  				Validators: []*ethpb.Validator{
   307  					{
   308  						EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   309  						ExitEpoch:         0,
   310  						WithdrawableEpoch: params.BeaconConfig().MinValidatorWithdrawabilityDelay,
   311  					},
   312  				},
   313  			},
   314  			wanted: []types.ValidatorIndex{0},
   315  		},
   316  	}
   317  	for _, tt := range tests {
   318  		s, err := v1.InitializeFromProto(tt.state)
   319  		require.NoError(t, err)
   320  		activeCount, err := helpers.ActiveValidatorCount(s, helpers.PrevEpoch(s))
   321  		require.NoError(t, err)
   322  		exitedIndices, err := ExitedValidatorIndices(0, tt.state.Validators, activeCount)
   323  		require.NoError(t, err)
   324  		assert.DeepEqual(t, tt.wanted, exitedIndices)
   325  	}
   326  }