new shuffling routine and adjust tests for it

This commit is contained in:
Dustin Brody 2019-01-22 14:36:31 -08:00
parent d728f113ac
commit 21b8bd7f71
2 changed files with 34 additions and 40 deletions

View File

@ -22,6 +22,7 @@ func min_empty_validator_index*(
ZERO_BALANCE_VALIDATOR_TTL.uint64 <= current_slot:
return some(i)
# TODO remove this once get_shuffling works
func get_shuffling_prev*(seed: Eth2Digest,
validators: openArray[Validator],
crosslinking_start_shard: uint64, # TODO remove
@ -60,43 +61,38 @@ func get_shuffling_prev*(seed: Eth2Digest,
result[slot] = committees
func xorSeed(seed: Eth2Digest, x: uint64): Eth2Digest =
## Integers are all encoded as bigendian
## Helper for get_shuffling in lieu of generally better bitwise handling
## xor least significant/highest-index 8 bytes in place (after copy)
result = seed
for i in 0 ..< 8:
result.data[31 - i] = result.data[31 - i] xor byte((x shr i*8) and 0xff)
func get_shuffling*(seed: Eth2Digest,
validators: openArray[Validator],
crosslinking_start_shard: uint64, # TODO remove
slot_nonaligned: uint64
): array[EPOCH_LENGTH, seq[ShardCommittee]] =
## Split up validators into groups at the start of every epoch,
## determining at what height they can make attestations and what shard they are making crosslinks for
): seq[seq[Uint24]] =
## 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.
## Implementation should do the following: http://vitalik.ca/files/ShuffleAndAssign.png
let
slot = slot_nonaligned - slot_nonaligned mod EPOCH_LENGTH
active_validator_indices = get_active_validator_indices(validators, slot)
committees_per_slot = clamp(
len(active_validator_indices) div EPOCH_LENGTH div TARGET_COMMITTEE_SIZE,
1, SHARD_COUNT div EPOCH_LENGTH).uint64
# Shuffle with seed
shuffled_active_validator_indices = shuffle(active_validator_indices, seed)
# Split the shuffled list into cycle_length pieces
validators_per_slot = split(shuffled_active_validator_indices, EPOCH_LENGTH)
assert validators_per_slot.len() == EPOCH_LENGTH # what split should do..
committees_per_slot = get_committee_count_per_slot(len(active_validator_indices)).int
for slot, slot_indices in validators_per_slot:
let
shard_indices = split(slot_indices, committees_per_slot)
shard_id_start =
crosslinking_start_shard + slot.uint64 * committees_per_slot
# Shuffle
shuffled_active_validator_indices = shuffle(
active_validator_indices,
xorSeed(seed, slot))
var committees = newSeq[ShardCommittee](shard_indices.len)
for shard_position, indices in shard_indices:
committees[shard_position].shard =
shard_id_start + shard_position.uint64 mod SHARD_COUNT.uint64
committees[shard_position].committee = indices
committees[shard_position].total_validator_count =
len(active_validator_indices).uint64
result[slot] = committees
# Split the shuffled list into epoch_length * committees_per_slot pieces
result = split(shuffled_active_validator_indices, committees_per_slot * EPOCH_LENGTH)
assert result.len() == committees_per_slot * EPOCH_LENGTH # what split should do..
func get_new_validator_registry_delta_chain_tip*(
current_validator_registry_delta_chain_tip: Eth2Digest,

View File

@ -6,12 +6,12 @@
import
math,unittest, sequtils,
../beacon_chain/spec/[datatypes, digest, validator]
../beacon_chain/spec/[helpers, datatypes, digest, validator]
func sumCommittees(v: openArray[seq[ShardCommittee]]): int =
func sumCommittees(v: openArray[seq[Uint24]], reqCommitteeLen: int): int =
for x in v:
for y in x:
inc result, y.committee.len
assert x.len == reqCommitteeLen
inc result, x.len
suite "Validators":
## For now just test that we can compile and execute block processing with mock data.
@ -19,17 +19,15 @@ suite "Validators":
## https://github.com/sigp/lighthouse/blob/ba548e49a52687a655c61b443b6835d79c6d4236/beacon_chain/validator_shuffling/src/shuffle.rs
test "Smoke validator shuffling":
let
num_validators = 32*1024
validators = repeat(
Validator(
exit_slot: FAR_FUTURE_SLOT
), 32*1024)
# TODO the shuffling looks really odd, probably buggy
let s = get_shuffling_prev(Eth2Digest(), validators, 0, 0)
), num_validators)
s = get_shuffling(Eth2Digest(), validators, 0)
committees = EPOCH_LENGTH * get_committee_count_per_slot(len(validators)).int
check:
s.len == EPOCH_LENGTH
# 32k validators means 2 shards validated per slot - the aim is to get
# TARGET_COMMITTEE_SIZE validators in each shard and there are
# EPOCH_LENGTH slots which each will crosslink a different shard
s[0].len == 32 * 1024 div (TARGET_COMMITTEE_SIZE * EPOCH_LENGTH)
sumCommittees(s) == validators.len() # all validators accounted for
s.len == committees
# 32k validators: EPOCH_LENGTH slots * committee_count_per_slot =
# EPOCH_LENGTH * committee_count_per_slot committees.
sumCommittees(s, num_validators div committees) == validators.len() # all validators accounted for