package helpers import ( "fmt" "reflect" "strings" "testing" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" ) var size = 1<<(params.BeaconConfig().RandBytes*8) - 1 var validatorsUpperBound = make([]*pb.ValidatorRecord, size) var validator = &pb.ValidatorRecord{ ExitEpoch: params.BeaconConfig().FarFutureEpoch, } func populateValidatorsMax() { for i := 0; i < len(validatorsUpperBound); i++ { validatorsUpperBound[i] = validator } } func TestEpochCommitteeCount_Ok(t *testing.T) { // this defines the # of validators required to have 1 committee // per slot for epoch length. validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize tests := []struct { validatorCount uint64 committeeCount uint64 }{ {0, params.BeaconConfig().EpochLength}, {1000, params.BeaconConfig().EpochLength}, {2 * validatorsPerEpoch, 2 * params.BeaconConfig().EpochLength}, {5 * validatorsPerEpoch, 5 * params.BeaconConfig().EpochLength}, {16 * validatorsPerEpoch, 16 * params.BeaconConfig().EpochLength}, {32 * validatorsPerEpoch, 16 * params.BeaconConfig().EpochLength}, } for _, test := range tests { if test.committeeCount != EpochCommitteeCount(test.validatorCount) { t.Errorf("wanted: %d, got: %d", test.committeeCount, EpochCommitteeCount(test.validatorCount)) } } } func TestCurrentEpochCommitteeCount_Ok(t *testing.T) { validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize committeesPerEpoch := uint64(8) // set curr epoch total validators count to 8 committees per slot. validators := make([]*pb.ValidatorRecord, committeesPerEpoch*validatorsPerEpoch) for i := 0; i < len(validators); i++ { validators[i] = &pb.ValidatorRecord{ ExitEpoch: params.BeaconConfig().FarFutureEpoch, } } state := &pb.BeaconState{ ValidatorRegistry: validators, } if CurrentEpochCommitteeCount(state) != committeesPerEpoch*params.BeaconConfig().EpochLength { t.Errorf("Incorrect current epoch committee count per slot. Wanted: %d, got: %d", committeesPerEpoch, CurrentEpochCommitteeCount(state)) } } func TestPrevEpochCommitteeCount_Ok(t *testing.T) { validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize committeesPerEpoch := uint64(3) // set prev epoch total validators count to 3 committees per slot. validators := make([]*pb.ValidatorRecord, committeesPerEpoch*validatorsPerEpoch) for i := 0; i < len(validators); i++ { validators[i] = &pb.ValidatorRecord{ ExitEpoch: params.BeaconConfig().FarFutureEpoch, } } state := &pb.BeaconState{ ValidatorRegistry: validators, } if PrevEpochCommitteeCount(state) != committeesPerEpoch*params.BeaconConfig().EpochLength { t.Errorf("Incorrect prev epoch committee count per slot. Wanted: %d, got: %d", committeesPerEpoch, PrevEpochCommitteeCount(state)) } } func TestNextEpochCommitteeCount_Ok(t *testing.T) { validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize committeesPerEpoch := uint64(6) // set prev epoch total validators count to 3 committees per slot. validators := make([]*pb.ValidatorRecord, committeesPerEpoch*validatorsPerEpoch) for i := 0; i < len(validators); i++ { validators[i] = &pb.ValidatorRecord{ ExitEpoch: params.BeaconConfig().FarFutureEpoch, } } state := &pb.BeaconState{ ValidatorRegistry: validators, } if NextEpochCommitteeCount(state) != committeesPerEpoch*params.BeaconConfig().EpochLength { t.Errorf("Incorrect next epoch committee count per slot. Wanted: %d, got: %d", committeesPerEpoch, NextEpochCommitteeCount(state)) } } func TestShuffling_Ok(t *testing.T) { validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize committeesPerEpoch := uint64(6) // Set epoch total validators count to 6 committees per slot. validators := make([]*pb.ValidatorRecord, committeesPerEpoch*validatorsPerEpoch) for i := 0; i < len(validators); i++ { validators[i] = &pb.ValidatorRecord{ ExitEpoch: params.BeaconConfig().FarFutureEpoch, } } randaoSeed := [32]byte{'A'} slot := uint64(10) committees, err := Shuffling(randaoSeed, validators, slot) if err != nil { t.Fatalf("Could not shuffle validators: %v", err) } // Verify shuffled list is correctly split into committees_per_slot pieces. committeesPerEpoch = EpochCommitteeCount(uint64(len(validators))) committeesPerSlot := committeesPerEpoch / params.BeaconConfig().EpochLength if committeesPerSlot != committeesPerSlot { t.Errorf("Incorrect committee count after splitting. Wanted: %d, got: %d", committeesPerSlot, len(committees)) } // Verify each shuffled committee is TARGET_COMMITTEE_SIZE. for i := 0; i < len(committees); i++ { committeeCount := uint64(len(committees[i])) if committeeCount != params.BeaconConfig().TargetCommitteeSize { t.Errorf("Incorrect validator count per committee. Wanted: %d, got: %d", params.BeaconConfig().TargetCommitteeSize, committeeCount) } } } func TestShuffling_OutOfBound(t *testing.T) { populateValidatorsMax() if _, err := Shuffling([32]byte{}, validatorsUpperBound, 0); err == nil { t.Fatalf("Shuffling should have failed with exceeded upper bound") } } func TestCrosslinkCommitteesAtSlot_Ok(t *testing.T) { validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize committeesPerEpoch := uint64(6) // Set epoch total validators count to 6 committees per slot. validators := make([]*pb.ValidatorRecord, committeesPerEpoch*validatorsPerEpoch) for i := 0; i < len(validators); i++ { validators[i] = &pb.ValidatorRecord{ ExitEpoch: params.BeaconConfig().FarFutureEpoch, } } state := &pb.BeaconState{ ValidatorRegistry: validators, Slot: 200, } committees, err := CrosslinkCommitteesAtSlot(state, 132, false) if err != nil { t.Fatalf("Could not get crosslink committee: %v", err) } if len(committees) != int(committeesPerEpoch) { t.Errorf("Incorrect committee count per slot. Wanted: %d, got: %d", committeesPerEpoch, len(committees)) } newCommittees, err := CrosslinkCommitteesAtSlot(state, 180, false) if err != nil { t.Fatalf("Could not get crosslink committee: %v", err) } if reflect.DeepEqual(committees, newCommittees) { t.Error("Committees from different slot shall not be equal") } } func TestCrosslinkCommitteesAtSlot_OutOfBound(t *testing.T) { want := fmt.Sprintf( "input committee epoch %d out of bounds: %d <= epoch <= %d", 2, 0, 0, ) if _, err := CrosslinkCommitteesAtSlot(&pb.BeaconState{}, params.BeaconConfig().EpochLength*2, false); !strings.Contains(err.Error(), want) { t.Errorf("Expected %s, received %v", want, err) } } func TestCrosslinkCommitteesAtSlot_ShuffleFailed(t *testing.T) { state := &pb.BeaconState{ ValidatorRegistry: validatorsUpperBound, Slot: 100, } want := fmt.Sprint( "could not shuffle epoch validators: " + "input list exceeded upper bound and reached modulo bias", ) if _, err := CrosslinkCommitteesAtSlot(state, 1, false); !strings.Contains(err.Error(), want) { t.Errorf("Expected: %s, received: %v", want, err) } }