mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Aligning ETH2.0 spec - Make Epoch First Citizen (Shuffling and GetCrosslinkAtSlot) (#1488)
This commit is contained in:
@@ -347,7 +347,7 @@ func Crosslinks(
|
||||
epochLength := config.EpochLength
|
||||
startSlot := state.Slot - 2*epochLength
|
||||
for i := startSlot; i < state.Slot; i++ {
|
||||
crosslinkCommittees, err := validators.CrosslinkCommitteesAtSlot(state, i)
|
||||
crosslinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(state, i, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get shard committees for slot %d: %v", i, err)
|
||||
}
|
||||
|
||||
@@ -205,10 +205,16 @@ func TestInclusionDistRewards_Ok(t *testing.T) {
|
||||
ExitEpoch: config.FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
var participationBitfield []byte
|
||||
// participation byte length = number of validators / target committee size / bits in a byte.
|
||||
byteLength := int(config.DepositsForChainStart / config.TargetCommitteeSize / 8)
|
||||
for i := 0; i < byteLength; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
attestation := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: 0},
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 5},
|
||||
}
|
||||
|
||||
@@ -433,9 +439,15 @@ func TestInactivityInclusionPenalty_Ok(t *testing.T) {
|
||||
ExitEpoch: config.FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
var participationBitfield []byte
|
||||
// participation byte length = number of validators / target committee size / bits in a byte.
|
||||
byteLength := int(config.DepositsForChainStart / config.TargetCommitteeSize / 8)
|
||||
for i := 0; i < byteLength; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
attestation := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: 0},
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 5},
|
||||
}
|
||||
|
||||
@@ -511,10 +523,15 @@ func TestAttestationInclusionRewards(t *testing.T) {
|
||||
ExitEpoch: config.FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
var participationBitfield []byte
|
||||
// participation byte length = number of validators / target committee size / bits in a byte.
|
||||
byteLength := int(config.DepositsForChainStart / config.TargetCommitteeSize / 8)
|
||||
for i := 0; i < byteLength; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
attestation := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: 0},
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 0},
|
||||
}
|
||||
|
||||
|
||||
@@ -303,6 +303,10 @@ func TestHeadAttestationsNotOk(t *testing.T) {
|
||||
|
||||
func TestWinningRootOk(t *testing.T) {
|
||||
state := buildState(0, config.DepositsForChainStart)
|
||||
var participationBitfield []byte
|
||||
for i := 0; i < 16; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0x01))
|
||||
}
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
@@ -312,7 +316,7 @@ func TestWinningRootOk(t *testing.T) {
|
||||
Slot: 0,
|
||||
ShardBlockRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
@@ -330,20 +334,6 @@ func TestWinningRootOk(t *testing.T) {
|
||||
if !bytes.Equal(winnerRoot, []byte{100}) {
|
||||
t.Errorf("Incorrect winner root, wanted:[100], got: %v", winnerRoot)
|
||||
}
|
||||
|
||||
// Give root [105] one more attester
|
||||
attestations[5].ParticipationBitfield = []byte{0xff}
|
||||
winnerRoot, err = winningRoot(
|
||||
state,
|
||||
0,
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute winningRoot: %v", err)
|
||||
}
|
||||
if !bytes.Equal(winnerRoot, []byte{105}) {
|
||||
t.Errorf("Incorrect winner root, wanted:[105], got: %v", winnerRoot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinningRootCantGetParticipantBitfield(t *testing.T) {
|
||||
@@ -357,14 +347,14 @@ func TestWinningRootCantGetParticipantBitfield(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 1, 0)
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := winningRoot(state, 0, attestations, nil); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidatorsOk(t *testing.T) {
|
||||
state := buildState(0, config.DepositsForChainStart)
|
||||
state := buildState(0, config.EpochLength*2)
|
||||
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -386,8 +376,8 @@ func TestAttestingValidatorsOk(t *testing.T) {
|
||||
t.Fatalf("Could not execute AttestingValidators: %v", err)
|
||||
}
|
||||
|
||||
// Verify the winner root is attested by validator 237 224 based on shuffling.
|
||||
if !reflect.DeepEqual(attestedValidators, []uint64{237, 224}) {
|
||||
// Verify the winner root is attested by validator 109 97 based on shuffling.
|
||||
if !reflect.DeepEqual(attestedValidators, []uint64{109, 97}) {
|
||||
t.Errorf("Active validators don't match. Wanted:[237,224], Got: %v", attestedValidators)
|
||||
}
|
||||
}
|
||||
@@ -402,7 +392,7 @@ func TestAttestingValidatorsCantGetWinningRoot(t *testing.T) {
|
||||
ParticipationBitfield: []byte{},
|
||||
}
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 1, 0)
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := AttestingValidators(state, 0, []*pb.PendingAttestationRecord{attestation}, nil); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
@@ -410,7 +400,7 @@ func TestAttestingValidatorsCantGetWinningRoot(t *testing.T) {
|
||||
|
||||
func TestTotalAttestingBalanceOk(t *testing.T) {
|
||||
validatorsPerCommittee := uint64(2)
|
||||
state := buildState(0, config.DepositsForChainStart)
|
||||
state := buildState(0, 2*config.EpochLength)
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
@@ -449,7 +439,7 @@ func TestTotalAttestingBalanceCantGetWinningRoot(t *testing.T) {
|
||||
ParticipationBitfield: []byte{},
|
||||
}
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 1, 0)
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := TotalAttestingBalance(state, 0, []*pb.PendingAttestationRecord{attestation}, nil); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
@@ -472,16 +462,20 @@ func TestTotalBalance(t *testing.T) {
|
||||
|
||||
func TestInclusionSlotOk(t *testing.T) {
|
||||
state := buildState(0, config.DepositsForChainStart)
|
||||
var participationBitfield []byte
|
||||
for i := 0; i < 16; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
state.LatestAttestations = []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{},
|
||||
ParticipationBitfield: []byte{0xFF},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 101},
|
||||
{Data: &pb.AttestationData{},
|
||||
ParticipationBitfield: []byte{0xFF},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 100},
|
||||
{Data: &pb.AttestationData{},
|
||||
ParticipationBitfield: []byte{0xFF},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 102},
|
||||
}
|
||||
slot, err := InclusionSlot(state, 237)
|
||||
@@ -496,13 +490,14 @@ func TestInclusionSlotOk(t *testing.T) {
|
||||
|
||||
func TestInclusionSlotBadBitfield(t *testing.T) {
|
||||
state := buildState(0, config.DepositsForChainStart)
|
||||
|
||||
state.LatestAttestations = []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{},
|
||||
ParticipationBitfield: []byte{},
|
||||
SlotIncluded: 100},
|
||||
}
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 1, 0)
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := InclusionSlot(state, 0); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
@@ -520,10 +515,14 @@ func TestInclusionSlotNotFound(t *testing.T) {
|
||||
|
||||
func TestInclusionDistanceOk(t *testing.T) {
|
||||
state := buildState(0, config.DepositsForChainStart)
|
||||
var participationBitfield []byte
|
||||
for i := 0; i < 16; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
state.LatestAttestations = []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{},
|
||||
ParticipationBitfield: []byte{0xFF},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
SlotIncluded: 100},
|
||||
}
|
||||
distance, err := InclusionDistance(state, 237)
|
||||
@@ -548,7 +547,7 @@ func TestInclusionDistanceBadBitfield(t *testing.T) {
|
||||
SlotIncluded: 100},
|
||||
}
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 1, 0)
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := InclusionDistance(state, 0); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ func ProcessCrosslinks(
|
||||
}
|
||||
|
||||
for i := startSlot; i < state.Slot; i++ {
|
||||
crosslinkCommittees, err := validators.CrosslinkCommitteesAtSlot(state, i)
|
||||
crosslinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(state, i, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get committees for slot %d: %v", i, err)
|
||||
}
|
||||
|
||||
@@ -295,6 +295,10 @@ func TestProcessFinalization(t *testing.T) {
|
||||
func TestProcessCrosslinksOk(t *testing.T) {
|
||||
state := buildState(5, config.DepositsForChainStart)
|
||||
state.LatestCrosslinks = []*pb.CrosslinkRecord{{}, {}}
|
||||
var participationBitfield []byte
|
||||
for i := 0; i < 16; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -303,7 +307,7 @@ func TestProcessCrosslinksOk(t *testing.T) {
|
||||
ShardBlockRootHash32: []byte{'A'},
|
||||
},
|
||||
// All validators attested to the above roots.
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
ParticipationBitfield: participationBitfield,
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
@@ -341,7 +345,7 @@ func TestProcessCrosslinksNoParticipantsBitField(t *testing.T) {
|
||||
|
||||
wanted := fmt.Sprintf(
|
||||
"wanted participants bitfield length %d, got: %d",
|
||||
1, 0,
|
||||
16, 0,
|
||||
)
|
||||
if _, err := ProcessCrosslinks(state, attestations, nil); !strings.Contains(err.Error(), wanted) {
|
||||
t.Errorf("Expected: %s, received: %s", wanted, err.Error())
|
||||
|
||||
@@ -11,8 +11,11 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -26,5 +29,8 @@ go_test(
|
||||
"validators_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//proto/beacon/p2p/v1:go_default_library"],
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// CrosslinkCommittee defines the validator committee of slot and shard combinations.
|
||||
type CrosslinkCommittee struct {
|
||||
Committee []uint64
|
||||
Shard uint64
|
||||
}
|
||||
|
||||
// EpochCommitteeCount returns the number of crosslink committees of an epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
@@ -20,15 +33,15 @@ import (
|
||||
// ) * EPOCH_LENGTH
|
||||
func EpochCommitteeCount(activeValidatorCount uint64) uint64 {
|
||||
var minCommitteePerSlot = uint64(1)
|
||||
var maxCommitteePerSlot = config.ShardCount / config.EpochLength
|
||||
var currCommitteePerSlot = activeValidatorCount / config.EpochLength / config.TargetCommitteeSize
|
||||
var maxCommitteePerSlot = params.BeaconConfig().ShardCount / params.BeaconConfig().EpochLength
|
||||
var currCommitteePerSlot = activeValidatorCount / params.BeaconConfig().EpochLength / params.BeaconConfig().TargetCommitteeSize
|
||||
if currCommitteePerSlot > maxCommitteePerSlot {
|
||||
return maxCommitteePerSlot * config.EpochLength
|
||||
return maxCommitteePerSlot * params.BeaconConfig().EpochLength
|
||||
}
|
||||
if currCommitteePerSlot < 1 {
|
||||
return minCommitteePerSlot * config.EpochLength
|
||||
return minCommitteePerSlot * params.BeaconConfig().EpochLength
|
||||
}
|
||||
return currCommitteePerSlot * config.EpochLength
|
||||
return currCommitteePerSlot * params.BeaconConfig().EpochLength
|
||||
}
|
||||
|
||||
// CurrentEpochCommitteeCount returns the number of crosslink committees per epoch
|
||||
@@ -88,3 +101,197 @@ func NextEpochCommitteeCount(state *pb.BeaconState) uint64 {
|
||||
state.ValidatorRegistry, CurrentEpoch(state)+1)
|
||||
return EpochCommitteeCount(uint64(len(prevActiveValidatorIndices)))
|
||||
}
|
||||
|
||||
// CrosslinkCommitteesAtSlot returns the list of crosslink committees, it
|
||||
// contains the shard associated with the committee and the validator indices
|
||||
// in that committee.
|
||||
// def get_crosslink_committees_at_slot(state: BeaconState,
|
||||
// slot: SlotNumber,
|
||||
// registry_change=False: bool) -> List[Tuple[List[ValidatorIndex], ShardNumber]]:
|
||||
// """
|
||||
// Return the list of ``(committee, shard)`` tuples for the ``slot``.
|
||||
//
|
||||
// Note: There are two possible shufflings for crosslink committees for a
|
||||
// ``slot`` in the next epoch -- with and without a `registry_change`
|
||||
// """
|
||||
// epoch = slot_to_epoch(slot)
|
||||
// current_epoch = get_current_epoch(state)
|
||||
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch
|
||||
// next_epoch = current_epoch + 1
|
||||
//
|
||||
// assert previous_epoch <= epoch <= next_epoch
|
||||
//
|
||||
// if epoch == previous_epoch:
|
||||
// committees_per_epoch = get_previous_epoch_committee_count(state)
|
||||
// seed = state.previous_epoch_seed
|
||||
// shuffling_epoch = state.previous_calculation_epoch
|
||||
// shuffling_start_shard = state.previous_epoch_start_shard
|
||||
// elif epoch == current_epoch:
|
||||
// committees_per_epoch = get_current_epoch_committee_count(state)
|
||||
// seed = state.current_epoch_seed
|
||||
// shuffling_epoch = state.current_calculation_epoch
|
||||
// shuffling_start_shard = state.current_epoch_start_shard
|
||||
// elif epoch == next_epoch:
|
||||
// current_committees_per_epoch = get_current_epoch_committee_count(state)
|
||||
// committees_per_epoch = get_next_epoch_committee_count(state)
|
||||
// shuffling_epoch = next_epoch
|
||||
//
|
||||
// epochs_since_last_registry_update = current_epoch - state.validator_registry_update_epoch
|
||||
// if registry_change:
|
||||
// seed = generate_seed(state, next_epoch)
|
||||
// shuffling_start_shard = (state.current_epoch_start_shard + current_committees_per_epoch) % SHARD_COUNT
|
||||
// elif epochs_since_last_registry_update > 1 and is_power_of_two(epochs_since_last_registry_update):
|
||||
// seed = generate_seed(state, next_epoch)
|
||||
// shuffling_start_shard = state.current_epoch_start_shard
|
||||
// else:
|
||||
// seed = state.current_epoch_seed
|
||||
// shuffling_start_shard = state.current_epoch_start_shard
|
||||
//
|
||||
// shuffling = get_shuffling(
|
||||
// seed,
|
||||
// state.validator_registry,
|
||||
// shuffling_epoch,
|
||||
// )
|
||||
// offset = slot % EPOCH_LENGTH
|
||||
// committees_per_slot = committees_per_epoch // EPOCH_LENGTH
|
||||
// slot_start_shard = (shuffling_start_shard + committees_per_slot * offset) % SHARD_COUNT
|
||||
//
|
||||
// return [
|
||||
// (
|
||||
// shuffling[committees_per_slot * offset + i],
|
||||
// (slot_start_shard + i) % SHARD_COUNT,
|
||||
// )
|
||||
// for i in range(committees_per_slot)
|
||||
// ]
|
||||
func CrosslinkCommitteesAtSlot(
|
||||
state *pb.BeaconState,
|
||||
slot uint64,
|
||||
registryChange bool) ([]*CrosslinkCommittee, error) {
|
||||
var committeesPerEpoch uint64
|
||||
var shufflingEpoch uint64
|
||||
var shufflingStartShard uint64
|
||||
var seed [32]byte
|
||||
var err error
|
||||
|
||||
wantedEpoch := SlotToEpoch(slot)
|
||||
currentEpoch := CurrentEpoch(state)
|
||||
prevEpoch := PrevEpoch(state)
|
||||
nextEpoch := NextEpoch(state)
|
||||
|
||||
if wantedEpoch < prevEpoch || wantedEpoch > nextEpoch {
|
||||
return nil, fmt.Errorf(
|
||||
"input committee epoch %d out of bounds: %d <= epoch <= %d",
|
||||
wantedEpoch,
|
||||
prevEpoch,
|
||||
currentEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
if wantedEpoch == prevEpoch {
|
||||
committeesPerEpoch = PrevEpochCommitteeCount(state)
|
||||
seed = bytesutil.ToBytes32(state.PreviousEpochSeedHash32)
|
||||
shufflingEpoch = state.PreviousEpochCalculationSlot
|
||||
shufflingStartShard = state.PreviousEpochStartShard
|
||||
} else if wantedEpoch == currentEpoch {
|
||||
committeesPerEpoch = PrevEpochCommitteeCount(state)
|
||||
seed = bytesutil.ToBytes32(state.CurrentEpochSeedHash32)
|
||||
shufflingEpoch = state.CurrentEpochCalculationSlot
|
||||
shufflingStartShard = state.CurrentEpochStartShard
|
||||
} else if wantedEpoch == nextEpoch {
|
||||
currentCommitteesPerEpoch := CurrentEpochCommitteeCount(state)
|
||||
committeesPerEpoch = NextEpochCommitteeCount(state)
|
||||
shufflingEpoch = nextEpoch
|
||||
|
||||
epochsSinceLastRegistryUpdate := currentEpoch - state.ValidatorRegistryUpdateSlot
|
||||
if registryChange {
|
||||
seed, err = GenerateSeed(state, nextEpoch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not generate seed: %v", err)
|
||||
}
|
||||
shufflingStartShard = (state.CurrentEpochStartShard + currentCommitteesPerEpoch) %
|
||||
params.BeaconConfig().ShardCount
|
||||
} else if epochsSinceLastRegistryUpdate > 1 &&
|
||||
mathutil.IsPowerOf2(epochsSinceLastRegistryUpdate) {
|
||||
seed, err = GenerateSeed(state, nextEpoch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not generate seed: %v", err)
|
||||
}
|
||||
shufflingStartShard = state.CurrentEpochStartShard
|
||||
} else {
|
||||
seed = bytesutil.ToBytes32(state.CurrentEpochSeedHash32)
|
||||
shufflingStartShard = state.CurrentEpochStartShard
|
||||
}
|
||||
}
|
||||
|
||||
shuffledIndices, err := Shuffling(
|
||||
seed,
|
||||
state.ValidatorRegistry,
|
||||
shufflingEpoch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not shuffle epoch validators: %v", err)
|
||||
}
|
||||
|
||||
offSet := slot % params.BeaconConfig().EpochLength
|
||||
committeesPerSlot := committeesPerEpoch / params.BeaconConfig().EpochLength
|
||||
slotStardShard := (shufflingStartShard + committeesPerSlot*offSet) %
|
||||
params.BeaconConfig().ShardCount
|
||||
|
||||
var crosslinkCommittees []*CrosslinkCommittee
|
||||
for i := uint64(0); i < committeesPerSlot; i++ {
|
||||
crosslinkCommittees = append(crosslinkCommittees, &CrosslinkCommittee{
|
||||
Committee: shuffledIndices[committeesPerSlot*offSet+i],
|
||||
Shard: (slotStardShard + i) % params.BeaconConfig().ShardCount,
|
||||
})
|
||||
}
|
||||
|
||||
return crosslinkCommittees, nil
|
||||
}
|
||||
|
||||
// Shuffling shuffles input validator indices and splits them by slot and shard.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_shuffling(seed: Bytes32,
|
||||
// validators: List[Validator],
|
||||
// epoch: EpochNumber) -> List[List[ValidatorIndex]]
|
||||
// """
|
||||
// Shuffle ``validators`` into crosslink committees seeded by ``seed`` and ``epoch``.
|
||||
// Return a list of ``committees_per_epoch`` committees where each
|
||||
// committee is itself a list of validator indices.
|
||||
// """
|
||||
//
|
||||
// active_validator_indices = get_active_validator_indices(validators, epoch)
|
||||
//
|
||||
// committees_per_epoch = get_epoch_committee_count(len(active_validator_indices))
|
||||
//
|
||||
// # Shuffle
|
||||
// seed = xor(seed, int_to_bytes32(epoch))
|
||||
// shuffled_active_validator_indices = shuffle(active_validator_indices, seed)
|
||||
//
|
||||
// # Split the shuffled list into committees_per_epoch pieces
|
||||
// return split(shuffled_active_validator_indices, committees_per_epoch)
|
||||
func Shuffling(
|
||||
seed [32]byte,
|
||||
validators []*pb.ValidatorRecord,
|
||||
slot uint64) ([][]uint64, error) {
|
||||
|
||||
// Normalize slot to start of epoch boundary.
|
||||
slot -= slot % params.BeaconConfig().EpochLength
|
||||
|
||||
// Figure out how many committees can be in a single slot.
|
||||
activeIndices := ActiveValidatorIndices(validators, slot)
|
||||
activeCount := uint64(len(activeIndices))
|
||||
committeesPerEpoch := EpochCommitteeCount(activeCount)
|
||||
|
||||
// Convert slot to bytes and xor it with seed.
|
||||
slotInBytes := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(slotInBytes, slot)
|
||||
seed = bytesutil.ToBytes32(bytesutil.Xor(seed[:], slotInBytes))
|
||||
|
||||
shuffledIndices, err := utils.ShuffleIndices(seed, activeIndices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Split the shuffled list into epoch_length * committees_per_slot pieces.
|
||||
return utils.SplitIndices(shuffledIndices, committeesPerEpoch), nil
|
||||
}
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
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 := config.EpochLength * config.TargetCommitteeSize
|
||||
validatorsPerEpoch := params.BeaconConfig().EpochLength * params.BeaconConfig().TargetCommitteeSize
|
||||
tests := []struct {
|
||||
validatorCount uint64
|
||||
committeeCount uint64
|
||||
}{
|
||||
{0, config.EpochLength},
|
||||
{1000, config.EpochLength},
|
||||
{2 * validatorsPerEpoch, 2 * config.EpochLength},
|
||||
{5 * validatorsPerEpoch, 5 * config.EpochLength},
|
||||
{16 * validatorsPerEpoch, 16 * config.EpochLength},
|
||||
{32 * validatorsPerEpoch, 16 * config.EpochLength},
|
||||
{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) {
|
||||
@@ -29,13 +45,13 @@ func TestEpochCommitteeCount_Ok(t *testing.T) {
|
||||
}
|
||||
}
|
||||
func TestCurrentEpochCommitteeCount_Ok(t *testing.T) {
|
||||
validatorsPerEpoch := config.EpochLength * config.TargetCommitteeSize
|
||||
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: config.FarFutureEpoch,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,20 +59,20 @@ func TestCurrentEpochCommitteeCount_Ok(t *testing.T) {
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
|
||||
if CurrentEpochCommitteeCount(state) != committeesPerEpoch*config.EpochLength {
|
||||
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 := config.EpochLength * config.TargetCommitteeSize
|
||||
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: config.FarFutureEpoch,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,28 +80,133 @@ func TestPrevEpochCommitteeCount_Ok(t *testing.T) {
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
|
||||
if PrevEpochCommitteeCount(state) != committeesPerEpoch*config.EpochLength {
|
||||
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 := config.EpochLength * config.TargetCommitteeSize
|
||||
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: config.FarFutureEpoch,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
if NextEpochCommitteeCount(state) != committeesPerEpoch*config.EpochLength {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// GenerateSeed generates the randao seed of a given epoch.
|
||||
@@ -20,8 +21,8 @@ import (
|
||||
// get_active_index_root(state, epoch)
|
||||
// )
|
||||
func GenerateSeed(state *pb.BeaconState, wantedEpoch uint64) ([32]byte, error) {
|
||||
if wantedEpoch > config.SeedLookahead {
|
||||
wantedEpoch -= config.SeedLookahead
|
||||
if wantedEpoch > params.BeaconConfig().SeedLookahead {
|
||||
wantedEpoch -= params.BeaconConfig().SeedLookahead
|
||||
}
|
||||
randaoMix, err := RandaoMix(state, wantedEpoch)
|
||||
if err != nil {
|
||||
@@ -47,14 +48,14 @@ func GenerateSeed(state *pb.BeaconState, wantedEpoch uint64) ([32]byte, error) {
|
||||
func ActiveIndexRoot(state *pb.BeaconState, wantedEpoch uint64) ([]byte, error) {
|
||||
var earliestEpoch uint64
|
||||
currentEpoch := CurrentEpoch(state)
|
||||
if currentEpoch > config.LatestIndexRootsLength+config.EntryExitDelay {
|
||||
earliestEpoch = currentEpoch - (config.LatestIndexRootsLength + config.EntryExitDelay)
|
||||
if currentEpoch > params.BeaconConfig().LatestIndexRootsLength+params.BeaconConfig().EntryExitDelay {
|
||||
earliestEpoch = currentEpoch - (params.BeaconConfig().LatestIndexRootsLength + params.BeaconConfig().EntryExitDelay)
|
||||
}
|
||||
if earliestEpoch > wantedEpoch || wantedEpoch >= currentEpoch {
|
||||
return nil, fmt.Errorf("input indexRoot epoch %d out of bounds: %d <= epoch < %d",
|
||||
wantedEpoch, earliestEpoch, currentEpoch)
|
||||
}
|
||||
return state.LatestIndexRootHash32S[wantedEpoch%config.LatestIndexRootsLength], nil
|
||||
return state.LatestIndexRootHash32S[wantedEpoch%params.BeaconConfig().LatestIndexRootsLength], nil
|
||||
}
|
||||
|
||||
// RandaoMix returns the randao mix (xor'ed seed)
|
||||
@@ -71,12 +72,12 @@ func ActiveIndexRoot(state *pb.BeaconState, wantedEpoch uint64) ([]byte, error)
|
||||
func RandaoMix(state *pb.BeaconState, wantedEpoch uint64) ([]byte, error) {
|
||||
var earliestEpoch uint64
|
||||
currentEpoch := CurrentEpoch(state)
|
||||
if currentEpoch > config.LatestRandaoMixesLength {
|
||||
earliestEpoch = currentEpoch - config.LatestRandaoMixesLength
|
||||
if currentEpoch > params.BeaconConfig().LatestRandaoMixesLength {
|
||||
earliestEpoch = currentEpoch - params.BeaconConfig().LatestRandaoMixesLength
|
||||
}
|
||||
if earliestEpoch > wantedEpoch || wantedEpoch >= currentEpoch {
|
||||
return nil, fmt.Errorf("input randaoMix epoch %d out of bounds: %d <= epoch < %d",
|
||||
wantedEpoch, earliestEpoch, currentEpoch)
|
||||
}
|
||||
return state.LatestRandaoMixesHash32S[wantedEpoch%config.LatestRandaoMixesLength], nil
|
||||
return state.LatestRandaoMixesHash32S[wantedEpoch%params.BeaconConfig().LatestRandaoMixesLength], nil
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ import (
|
||||
"testing"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestRandaoMix_Ok(t *testing.T) {
|
||||
randaoMixes := make([][]byte, config.LatestRandaoMixesLength)
|
||||
randaoMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
|
||||
for i := 0; i < len(randaoMixes); i++ {
|
||||
intInBytes := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(intInBytes, uint64(i))
|
||||
@@ -32,11 +33,11 @@ func TestRandaoMix_Ok(t *testing.T) {
|
||||
},
|
||||
{
|
||||
epoch: 99999,
|
||||
randaoMix: randaoMixes[99999%config.LatestRandaoMixesLength],
|
||||
randaoMix: randaoMixes[99999%params.BeaconConfig().LatestRandaoMixesLength],
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state.Slot = (test.epoch + 1) * config.EpochLength
|
||||
state.Slot = (test.epoch + 1) * params.BeaconConfig().EpochLength
|
||||
mix, err := RandaoMix(state, test.epoch)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get randao mix: %v", err)
|
||||
@@ -59,7 +60,7 @@ func TestRandaoMix_OutOfBound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestActiveIndexRoot_Ok(t *testing.T) {
|
||||
activeIndexRoots := make([][]byte, config.LatestIndexRootsLength)
|
||||
activeIndexRoots := make([][]byte, params.BeaconConfig().LatestIndexRootsLength)
|
||||
for i := 0; i < len(activeIndexRoots); i++ {
|
||||
intInBytes := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(intInBytes, uint64(i))
|
||||
@@ -80,11 +81,11 @@ func TestActiveIndexRoot_Ok(t *testing.T) {
|
||||
},
|
||||
{
|
||||
epoch: 999999,
|
||||
indexRoot: activeIndexRoots[999999%config.LatestIndexRootsLength],
|
||||
indexRoot: activeIndexRoots[999999%params.BeaconConfig().LatestIndexRootsLength],
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state.Slot = (test.epoch + 1) * config.EpochLength
|
||||
state.Slot = (test.epoch + 1) * params.BeaconConfig().EpochLength
|
||||
indexRoot, err := ActiveIndexRoot(state, test.epoch)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get index root: %v", err)
|
||||
@@ -109,7 +110,7 @@ func TestActiveIndexRoot_OutOfBound(t *testing.T) {
|
||||
func TestGenerateSeed_OutOfBound(t *testing.T) {
|
||||
wanted := fmt.Sprintf(
|
||||
"input randaoMix epoch %d out of bounds: %d <= epoch < %d",
|
||||
100-config.SeedLookahead, 0, 0,
|
||||
100-params.BeaconConfig().SeedLookahead, 0, 0,
|
||||
)
|
||||
if _, err := GenerateSeed(&pb.BeaconState{}, 100); !strings.Contains(err.Error(), wanted) {
|
||||
t.Errorf("Expected: %s, received: %s", wanted, err.Error())
|
||||
@@ -117,25 +118,25 @@ func TestGenerateSeed_OutOfBound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerateSeed_Ok(t *testing.T) {
|
||||
activeIndexRoots := make([][]byte, config.LatestIndexRootsLength)
|
||||
activeIndexRoots := make([][]byte, params.BeaconConfig().LatestIndexRootsLength)
|
||||
for i := 0; i < len(activeIndexRoots); i++ {
|
||||
intInBytes := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(intInBytes, uint64(i))
|
||||
activeIndexRoots[i] = intInBytes
|
||||
}
|
||||
randaoMixes := make([][]byte, config.LatestRandaoMixesLength)
|
||||
randaoMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
|
||||
for i := 0; i < len(randaoMixes); i++ {
|
||||
intInBytes := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(intInBytes, uint64(i))
|
||||
randaoMixes[i] = intInBytes
|
||||
}
|
||||
slot := 10 * config.SeedLookahead * config.EpochLength
|
||||
slot := 10 * params.BeaconConfig().SeedLookahead * params.BeaconConfig().EpochLength
|
||||
state := &pb.BeaconState{
|
||||
LatestIndexRootHash32S: activeIndexRoots,
|
||||
LatestRandaoMixesHash32S: randaoMixes,
|
||||
Slot: slot}
|
||||
|
||||
got, err := GenerateSeed(state, 10*config.EpochLength)
|
||||
got, err := GenerateSeed(state, 10*params.BeaconConfig().EpochLength)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate seed: %v", err)
|
||||
}
|
||||
|
||||
@@ -5,15 +5,13 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var config = params.BeaconConfig()
|
||||
|
||||
// SlotToEpoch returns the epoch number of the input slot.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def slot_to_epoch(slot: SlotNumber) -> EpochNumber:
|
||||
// return slot // EPOCH_LENGTH
|
||||
func SlotToEpoch(slot uint64) uint64 {
|
||||
return slot / config.EpochLength
|
||||
return slot / params.BeaconConfig().EpochLength
|
||||
}
|
||||
|
||||
// CurrentEpoch returns the current epoch number calculated from
|
||||
@@ -49,5 +47,5 @@ func NextEpoch(state *pb.BeaconState) uint64 {
|
||||
// def get_epoch_start_slot(epoch: EpochNumber) -> SlotNumber:
|
||||
// return epoch * EPOCH_LENGTH
|
||||
func StartSlot(epoch uint64) uint64 {
|
||||
return epoch * config.EpochLength
|
||||
return epoch * params.BeaconConfig().EpochLength
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestSlotToEpoch(t *testing.T) {
|
||||
@@ -11,11 +12,11 @@ func TestSlotToEpoch(t *testing.T) {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0 / config.EpochLength},
|
||||
{slot: 50, epoch: 0 / config.EpochLength},
|
||||
{slot: 64, epoch: 64 / config.EpochLength},
|
||||
{slot: 128, epoch: 128 / config.EpochLength},
|
||||
{slot: 200, epoch: 200 / config.EpochLength},
|
||||
{slot: 0, epoch: 0 / params.BeaconConfig().EpochLength},
|
||||
{slot: 50, epoch: 0 / params.BeaconConfig().EpochLength},
|
||||
{slot: 64, epoch: 64 / params.BeaconConfig().EpochLength},
|
||||
{slot: 128, epoch: 128 / params.BeaconConfig().EpochLength},
|
||||
{slot: 200, epoch: 200 / params.BeaconConfig().EpochLength},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if tt.epoch != SlotToEpoch(tt.slot) {
|
||||
@@ -29,11 +30,11 @@ func TestCurrentEpoch(t *testing.T) {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0 / config.EpochLength},
|
||||
{slot: 50, epoch: 0 / config.EpochLength},
|
||||
{slot: 64, epoch: 64 / config.EpochLength},
|
||||
{slot: 128, epoch: 128 / config.EpochLength},
|
||||
{slot: 200, epoch: 200 / config.EpochLength},
|
||||
{slot: 0, epoch: 0 / params.BeaconConfig().EpochLength},
|
||||
{slot: 50, epoch: 0 / params.BeaconConfig().EpochLength},
|
||||
{slot: 64, epoch: 64 / params.BeaconConfig().EpochLength},
|
||||
{slot: 128, epoch: 128 / params.BeaconConfig().EpochLength},
|
||||
{slot: 200, epoch: 200 / params.BeaconConfig().EpochLength},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.slot}
|
||||
@@ -48,11 +49,11 @@ func TestPrevEpoch(t *testing.T) {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0 / config.EpochLength},
|
||||
{slot: 50, epoch: 0 / config.EpochLength},
|
||||
{slot: 64, epoch: 64/config.EpochLength - 1},
|
||||
{slot: 128, epoch: 128/config.EpochLength - 1},
|
||||
{slot: 200, epoch: 200/config.EpochLength - 1},
|
||||
{slot: 0, epoch: 0 / params.BeaconConfig().EpochLength},
|
||||
{slot: 50, epoch: 0 / params.BeaconConfig().EpochLength},
|
||||
{slot: 64, epoch: 64/params.BeaconConfig().EpochLength - 1},
|
||||
{slot: 128, epoch: 128/params.BeaconConfig().EpochLength - 1},
|
||||
{slot: 200, epoch: 200/params.BeaconConfig().EpochLength - 1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.slot}
|
||||
@@ -67,11 +68,11 @@ func TestNextEpoch(t *testing.T) {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0/config.EpochLength + 1},
|
||||
{slot: 50, epoch: 0/config.EpochLength + 1},
|
||||
{slot: 64, epoch: 64/config.EpochLength + 1},
|
||||
{slot: 128, epoch: 128/config.EpochLength + 1},
|
||||
{slot: 200, epoch: 200/config.EpochLength + 1},
|
||||
{slot: 0, epoch: 0/params.BeaconConfig().EpochLength + 1},
|
||||
{slot: 50, epoch: 0/params.BeaconConfig().EpochLength + 1},
|
||||
{slot: 64, epoch: 64/params.BeaconConfig().EpochLength + 1},
|
||||
{slot: 128, epoch: 128/params.BeaconConfig().EpochLength + 1},
|
||||
{slot: 200, epoch: 200/params.BeaconConfig().EpochLength + 1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.slot}
|
||||
@@ -86,9 +87,9 @@ func TestEpochStartSlot(t *testing.T) {
|
||||
epoch uint64
|
||||
startSlot uint64
|
||||
}{
|
||||
{epoch: 0, startSlot: 0 * config.EpochLength},
|
||||
{epoch: 1, startSlot: 1 * config.EpochLength},
|
||||
{epoch: 10, startSlot: 10 * config.EpochLength},
|
||||
{epoch: 0, startSlot: 0 * params.BeaconConfig().EpochLength},
|
||||
{epoch: 1, startSlot: 1 * params.BeaconConfig().EpochLength},
|
||||
{epoch: 10, startSlot: 10 * params.BeaconConfig().EpochLength},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.epoch}
|
||||
|
||||
@@ -2,6 +2,7 @@ package helpers
|
||||
|
||||
import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// IsActiveValidator returns the boolean value on whether the validator
|
||||
@@ -49,5 +50,5 @@ func ActiveValidatorIndices(validators []*pb.ValidatorRecord, epoch uint64) []ui
|
||||
// """
|
||||
// return epoch + 1 + ENTRY_EXIT_DELAY
|
||||
func EntryExitEffectEpoch(epoch uint64) uint64 {
|
||||
return epoch + 1 + config.EntryExitDelay
|
||||
return epoch + 1 + params.BeaconConfig().EntryExitDelay
|
||||
}
|
||||
|
||||
@@ -548,7 +548,7 @@ func TestProcessEpoch_CantGetPrevValidatorIndices(t *testing.T) {
|
||||
}
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"input committee epoch 0 out of bounds: %d <= epoch < %d",
|
||||
"input committee epoch 0 out of bounds: %d <= epoch <= %d",
|
||||
helpers.SlotToEpoch(config.EpochLength),
|
||||
helpers.SlotToEpoch(config.EpochLength*2),
|
||||
)
|
||||
@@ -583,6 +583,10 @@ func TestProcessEpoch_CantProcessEjections(t *testing.T) {
|
||||
for i := uint64(0); i < 4*config.EpochLength; i++ {
|
||||
randaoHashes = append(randaoHashes, []byte{byte(i)})
|
||||
}
|
||||
var participationBitfield []byte
|
||||
for i := 0; i < 16; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
ExitEpoch := 4*config.EpochLength + 1
|
||||
validatorRegistries[0].ExitEpoch = ExitEpoch
|
||||
@@ -595,7 +599,7 @@ func TestProcessEpoch_CantProcessEjections(t *testing.T) {
|
||||
LatestRandaoMixesHash32S: randaoHashes,
|
||||
LatestCrosslinks: []*pb.CrosslinkRecord{{}},
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{}, ParticipationBitfield: []byte{0xFF}},
|
||||
{Data: &pb.AttestationData{}, ParticipationBitfield: participationBitfield},
|
||||
}}
|
||||
|
||||
want := fmt.Sprintf("could not process inclusion distance: 0")
|
||||
|
||||
@@ -10,7 +10,6 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bitutil:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
|
||||
@@ -5,16 +5,12 @@
|
||||
package validators
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bitutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// CrosslinkCommittee defines the validator committee of slot and shard combinations.
|
||||
@@ -53,7 +49,7 @@ func AttestationParticipants(
|
||||
participationBitfield []byte) ([]uint64, error) {
|
||||
|
||||
// Find the relevant committee.
|
||||
crosslinkCommittees, err := CrosslinkCommitteesAtSlot(state, attestationData.Slot)
|
||||
crosslinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(state, attestationData.Slot, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -85,153 +81,3 @@ func AttestationParticipants(
|
||||
}
|
||||
return participants, nil
|
||||
}
|
||||
|
||||
// CrosslinkCommitteesAtSlot returns the list of crosslink committees, it
|
||||
// contains the shard associated with the committee and the validator indices
|
||||
// in that committee.
|
||||
// def get_crosslink_committees_at_slot(state: BeaconState,
|
||||
// slot: SlotNumber) -> List[Tuple[List[ValidatorIndex], ShardNumber]]:
|
||||
// """
|
||||
// Returns the list of ``(committee, shard)`` tuples for the ``slot``.
|
||||
// """
|
||||
// epoch = slot_to_epoch(slot)
|
||||
// current_epoch = get_current_epoch(state)
|
||||
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch
|
||||
// next_epoch = current_epoch + 1
|
||||
//
|
||||
// assert previous_epoch <= epoch < next_epoch
|
||||
//
|
||||
// if epoch < current_epoch:
|
||||
// committees_per_epoch = get_previous_epoch_committee_count(state)
|
||||
// seed = state.previous_epoch_seed
|
||||
// shuffling_epoch = state.previous_calculation_epoch
|
||||
// shuffling_start_shard = state.previous_epoch_start_shard
|
||||
// else:
|
||||
// committees_per_epoch = get_current_epoch_committee_count(state)
|
||||
// seed = state.current_epoch_seed
|
||||
// shuffling_epoch = state.current_calculation_epoch
|
||||
// shuffling_start_shard = state.current_epoch_start_shard
|
||||
//
|
||||
// shuffling = get_shuffling(
|
||||
// seed,
|
||||
// state.validator_registry,
|
||||
// shuffling_epoch,
|
||||
// )
|
||||
// offset = slot % EPOCH_LENGTH
|
||||
// committees_per_slot = committees_per_epoch // EPOCH_LENGTH
|
||||
// slot_start_shard = (shuffling_start_shard + committees_per_slot * offset) % SHARD_COUNT
|
||||
//
|
||||
// return [
|
||||
// (
|
||||
// shuffling[committees_per_slot * offset + i],
|
||||
// (slot_start_shard + i) % SHARD_COUNT,
|
||||
// )
|
||||
// for i in range(committees_per_slot)
|
||||
// ]
|
||||
func CrosslinkCommitteesAtSlot(state *pb.BeaconState, slot uint64) ([]*CrosslinkCommittee, error) {
|
||||
var countPerSlot uint64
|
||||
var startShard uint64
|
||||
var shuffledIndices [][]uint64
|
||||
var err error
|
||||
|
||||
wantedEpoch := helpers.SlotToEpoch(slot)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
nextEpoch := helpers.NextEpoch(state)
|
||||
|
||||
if wantedEpoch < prevEpoch || wantedEpoch >= nextEpoch {
|
||||
return nil, fmt.Errorf(
|
||||
"input committee epoch %d out of bounds: %d <= epoch < %d",
|
||||
wantedEpoch,
|
||||
prevEpoch,
|
||||
currentEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
offSet := slot % params.BeaconConfig().EpochLength
|
||||
if wantedEpoch < currentEpoch {
|
||||
countPerSlot = helpers.PrevEpochCommitteeCount(state)
|
||||
shuffledIndices, err = Shuffling(
|
||||
bytesutil.ToBytes32(state.PreviousEpochSeedHash32),
|
||||
state.ValidatorRegistry,
|
||||
state.PreviousEpochCalculationSlot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not shuffle prev epoch validators: %v", err)
|
||||
}
|
||||
startShard = (state.PreviousEpochStartShard + countPerSlot*offSet) %
|
||||
params.BeaconConfig().ShardCount
|
||||
} else {
|
||||
countPerSlot = helpers.CurrentEpochCommitteeCount(state)
|
||||
shuffledIndices, err = Shuffling(
|
||||
bytesutil.ToBytes32(state.CurrentEpochSeedHash32),
|
||||
state.ValidatorRegistry,
|
||||
state.CurrentEpochCalculationSlot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not shuffle current epoch validators: %v", err)
|
||||
}
|
||||
startShard = (state.CurrentEpochCalculationSlot + countPerSlot*offSet) %
|
||||
params.BeaconConfig().ShardCount
|
||||
}
|
||||
|
||||
var crosslinkCommittees []*CrosslinkCommittee
|
||||
for i := uint64(0); i < countPerSlot; i++ {
|
||||
crosslinkCommittees = append(crosslinkCommittees, &CrosslinkCommittee{
|
||||
Committee: shuffledIndices[countPerSlot*offSet+i],
|
||||
Shard: (startShard + i) % params.BeaconConfig().ShardCount,
|
||||
})
|
||||
}
|
||||
|
||||
return crosslinkCommittees, nil
|
||||
}
|
||||
|
||||
// Shuffling shuffles input validator indices and splits them by slot and shard.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_shuffling(seed: Bytes32,
|
||||
// validators: List[Validator],
|
||||
// slot: int) -> List[List[int]]
|
||||
// """
|
||||
// Shuffles ``validators`` into crosslink committees seeded by ``seed`` and ``slot``.
|
||||
// Returns a list of ``EPOCH_LENGTH * committees_per_slot`` committees where each
|
||||
// committee is itself a list of validator indices.
|
||||
// """
|
||||
//
|
||||
// # Normalizes slot to start of epoch boundary
|
||||
// slot -= slot % EPOCH_LENGTH
|
||||
//
|
||||
// active_validator_indices = get_active_validator_indices(validators, slot)
|
||||
//
|
||||
// committees_per_slot = get_committee_count_per_slot(len(active_validator_indices))
|
||||
//
|
||||
// # Shuffle
|
||||
// seed = xor(seed, int_to_bytes32(slot))
|
||||
// shuffled_active_validator_indices = shuffle(active_validator_indices, seed)
|
||||
//
|
||||
// # Split the shuffled list into epoch_length * committees_per_slot pieces
|
||||
// return split(shuffled_active_validator_indices, committees_per_slot * EPOCH_LENGTH)
|
||||
func Shuffling(
|
||||
seed [32]byte,
|
||||
validators []*pb.ValidatorRecord,
|
||||
slot uint64) ([][]uint64, error) {
|
||||
|
||||
// Normalize slot to start of epoch boundary.
|
||||
slot -= slot % params.BeaconConfig().EpochLength
|
||||
|
||||
// Figure out how many committees can be in a single slot.
|
||||
activeIndices := helpers.ActiveValidatorIndices(validators, slot)
|
||||
activeCount := uint64(len(activeIndices))
|
||||
committeesPerSlot := helpers.EpochCommitteeCount(activeCount)
|
||||
|
||||
// Convert slot to bytes and xor it with seed.
|
||||
slotInBytes := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(slotInBytes, slot)
|
||||
seed = bytesutil.ToBytes32(bytesutil.Xor(seed[:], slotInBytes))
|
||||
|
||||
shuffledIndices, err := utils.ShuffleIndices(seed, activeIndices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Split the shuffled list into epoch_length * committees_per_slot pieces.
|
||||
return utils.SplitIndices(shuffledIndices, committeesPerSlot*params.BeaconConfig().EpochLength), nil
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package validators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestAttestationParticipants_ok(t *testing.T) {
|
||||
@@ -17,7 +13,7 @@ func TestAttestationParticipants_ok(t *testing.T) {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
validators := make([]*pb.ValidatorRecord, params.BeaconConfig().DepositsForChainStart)
|
||||
validators := make([]*pb.ValidatorRecord, 2*params.BeaconConfig().EpochLength)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.ValidatorRecord{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
@@ -40,37 +36,37 @@ func TestAttestationParticipants_ok(t *testing.T) {
|
||||
{
|
||||
attestationSlot: 2,
|
||||
stateSlot: 5,
|
||||
shard: 256,
|
||||
shard: 2,
|
||||
bitfield: []byte{0xFF},
|
||||
wanted: []uint64{766, 752},
|
||||
wanted: []uint64{11, 121},
|
||||
},
|
||||
{
|
||||
attestationSlot: 1,
|
||||
stateSlot: 10,
|
||||
shard: 128,
|
||||
shard: 1,
|
||||
bitfield: []byte{77},
|
||||
wanted: []uint64{511},
|
||||
wanted: []uint64{117},
|
||||
},
|
||||
{
|
||||
attestationSlot: 10,
|
||||
stateSlot: 20,
|
||||
shard: 383,
|
||||
shard: 10,
|
||||
bitfield: []byte{0xFF},
|
||||
wanted: []uint64{3069, 2608},
|
||||
wanted: []uint64{14, 30},
|
||||
},
|
||||
{
|
||||
attestationSlot: 64,
|
||||
stateSlot: 100,
|
||||
shard: 0,
|
||||
bitfield: []byte{0xFF},
|
||||
wanted: []uint64{237, 224},
|
||||
wanted: []uint64{109, 97},
|
||||
},
|
||||
{
|
||||
attestationSlot: 999,
|
||||
stateSlot: 1000,
|
||||
shard: 1023,
|
||||
shard: 39,
|
||||
bitfield: []byte{99},
|
||||
wanted: []uint64{10494},
|
||||
wanted: []uint64{89},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -115,124 +111,3 @@ func TestAttestationParticipants_IncorrectBitfield(t *testing.T) {
|
||||
t.Error("attestation participants should have failed with incorrect bitfield")
|
||||
}
|
||||
}
|
||||
|
||||
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 = helpers.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().EpochLength != params.BeaconConfig().TargetCommitteeSize {
|
||||
t.Errorf("Incorrect validator count per committee. Wanted: %d, got: %d",
|
||||
params.BeaconConfig().TargetCommitteeSize, committeeCount*params.BeaconConfig().EpochLength)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get crosslink committee: %v", err)
|
||||
}
|
||||
if len(committees) != int(committeesPerEpoch*params.BeaconConfig().EpochLength) {
|
||||
t.Errorf("Incorrect committee count per slot. Wanted: %d, got: %d",
|
||||
committeesPerEpoch*params.BeaconConfig().EpochLength, len(committees))
|
||||
}
|
||||
|
||||
newCommittees, err := CrosslinkCommitteesAtSlot(state, 180)
|
||||
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",
|
||||
1, 0, 0,
|
||||
)
|
||||
|
||||
if _, err := CrosslinkCommitteesAtSlot(&pb.BeaconState{}, params.BeaconConfig().EpochLength+1); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrosslinkCommitteesAtPrevSlot_ShuffleFailed(t *testing.T) {
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validatorsUpperBound,
|
||||
Slot: 100,
|
||||
}
|
||||
|
||||
want := fmt.Sprint(
|
||||
"could not shuffle prev epoch validators: " +
|
||||
"input list exceeded upper bound and reached modulo bias",
|
||||
)
|
||||
|
||||
if _, err := CrosslinkCommitteesAtSlot(state, 1); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected: %s, received: %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrosslinkCommitteesAtCurrSlot_ShuffleFailed(t *testing.T) {
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validatorsUpperBound,
|
||||
Slot: 100,
|
||||
}
|
||||
|
||||
want := fmt.Sprint(
|
||||
"could not shuffle current epoch validators: " +
|
||||
"input list exceeded upper bound and reached modulo bias",
|
||||
)
|
||||
|
||||
if _, err := CrosslinkCommitteesAtSlot(state, 99); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected: %s, received: %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func ActiveValidators(state *pb.BeaconState, validatorIndices []uint32) []*pb.Va
|
||||
// first_committee, _ = get_crosslink_committees_at_slot(state, slot)[0]
|
||||
// return first_committee[slot % len(first_committee)]
|
||||
func BeaconProposerIdx(state *pb.BeaconState, slot uint64) (uint64, error) {
|
||||
committeeArray, err := CrosslinkCommitteesAtSlot(state, slot)
|
||||
committeeArray, err := helpers.CrosslinkCommitteesAtSlot(state, slot, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -13,18 +13,6 @@ import (
|
||||
"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 TestHasVoted(t *testing.T) {
|
||||
// Setting bit field to 11111111.
|
||||
pendingAttestation := &pb.Attestation{
|
||||
@@ -189,7 +177,7 @@ func TestBoundaryAttesterIndices(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
validators := make([]*pb.ValidatorRecord, params.BeaconConfig().DepositsForChainStart)
|
||||
validators := make([]*pb.ValidatorRecord, params.BeaconConfig().EpochLength*2)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.ValidatorRecord{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
@@ -210,9 +198,9 @@ func TestBoundaryAttesterIndices(t *testing.T) {
|
||||
t.Fatalf("Failed to run BoundaryAttesterIndices: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(attesterIndices, []uint64{237, 224}) {
|
||||
if !reflect.DeepEqual(attesterIndices, []uint64{109, 97}) {
|
||||
t.Errorf("Incorrect boundary attester indices. Wanted: %v, got: %v",
|
||||
[]uint64{237, 224}, attesterIndices)
|
||||
[]uint64{109, 97}, attesterIndices)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,19 +230,19 @@ func TestBeaconProposerIdx(t *testing.T) {
|
||||
},
|
||||
{
|
||||
slot: 10,
|
||||
index: 2797,
|
||||
index: 2807,
|
||||
},
|
||||
{
|
||||
slot: 19,
|
||||
index: 4658,
|
||||
index: 5122,
|
||||
},
|
||||
{
|
||||
slot: 30,
|
||||
index: 7917,
|
||||
index: 7947,
|
||||
},
|
||||
{
|
||||
slot: 39,
|
||||
index: 9778,
|
||||
index: 10262,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -296,39 +284,31 @@ func TestAttestingValidatorIndices_Ok(t *testing.T) {
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 5,
|
||||
Slot: 0,
|
||||
}
|
||||
|
||||
prevAttestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 3,
|
||||
Shard: 384,
|
||||
ShardBlockRootHash32: []byte{'B'},
|
||||
},
|
||||
ParticipationBitfield: []byte{0xFF},
|
||||
}
|
||||
|
||||
thisAttestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 3,
|
||||
Shard: 385,
|
||||
Shard: 6,
|
||||
ShardBlockRootHash32: []byte{'B'},
|
||||
},
|
||||
ParticipationBitfield: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
|
||||
}
|
||||
|
||||
indices, err := AttestingValidatorIndices(
|
||||
state,
|
||||
384,
|
||||
6,
|
||||
[]byte{'B'},
|
||||
[]*pb.PendingAttestationRecord{thisAttestation},
|
||||
nil,
|
||||
[]*pb.PendingAttestationRecord{prevAttestation})
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute AttestingValidatorIndices: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(indices, []uint64{213, 1024}) {
|
||||
if !reflect.DeepEqual(indices, []uint64{1141, 688}) {
|
||||
t.Errorf("Could not get incorrect validator indices. Wanted: %v, got: %v",
|
||||
[]uint64{213, 1024}, indices)
|
||||
[]uint64{1141, 688}, indices)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func setupInitialDeposits(t *testing.T) []*pb.Deposit {
|
||||
|
||||
@@ -5,17 +5,15 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
BIN
beacon-chain/main
Executable file
BIN
beacon-chain/main
Executable file
Binary file not shown.
@@ -12,6 +12,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/rpc",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// ValidatorServer defines a server implementation of the gRPC Validator service,
|
||||
@@ -59,7 +59,7 @@ func (vs *ValidatorServer) ValidatorEpochAssignments(
|
||||
var proposerSlot uint64
|
||||
|
||||
for slot := req.EpochStart; slot < req.EpochStart+params.BeaconConfig().EpochLength; slot++ {
|
||||
crossLinkCommittees, err := v.CrosslinkCommitteesAtSlot(beaconState, slot)
|
||||
crossLinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(beaconState, slot, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -108,9 +108,9 @@ func TestValidatorEpochAssignments(t *testing.T) {
|
||||
}
|
||||
// With initial shuffling of default 16384 validators, the validator corresponding to
|
||||
// public key 0 should correspond to an attester slot of 2 at shard 5.
|
||||
if res.Assignment.Shard != 358 {
|
||||
if res.Assignment.Shard != 5 {
|
||||
t.Errorf(
|
||||
"Expected validator with pubkey %#x to be assigned to shard 358, received %d",
|
||||
"Expected validator with pubkey %#x to be assigned to shard 5, received %d",
|
||||
req.PublicKey,
|
||||
res.Assignment.Shard,
|
||||
)
|
||||
|
||||
@@ -7,10 +7,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
Reference in New Issue
Block a user