2018-11-23 22:44:43 +00:00
|
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
# Helpers and functions pertaining to managing the validator set
|
|
|
|
|
2018-11-23 19:42:47 +00:00
|
|
|
import
|
|
|
|
options,
|
2018-11-27 23:10:09 +00:00
|
|
|
eth_common,
|
2018-11-28 19:49:03 +00:00
|
|
|
./crypto, ./datatypes, ./digest, ./helpers
|
2018-11-23 19:42:47 +00:00
|
|
|
|
2018-12-03 17:46:22 +00:00
|
|
|
func min_empty_validator_index(validators: seq[ValidatorRecord], current_slot: uint64): Option[int] =
|
2018-11-23 19:42:47 +00:00
|
|
|
for i, v in validators:
|
2018-12-03 17:46:22 +00:00
|
|
|
if v.balance == 0 and v.last_status_change_slot + DELETION_PERIOD.uint64 <= current_slot:
|
2018-11-23 19:42:47 +00:00
|
|
|
return some(i)
|
|
|
|
|
2018-11-29 05:23:40 +00:00
|
|
|
func get_new_validators*(current_validators: seq[ValidatorRecord],
|
|
|
|
fork_data: ForkData,
|
|
|
|
pubkey: ValidatorPubKey,
|
2018-12-03 17:46:22 +00:00
|
|
|
deposit: uint64,
|
2018-11-29 05:23:40 +00:00
|
|
|
proof_of_possession: seq[byte],
|
|
|
|
withdrawal_credentials: Eth2Digest,
|
|
|
|
randao_commitment: Eth2Digest,
|
|
|
|
status: ValidatorStatusCodes,
|
|
|
|
current_slot: uint64
|
|
|
|
): tuple[validators: seq[ValidatorRecord], index: int] =
|
2018-11-29 22:11:05 +00:00
|
|
|
# TODO Spec candidate: inefficient API
|
2018-11-29 18:18:12 +00:00
|
|
|
#
|
2018-11-23 19:42:47 +00:00
|
|
|
# Check that validator really did register
|
2018-11-29 05:23:40 +00:00
|
|
|
# let signed_message = signed_message = bytes32(pubkey) + withdrawal_credentials + randao_commitment
|
2018-11-23 19:42:47 +00:00
|
|
|
# assert BLSVerify(pub=pubkey,
|
|
|
|
# msg=hash(signed_message),
|
2018-11-29 05:23:40 +00:00
|
|
|
# sig=proof_of_possession,
|
|
|
|
# domain=get_domain(
|
|
|
|
# fork_data,
|
|
|
|
# current_slot,
|
|
|
|
# DOMAIN_DEPOSIT
|
|
|
|
# ))
|
2018-11-23 19:42:47 +00:00
|
|
|
|
2018-11-29 05:23:40 +00:00
|
|
|
var new_validators = current_validators
|
|
|
|
|
|
|
|
for index, val in new_validators.mpairs():
|
|
|
|
if val.pubkey == pubkey:
|
|
|
|
# assert deposit_size >= MIN_TOPUP_SIZE
|
|
|
|
# assert val.status != WITHDRAWN
|
|
|
|
# assert val.withdrawal_credentials == withdrawal_credentials
|
|
|
|
|
2018-12-03 17:46:22 +00:00
|
|
|
val.balance.inc(deposit.int)
|
2018-11-29 05:23:40 +00:00
|
|
|
return (new_validators, index)
|
|
|
|
|
|
|
|
# new validator
|
2018-11-23 19:42:47 +00:00
|
|
|
let
|
|
|
|
rec = ValidatorRecord(
|
|
|
|
pubkey: pubkey,
|
2018-11-28 04:23:27 +00:00
|
|
|
withdrawal_credentials: withdrawal_credentials,
|
2018-11-23 19:42:47 +00:00
|
|
|
randao_commitment: randao_commitment,
|
2018-11-28 04:23:27 +00:00
|
|
|
randao_skips: 0,
|
2018-12-03 17:46:22 +00:00
|
|
|
balance: deposit,
|
2018-11-23 19:42:47 +00:00
|
|
|
status: status,
|
2018-11-28 04:23:27 +00:00
|
|
|
last_status_change_slot: current_slot,
|
2018-11-23 19:42:47 +00:00
|
|
|
exit_seq: 0
|
|
|
|
)
|
|
|
|
|
2018-12-03 17:46:22 +00:00
|
|
|
let index = min_empty_validator_index(new_validators, current_slot)
|
2018-11-23 19:42:47 +00:00
|
|
|
if index.isNone:
|
2018-11-29 05:23:40 +00:00
|
|
|
new_validators.add(rec)
|
|
|
|
(new_validators, len(new_validators) - 1)
|
2018-11-23 19:42:47 +00:00
|
|
|
else:
|
2018-11-29 05:23:40 +00:00
|
|
|
new_validators[index.get()] = rec
|
|
|
|
(new_validators, index.get())
|
2018-11-23 22:44:43 +00:00
|
|
|
|
2018-11-29 05:23:40 +00:00
|
|
|
func get_active_validator_indices*(validators: openArray[ValidatorRecord]): seq[Uint24] =
|
2018-11-23 22:44:43 +00:00
|
|
|
## Select the active validators
|
|
|
|
for idx, val in validators:
|
2018-12-03 17:46:22 +00:00
|
|
|
if val.status == ACTIVE or val.status == PENDING_EXIT:
|
2018-11-23 22:44:43 +00:00
|
|
|
result.add idx.Uint24
|
|
|
|
|
2018-11-27 23:10:09 +00:00
|
|
|
func get_new_shuffling*(seed: Eth2Digest,
|
2018-11-23 22:44:43 +00:00
|
|
|
validators: openArray[ValidatorRecord],
|
|
|
|
crosslinking_start_shard: int
|
2018-12-03 17:46:22 +00:00
|
|
|
): array[EPOCH_LENGTH, seq[ShardAndCommittee]] =
|
2018-11-23 22:44:43 +00:00
|
|
|
## 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
|
|
|
|
## Implementation should do the following: http://vitalik.ca/files/ShuffleAndAssign.png
|
|
|
|
|
|
|
|
let
|
|
|
|
active_validators = get_active_validator_indices(validators)
|
|
|
|
committees_per_slot = clamp(
|
2018-12-03 17:46:22 +00:00
|
|
|
len(active_validators) div EPOCH_LENGTH div TARGET_COMMITTEE_SIZE,
|
|
|
|
1, SHARD_COUNT div EPOCH_LENGTH)
|
2018-11-23 22:44:43 +00:00
|
|
|
# Shuffle with seed
|
|
|
|
shuffled_active_validator_indices = shuffle(active_validators, seed)
|
|
|
|
# Split the shuffled list into cycle_length pieces
|
2018-12-03 17:46:22 +00:00
|
|
|
validators_per_slot = split(shuffled_active_validator_indices, EPOCH_LENGTH)
|
2018-11-23 22:44:43 +00:00
|
|
|
|
2018-12-03 17:46:22 +00:00
|
|
|
assert validators_per_slot.len() == EPOCH_LENGTH # what split should do..
|
2018-11-23 22:44:43 +00:00
|
|
|
|
|
|
|
for slot, slot_indices in validators_per_slot:
|
|
|
|
let
|
|
|
|
shard_indices = split(slot_indices, committees_per_slot)
|
|
|
|
shard_id_start = crosslinking_start_shard + slot * committees_per_slot
|
|
|
|
|
|
|
|
var committees = newSeq[ShardAndCommittee](shard_indices.len)
|
|
|
|
for shard_position, indices in shard_indices:
|
2018-11-29 05:23:40 +00:00
|
|
|
committees[shard_position].shard =
|
|
|
|
uint64(shard_id_start + shard_position) mod SHARD_COUNT
|
2018-11-23 22:44:43 +00:00
|
|
|
committees[shard_position].committee = indices
|
|
|
|
|
|
|
|
result[slot] = committees
|