nimbus-eth2/beacon_chain/spec/beaconstate.nim

154 lines
5.7 KiB
Nim
Raw Normal View History

# beacon_chain
# 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.
import
math, sequtils,
../extras,
./datatypes, ./digest, ./helpers, ./validator
func on_startup*(initial_validator_entries: openArray[InitialValidator],
genesis_time: uint64,
processed_pow_receipt_root: Eth2Digest): BeaconState =
## BeaconState constructor
##
## Before the beacon chain starts, validators will register in the Eth1 chain
## and deposit ETH. When enough many validators have registered, a
## `ChainStart` log will be emitted and the beacon chain can start beaconing.
##
## Because the state root hash is part of the genesis block, the beacon state
## must be calculated before creating the genesis block.
#
# Induct validators
# Not in spec: the system doesn't work unless there are at least EPOCH_LENGTH
# validators - there needs to be at least one member in each committee -
# good to know for testing, though arguably the system is not that useful at
# at that point :)
assert initial_validator_entries.len >= EPOCH_LENGTH
var validators: seq[ValidatorRecord]
for v in initial_validator_entries:
validators = get_new_validators(
validators,
ForkData(
pre_fork_version: INITIAL_FORK_VERSION,
post_fork_version: INITIAL_FORK_VERSION,
fork_slot: INITIAL_SLOT_NUMBER
),
v.pubkey,
v.deposit_size,
v.proof_of_possession,
v.withdrawal_credentials,
v.randao_commitment,
ACTIVE,
INITIAL_SLOT_NUMBER
).validators
# Setup state
let
initial_shuffling = get_new_shuffling(Eth2Digest(), validators, 0)
# initial_shuffling + initial_shuffling in spec, but more ugly
var shard_and_committee_for_slots: array[2 * EPOCH_LENGTH, seq[ShardAndCommittee]]
for i, n in initial_shuffling:
shard_and_committee_for_slots[i] = n
shard_and_committee_for_slots[EPOCH_LENGTH + i] = n
# TODO validators vs indices
let active_validator_indices = get_active_validator_indices(validators)
let persistent_committees = split(shuffle(
active_validator_indices, ZERO_HASH), SHARD_COUNT)
BeaconState(
validator_registry: validators,
validator_registry_latest_change_slot: INITIAL_SLOT_NUMBER,
validator_registry_exit_count: 0,
validator_registry_delta_chain_tip: ZERO_HASH,
# Randomness and committees
randao_mix: ZERO_HASH,
next_seed: ZERO_HASH,
shard_and_committee_for_slots: shard_and_committee_for_slots,
persistent_committees: persistent_committees,
# Finality
previous_justified_slot: INITIAL_SLOT_NUMBER,
justified_slot: INITIAL_SLOT_NUMBER,
finalized_slot: INITIAL_SLOT_NUMBER,
# Recent state
latest_state_recalculation_slot: INITIAL_SLOT_NUMBER,
latest_block_hashes: repeat(ZERO_HASH, EPOCH_LENGTH * 2),
# PoW receipt root
processed_pow_receipt_root: processed_pow_receipt_root,
# Misc
genesis_time: genesis_time,
fork_data: ForkData(
pre_fork_version: INITIAL_FORK_VERSION,
post_fork_version: INITIAL_FORK_VERSION,
fork_slot: INITIAL_SLOT_NUMBER,
),
)
2018-11-29 01:08:34 +00:00
func get_block_hash*(state: BeaconState,
current_block: BeaconBlock,
slot: uint64): Eth2Digest =
let earliest_slot_in_array =
current_block.slot.int - state.latest_block_hashes.len
assert earliest_slot_in_array <= slot.int
assert slot < current_block.slot
2018-11-29 01:08:34 +00:00
state.latest_block_hashes[slot.int - earliest_slot_in_array]
func append_to_recent_block_hashes*(old_block_hashes: seq[Eth2Digest],
parent_slot, current_slot: uint64,
parent_hash: Eth2Digest): seq[Eth2Digest] =
let d = current_slot - parent_slot
result = old_block_hashes
result.add repeat(parent_hash, d)
func get_attestation_participants*(state: BeaconState,
attestation_data: AttestationData,
participation_bitfield: seq[byte]): seq[Uint24] =
## Attestation participants in the attestation data are called out in a
## bit field that corresponds to the committee of the shard at the time - this
## function converts it to list of indices in to BeaconState.validators
## Returns empty list if the shard is not found
# TODO Linear search through shard list? borderline ok, it's a small list
# TODO bitfield type needed, once bit order settles down
# TODO iterator candidate
let
sncs_for_slot = get_shard_and_committees_for_slot(
state, attestation_data.slot)
for snc in sncs_for_slot:
if snc.shard != attestation_data.shard:
continue
# TODO investigate functional library / approach to help avoid loop bugs
assert len(participation_bitfield) == ceil_div8(len(snc.committee))
for i, vindex in snc.committee:
let
bit = (participation_bitfield[i div 8] shr (7 - (i mod 8))) mod 2
if bit == 1:
result.add(vindex)
return # found the shard, we're done
func change_validators*(state: var BeaconState,
current_slot: uint64) =
## Change validator registry.
let res = get_changed_validators(
state.validator_registry,
state.latest_penalized_exit_balances,
state.validator_registry_delta_chain_tip,
current_slot
)
state.validator_registry = res.validators
state.latest_penalized_exit_balances = res.latest_penalized_exit_balances