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 := ðpb.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 = ðpb.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, ðpb.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 }