github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/epoch/epoch_processing_test.go (about) 1 package epoch_test 2 3 import ( 4 "fmt" 5 "testing" 6 7 types "github.com/prysmaticlabs/eth2-types" 8 "github.com/prysmaticlabs/go-bitfield" 9 "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 11 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 12 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 13 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 14 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 15 "github.com/prysmaticlabs/prysm/shared/params" 16 "github.com/prysmaticlabs/prysm/shared/testutil" 17 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 18 "github.com/prysmaticlabs/prysm/shared/testutil/require" 19 "google.golang.org/protobuf/proto" 20 ) 21 22 func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) { 23 // Generate 2 attestations. 24 atts := make([]*pb.PendingAttestation, 2) 25 for i := 0; i < len(atts); i++ { 26 atts[i] = &pb.PendingAttestation{ 27 Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, 32)}, 28 Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 29 }, 30 AggregationBits: bitfield.Bitlist{0x00, 0xFF, 0xFF, 0xFF}, 31 } 32 } 33 34 // Generate validators and state for the 2 attestations. 35 validatorCount := 1000 36 validators := make([]*ethpb.Validator, validatorCount) 37 for i := 0; i < len(validators); i++ { 38 validators[i] = ðpb.Validator{ 39 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 40 } 41 } 42 base := &pb.BeaconState{ 43 Validators: validators, 44 RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), 45 } 46 beaconState, err := v1.InitializeFromProto(base) 47 require.NoError(t, err) 48 49 indices, err := epoch.UnslashedAttestingIndices(beaconState, atts) 50 require.NoError(t, err) 51 for i := 0; i < len(indices)-1; i++ { 52 if indices[i] >= indices[i+1] { 53 t.Error("sorted indices not sorted or duplicated") 54 } 55 } 56 57 // Verify the slashed validator is filtered. 58 slashedValidator := indices[0] 59 validators = beaconState.Validators() 60 validators[slashedValidator].Slashed = true 61 require.NoError(t, beaconState.SetValidators(validators)) 62 indices, err = epoch.UnslashedAttestingIndices(beaconState, atts) 63 require.NoError(t, err) 64 for i := 0; i < len(indices); i++ { 65 assert.NotEqual(t, slashedValidator, indices[i], "Slashed validator %d is not filtered", slashedValidator) 66 } 67 } 68 69 func TestUnslashedAttestingIndices_DuplicatedAttestations(t *testing.T) { 70 // Generate 5 of the same attestations. 71 atts := make([]*pb.PendingAttestation, 5) 72 for i := 0; i < len(atts); i++ { 73 atts[i] = &pb.PendingAttestation{ 74 Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, 32)}, 75 Target: ðpb.Checkpoint{Epoch: 0}}, 76 AggregationBits: bitfield.Bitlist{0x00, 0xFF, 0xFF, 0xFF}, 77 } 78 } 79 80 // Generate validators and state for the 5 attestations. 81 validatorCount := 1000 82 validators := make([]*ethpb.Validator, validatorCount) 83 for i := 0; i < len(validators); i++ { 84 validators[i] = ðpb.Validator{ 85 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 86 } 87 } 88 base := &pb.BeaconState{ 89 Validators: validators, 90 RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), 91 } 92 beaconState, err := v1.InitializeFromProto(base) 93 require.NoError(t, err) 94 95 indices, err := epoch.UnslashedAttestingIndices(beaconState, atts) 96 require.NoError(t, err) 97 98 for i := 0; i < len(indices)-1; i++ { 99 if indices[i] >= indices[i+1] { 100 t.Error("sorted indices not sorted or duplicated") 101 } 102 } 103 } 104 105 func TestAttestingBalance_CorrectBalance(t *testing.T) { 106 helpers.ClearCache() 107 // Generate 2 attestations. 108 atts := make([]*pb.PendingAttestation, 2) 109 for i := 0; i < len(atts); i++ { 110 atts[i] = &pb.PendingAttestation{ 111 Data: ðpb.AttestationData{ 112 Target: ðpb.Checkpoint{Root: make([]byte, 32)}, 113 Source: ðpb.Checkpoint{Root: make([]byte, 32)}, 114 Slot: types.Slot(i), 115 }, 116 AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 117 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, 118 } 119 } 120 121 // Generate validators with balances and state for the 2 attestations. 122 validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount) 123 balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount) 124 for i := 0; i < len(validators); i++ { 125 validators[i] = ðpb.Validator{ 126 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 127 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 128 } 129 balances[i] = params.BeaconConfig().MaxEffectiveBalance 130 } 131 base := &pb.BeaconState{ 132 Slot: 2, 133 RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), 134 135 Validators: validators, 136 Balances: balances, 137 } 138 beaconState, err := v1.InitializeFromProto(base) 139 require.NoError(t, err) 140 141 balance, err := epoch.AttestingBalance(beaconState, atts) 142 require.NoError(t, err) 143 wanted := 256 * params.BeaconConfig().MaxEffectiveBalance 144 assert.Equal(t, wanted, balance) 145 } 146 147 func TestBaseReward_AccurateRewards(t *testing.T) { 148 tests := []struct { 149 a uint64 150 b uint64 151 c uint64 152 }{ 153 {params.BeaconConfig().MinDepositAmount, params.BeaconConfig().MinDepositAmount, 505976}, 154 {30 * 1e9, 30 * 1e9, 2771282}, 155 {params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance, 2862174}, 156 {40 * 1e9, params.BeaconConfig().MaxEffectiveBalance, 2862174}, 157 } 158 for _, tt := range tests { 159 base := &pb.BeaconState{ 160 Validators: []*ethpb.Validator{ 161 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: tt.b}}, 162 Balances: []uint64{tt.a}, 163 } 164 beaconState, err := v1.InitializeFromProto(base) 165 require.NoError(t, err) 166 c, err := epoch.BaseReward(beaconState, 0) 167 require.NoError(t, err) 168 assert.Equal(t, tt.c, c, "epoch.BaseReward(%d)", tt.a) 169 } 170 } 171 172 func TestProcessSlashings_NotSlashed(t *testing.T) { 173 base := &pb.BeaconState{ 174 Slot: 0, 175 Validators: []*ethpb.Validator{{Slashed: true}}, 176 Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance}, 177 Slashings: []uint64{0, 1e9}, 178 } 179 s, err := v1.InitializeFromProto(base) 180 require.NoError(t, err) 181 newState, err := epoch.ProcessSlashings(s) 182 require.NoError(t, err) 183 wanted := params.BeaconConfig().MaxEffectiveBalance 184 assert.Equal(t, wanted, newState.Balances()[0], "Unexpected slashed balance") 185 } 186 187 func TestProcessSlashings_SlashedLess(t *testing.T) { 188 tests := []struct { 189 state *pb.BeaconState 190 want uint64 191 }{ 192 { 193 state: &pb.BeaconState{ 194 Validators: []*ethpb.Validator{ 195 {Slashed: true, 196 WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2, 197 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 198 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}}, 199 Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, 200 Slashings: []uint64{0, 1e9}, 201 }, 202 // penalty = validator balance / increment * (2*total_penalties) / total_balance * increment 203 // 1000000000 = (32 * 1e9) / (1 * 1e9) * (1*1e9) / (32*1e9) * (1 * 1e9) 204 want: uint64(31000000000), // 32 * 1e9 - 1000000000 205 }, 206 { 207 state: &pb.BeaconState{ 208 Validators: []*ethpb.Validator{ 209 {Slashed: true, 210 WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2, 211 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 212 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 213 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 214 }, 215 Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, 216 Slashings: []uint64{0, 1e9}, 217 }, 218 // penalty = validator balance / increment * (2*total_penalties) / total_balance * increment 219 // 500000000 = (32 * 1e9) / (1 * 1e9) * (1*1e9) / (32*1e9) * (1 * 1e9) 220 want: uint64(32000000000), // 32 * 1e9 - 500000000 221 }, 222 { 223 state: &pb.BeaconState{ 224 Validators: []*ethpb.Validator{ 225 {Slashed: true, 226 WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2, 227 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 228 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 229 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, 230 }, 231 Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, 232 Slashings: []uint64{0, 2 * 1e9}, 233 }, 234 // penalty = validator balance / increment * (3*total_penalties) / total_balance * increment 235 // 1000000000 = (32 * 1e9) / (1 * 1e9) * (1*2e9) / (64*1e9) * (1 * 1e9) 236 want: uint64(31000000000), // 32 * 1e9 - 1000000000 237 }, 238 { 239 state: &pb.BeaconState{ 240 Validators: []*ethpb.Validator{ 241 {Slashed: true, 242 WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2, 243 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement}, 244 {ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement}}, 245 Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement, params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement}, 246 Slashings: []uint64{0, 1e9}, 247 }, 248 // penalty = validator balance / increment * (3*total_penalties) / total_balance * increment 249 // 2000000000 = (32 * 1e9 - 1*1e9) / (1 * 1e9) * (2*1e9) / (31*1e9) * (1 * 1e9) 250 want: uint64(30000000000), // 32 * 1e9 - 2000000000 251 }, 252 } 253 254 for i, tt := range tests { 255 t.Run(fmt.Sprint(i), func(t *testing.T) { 256 original := proto.Clone(tt.state) 257 s, err := v1.InitializeFromProto(tt.state) 258 require.NoError(t, err) 259 newState, err := epoch.ProcessSlashings(s) 260 require.NoError(t, err) 261 assert.Equal(t, tt.want, newState.Balances()[0], "ProcessSlashings({%v}) = newState; newState.Balances[0] = %d", original, newState.Balances()[0]) 262 }) 263 } 264 } 265 266 func TestProcessFinalUpdates_CanProcess(t *testing.T) { 267 s := buildState(t, params.BeaconConfig().SlotsPerHistoricalRoot-1, uint64(params.BeaconConfig().SlotsPerEpoch)) 268 ce := helpers.CurrentEpoch(s) 269 ne := ce + 1 270 require.NoError(t, s.SetEth1DataVotes([]*ethpb.Eth1Data{})) 271 balances := s.Balances() 272 balances[0] = 31.75 * 1e9 273 balances[1] = 31.74 * 1e9 274 require.NoError(t, s.SetBalances(balances)) 275 276 slashings := s.Slashings() 277 slashings[ce] = 0 278 require.NoError(t, s.SetSlashings(slashings)) 279 mixes := s.RandaoMixes() 280 mixes[ce] = []byte{'A'} 281 require.NoError(t, s.SetRandaoMixes(mixes)) 282 newS, err := epoch.ProcessFinalUpdates(s) 283 require.NoError(t, err) 284 285 // Verify effective balance is correctly updated. 286 assert.Equal(t, params.BeaconConfig().MaxEffectiveBalance, newS.Validators()[0].EffectiveBalance, "Effective balance incorrectly updated") 287 assert.Equal(t, uint64(31*1e9), newS.Validators()[1].EffectiveBalance, "Effective balance incorrectly updated") 288 289 // Verify slashed balances correctly updated. 290 assert.Equal(t, newS.Slashings()[ce], newS.Slashings()[ne], "Unexpected slashed balance") 291 292 // Verify randao is correctly updated in the right position. 293 mix, err := newS.RandaoMixAtIndex(uint64(ne)) 294 assert.NoError(t, err) 295 assert.DeepNotEqual(t, params.BeaconConfig().ZeroHash[:], mix, "latest RANDAO still zero hashes") 296 297 // Verify historical root accumulator was appended. 298 assert.Equal(t, 1, len(newS.HistoricalRoots()), "Unexpected slashed balance") 299 currAtt, err := newS.CurrentEpochAttestations() 300 require.NoError(t, err) 301 assert.NotNil(t, currAtt, "Nil value stored in current epoch attestations instead of empty slice") 302 } 303 304 func TestProcessRegistryUpdates_NoRotation(t *testing.T) { 305 base := &pb.BeaconState{ 306 Slot: 5 * params.BeaconConfig().SlotsPerEpoch, 307 Validators: []*ethpb.Validator{ 308 {ExitEpoch: params.BeaconConfig().MaxSeedLookahead}, 309 {ExitEpoch: params.BeaconConfig().MaxSeedLookahead}, 310 }, 311 Balances: []uint64{ 312 params.BeaconConfig().MaxEffectiveBalance, 313 params.BeaconConfig().MaxEffectiveBalance, 314 }, 315 FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, 316 } 317 beaconState, err := v1.InitializeFromProto(base) 318 require.NoError(t, err) 319 newState, err := epoch.ProcessRegistryUpdates(beaconState) 320 require.NoError(t, err) 321 for i, validator := range newState.Validators() { 322 assert.Equal(t, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch, "Could not update registry %d", i) 323 } 324 } 325 326 func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) { 327 base := &pb.BeaconState{ 328 Slot: 5 * params.BeaconConfig().SlotsPerEpoch, 329 FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 6, Root: make([]byte, 32)}, 330 } 331 limit, err := helpers.ValidatorChurnLimit(0) 332 require.NoError(t, err) 333 for i := uint64(0); i < limit+10; i++ { 334 base.Validators = append(base.Validators, ðpb.Validator{ 335 ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch, 336 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 337 ActivationEpoch: params.BeaconConfig().FarFutureEpoch, 338 }) 339 } 340 beaconState, err := v1.InitializeFromProto(base) 341 require.NoError(t, err) 342 currentEpoch := helpers.CurrentEpoch(beaconState) 343 newState, err := epoch.ProcessRegistryUpdates(beaconState) 344 require.NoError(t, err) 345 for i, validator := range newState.Validators() { 346 assert.Equal(t, currentEpoch+1, validator.ActivationEligibilityEpoch, "Could not update registry %d, unexpected activation eligibility epoch", i) 347 if uint64(i) < limit && validator.ActivationEpoch != helpers.ActivationExitEpoch(currentEpoch) { 348 t.Errorf("Could not update registry %d, validators failed to activate: wanted activation epoch %d, got %d", 349 i, helpers.ActivationExitEpoch(currentEpoch), validator.ActivationEpoch) 350 } 351 if uint64(i) >= limit && validator.ActivationEpoch != params.BeaconConfig().FarFutureEpoch { 352 t.Errorf("Could not update registry %d, validators should not have been activated, wanted activation epoch: %d, got %d", 353 i, params.BeaconConfig().FarFutureEpoch, validator.ActivationEpoch) 354 } 355 } 356 } 357 358 func TestProcessRegistryUpdates_ActivationCompletes(t *testing.T) { 359 base := &pb.BeaconState{ 360 Slot: 5 * params.BeaconConfig().SlotsPerEpoch, 361 Validators: []*ethpb.Validator{ 362 {ExitEpoch: params.BeaconConfig().MaxSeedLookahead, 363 ActivationEpoch: 5 + params.BeaconConfig().MaxSeedLookahead + 1}, 364 {ExitEpoch: params.BeaconConfig().MaxSeedLookahead, 365 ActivationEpoch: 5 + params.BeaconConfig().MaxSeedLookahead + 1}, 366 }, 367 FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, 368 } 369 beaconState, err := v1.InitializeFromProto(base) 370 require.NoError(t, err) 371 newState, err := epoch.ProcessRegistryUpdates(beaconState) 372 require.NoError(t, err) 373 for i, validator := range newState.Validators() { 374 assert.Equal(t, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i) 375 } 376 } 377 378 func TestProcessRegistryUpdates_ValidatorsEjected(t *testing.T) { 379 base := &pb.BeaconState{ 380 Slot: 0, 381 Validators: []*ethpb.Validator{ 382 { 383 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 384 EffectiveBalance: params.BeaconConfig().EjectionBalance - 1, 385 }, 386 { 387 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 388 EffectiveBalance: params.BeaconConfig().EjectionBalance - 1, 389 }, 390 }, 391 FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, 392 } 393 beaconState, err := v1.InitializeFromProto(base) 394 require.NoError(t, err) 395 newState, err := epoch.ProcessRegistryUpdates(beaconState) 396 require.NoError(t, err) 397 for i, validator := range newState.Validators() { 398 assert.Equal(t, params.BeaconConfig().MaxSeedLookahead+1, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i) 399 } 400 } 401 402 func TestProcessRegistryUpdates_CanExits(t *testing.T) { 403 e := types.Epoch(5) 404 exitEpoch := helpers.ActivationExitEpoch(e) 405 minWithdrawalDelay := params.BeaconConfig().MinValidatorWithdrawabilityDelay 406 base := &pb.BeaconState{ 407 Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(e)), 408 Validators: []*ethpb.Validator{ 409 { 410 ExitEpoch: exitEpoch, 411 WithdrawableEpoch: exitEpoch + minWithdrawalDelay}, 412 { 413 ExitEpoch: exitEpoch, 414 WithdrawableEpoch: exitEpoch + minWithdrawalDelay}, 415 }, 416 FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, 417 } 418 beaconState, err := v1.InitializeFromProto(base) 419 require.NoError(t, err) 420 newState, err := epoch.ProcessRegistryUpdates(beaconState) 421 require.NoError(t, err) 422 for i, validator := range newState.Validators() { 423 assert.Equal(t, exitEpoch, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i) 424 } 425 } 426 427 func buildState(t testing.TB, slot types.Slot, validatorCount uint64) iface.BeaconState { 428 validators := make([]*ethpb.Validator, validatorCount) 429 for i := 0; i < len(validators); i++ { 430 validators[i] = ðpb.Validator{ 431 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 432 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 433 } 434 } 435 validatorBalances := make([]uint64, len(validators)) 436 for i := 0; i < len(validatorBalances); i++ { 437 validatorBalances[i] = params.BeaconConfig().MaxEffectiveBalance 438 } 439 latestActiveIndexRoots := make( 440 [][]byte, 441 params.BeaconConfig().EpochsPerHistoricalVector, 442 ) 443 for i := 0; i < len(latestActiveIndexRoots); i++ { 444 latestActiveIndexRoots[i] = params.BeaconConfig().ZeroHash[:] 445 } 446 latestRandaoMixes := make( 447 [][]byte, 448 params.BeaconConfig().EpochsPerHistoricalVector, 449 ) 450 for i := 0; i < len(latestRandaoMixes); i++ { 451 latestRandaoMixes[i] = params.BeaconConfig().ZeroHash[:] 452 } 453 s, err := testutil.NewBeaconState() 454 require.NoError(t, err) 455 if err := s.SetSlot(slot); err != nil { 456 t.Error(err) 457 } 458 if err := s.SetBalances(validatorBalances); err != nil { 459 t.Error(err) 460 } 461 if err := s.SetValidators(validators); err != nil { 462 t.Error(err) 463 } 464 return s 465 }