2018-11-28 19:49:03 +00:00
|
|
|
# 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
|
2018-12-13 16:00:55 +00:00
|
|
|
chronicles, math, options, sequtils,
|
2018-12-11 17:55:45 +00:00
|
|
|
../extras, ../ssz,
|
|
|
|
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
2018-11-28 19:49:03 +00:00
|
|
|
|
2019-01-29 04:15:00 +00:00
|
|
|
func get_effective_balance*(state: BeaconState, index: ValidatorIndex): uint64 =
|
2018-12-27 20:14:37 +00:00
|
|
|
# Validators collect rewards which increases their balance but not their
|
|
|
|
# influence. Validators may also lose balance if they fail to do their duty
|
|
|
|
# in which case their influence decreases. Once they drop below a certain
|
|
|
|
# balance, they're removed from the validator registry.
|
2019-01-21 18:26:58 +00:00
|
|
|
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
2018-12-27 20:14:37 +00:00
|
|
|
|
|
|
|
func sum_effective_balances*(
|
2019-01-29 04:15:00 +00:00
|
|
|
state: BeaconState, validator_indices: openArray[ValidatorIndex]): uint64 =
|
2018-12-27 20:14:37 +00:00
|
|
|
# TODO spec - add as helper? Used pretty often
|
|
|
|
for index in validator_indices:
|
|
|
|
result += get_effective_balance(state, index)
|
|
|
|
|
|
|
|
func validate_proof_of_possession(state: BeaconState,
|
|
|
|
pubkey: ValidatorPubKey,
|
|
|
|
proof_of_possession: ValidatorSig,
|
|
|
|
withdrawal_credentials: Eth2Digest,
|
|
|
|
randao_commitment: Eth2Digest): bool =
|
|
|
|
let proof_of_possession_data = DepositInput(
|
|
|
|
pubkey: pubkey,
|
|
|
|
withdrawal_credentials: withdrawal_credentials,
|
|
|
|
randao_commitment: randao_commitment
|
|
|
|
)
|
|
|
|
|
|
|
|
bls_verify(
|
|
|
|
pubkey,
|
|
|
|
hash_tree_root_final(proof_of_possession_data).data,
|
|
|
|
proof_of_possession,
|
|
|
|
get_domain(
|
2019-01-29 03:22:22 +00:00
|
|
|
state.fork,
|
2018-12-27 20:14:37 +00:00
|
|
|
state.slot,
|
|
|
|
DOMAIN_DEPOSIT,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2018-12-13 16:00:55 +00:00
|
|
|
func process_deposit(state: var BeaconState,
|
|
|
|
pubkey: ValidatorPubKey,
|
2019-01-30 08:41:07 +00:00
|
|
|
amount: uint64,
|
2018-12-13 16:00:55 +00:00
|
|
|
proof_of_possession: ValidatorSig,
|
|
|
|
withdrawal_credentials: Eth2Digest,
|
2019-01-30 08:41:07 +00:00
|
|
|
randao_commitment: Eth2Digest) =
|
2018-12-13 16:00:55 +00:00
|
|
|
## Process a deposit from Ethereum 1.0.
|
|
|
|
|
2019-01-17 08:14:55 +00:00
|
|
|
if false:
|
|
|
|
# TODO return error; currently, just fails if ever called
|
|
|
|
# but hadn't been set up to run at all
|
|
|
|
doAssert validate_proof_of_possession(
|
|
|
|
state, pubkey, proof_of_possession, withdrawal_credentials,
|
|
|
|
randao_commitment)
|
2018-12-27 23:40:22 +00:00
|
|
|
|
|
|
|
let validator_pubkeys = state.validator_registry.mapIt(it.pubkey)
|
2018-12-13 16:00:55 +00:00
|
|
|
|
|
|
|
if pubkey notin validator_pubkeys:
|
|
|
|
# Add new validator
|
2019-01-17 18:27:11 +00:00
|
|
|
let validator = Validator(
|
2018-12-13 16:00:55 +00:00
|
|
|
pubkey: pubkey,
|
|
|
|
withdrawal_credentials: withdrawal_credentials,
|
|
|
|
randao_commitment: randao_commitment,
|
|
|
|
randao_layers: 0,
|
2019-01-29 03:22:22 +00:00
|
|
|
activation_epoch: FAR_FUTURE_EPOCH,
|
|
|
|
exit_epoch: FAR_FUTURE_EPOCH,
|
|
|
|
withdrawal_epoch: FAR_FUTURE_EPOCH,
|
|
|
|
penalized_epoch: FAR_FUTURE_EPOCH,
|
2019-01-16 11:39:16 +00:00
|
|
|
exit_count: 0,
|
|
|
|
status_flags: 0,
|
2018-12-13 16:00:55 +00:00
|
|
|
)
|
|
|
|
|
2019-01-30 08:41:07 +00:00
|
|
|
# Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled.
|
|
|
|
state.validator_registry.add(validator)
|
|
|
|
state.validator_balances.add(amount)
|
2018-12-13 16:00:55 +00:00
|
|
|
else:
|
2019-01-16 12:20:44 +00:00
|
|
|
# Increase balance by deposit amount
|
2018-12-13 16:00:55 +00:00
|
|
|
let index = validator_pubkeys.find(pubkey)
|
|
|
|
let validator = addr state.validator_registry[index]
|
2018-12-27 20:14:37 +00:00
|
|
|
assert state.validator_registry[index].withdrawal_credentials ==
|
|
|
|
withdrawal_credentials
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-01-30 08:41:07 +00:00
|
|
|
state.validator_balances[index] += amount
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
func get_entry_exit_effect_epoch*(epoch: EpochNumber): EpochNumber =
|
|
|
|
## An entry or exit triggered in the ``epoch`` given by the input takes effect at
|
|
|
|
## the epoch given by the output.
|
|
|
|
epoch + 1 + ENTRY_EXIT_DELAY
|
|
|
|
|
2018-12-13 16:00:55 +00:00
|
|
|
func activate_validator(state: var BeaconState,
|
2019-01-29 04:15:00 +00:00
|
|
|
index: ValidatorIndex,
|
2019-01-16 12:20:44 +00:00
|
|
|
genesis: bool) =
|
2018-12-13 16:00:55 +00:00
|
|
|
## Activate the validator with the given ``index``.
|
|
|
|
let validator = addr state.validator_registry[index]
|
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
validator.activation_epoch = if genesis: GENESIS_EPOCH else: get_entry_exit_effect_epoch(get_current_epoch(state))
|
2018-12-13 16:00:55 +00:00
|
|
|
|
|
|
|
func initiate_validator_exit(state: var BeaconState,
|
2019-01-29 04:15:00 +00:00
|
|
|
index: ValidatorIndex) =
|
2018-12-13 16:00:55 +00:00
|
|
|
## Initiate exit for the validator with the given ``index``.
|
2019-01-17 21:01:55 +00:00
|
|
|
var validator = state.validator_registry[index]
|
|
|
|
validator.status_flags = validator.status_flags or INITIATED_EXIT
|
|
|
|
state.validator_registry[index] = validator
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-01-16 12:20:44 +00:00
|
|
|
func exit_validator*(state: var BeaconState,
|
2019-01-29 04:15:00 +00:00
|
|
|
index: ValidatorIndex) =
|
2018-12-13 16:00:55 +00:00
|
|
|
## Exit the validator with the given ``index``.
|
|
|
|
|
2019-01-17 21:01:55 +00:00
|
|
|
let validator = addr state.validator_registry[index]
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-01-17 21:01:55 +00:00
|
|
|
# The following updates only occur if not previous exited
|
2019-01-29 03:22:22 +00:00
|
|
|
if validator.exit_epoch <= get_entry_exit_effect_epoch(get_current_epoch(state)):
|
2018-12-13 16:00:55 +00:00
|
|
|
return
|
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
validator.exit_epoch = get_entry_exit_effect_epoch(get_current_epoch(state))
|
2018-12-13 16:00:55 +00:00
|
|
|
|
|
|
|
# The following updates only occur if not previous exited
|
|
|
|
state.validator_registry_exit_count += 1
|
|
|
|
validator.exit_count = state.validator_registry_exit_count
|
2019-01-16 13:39:34 +00:00
|
|
|
|
|
|
|
func process_penalties_and_exits(state: var BeaconState) =
|
2019-01-29 03:22:22 +00:00
|
|
|
let
|
|
|
|
current_epoch = get_current_epoch(state)
|
|
|
|
# The active validators
|
|
|
|
active_validator_indices = get_active_validator_indices(state.validator_registry, state.slot)
|
2019-01-16 13:39:34 +00:00
|
|
|
# The total effective balance of active validators
|
|
|
|
var total_balance : uint64 = 0
|
|
|
|
for i in active_validator_indices:
|
|
|
|
total_balance += get_effective_balance(state, i)
|
|
|
|
|
|
|
|
for index, validator in state.validator_registry:
|
2019-01-29 03:22:22 +00:00
|
|
|
if current_epoch == validator.penalized_epoch + LATEST_PENALIZED_EXIT_LENGTH div 2:
|
2019-01-16 13:39:34 +00:00
|
|
|
let
|
2019-01-29 03:22:22 +00:00
|
|
|
e = (current_epoch mod LATEST_PENALIZED_EXIT_LENGTH).int
|
2019-01-16 13:39:34 +00:00
|
|
|
total_at_start = state.latest_penalized_exit_balances[(e + 1) mod LATEST_PENALIZED_EXIT_LENGTH]
|
|
|
|
total_at_end = state.latest_penalized_exit_balances[e]
|
|
|
|
total_penalties = total_at_end - total_at_start
|
2019-01-29 04:15:00 +00:00
|
|
|
penalty = get_effective_balance(state, index.ValidatorIndex) * min(total_penalties * 3, total_balance) div total_balance
|
2019-01-16 13:39:34 +00:00
|
|
|
state.validator_balances[index] -= penalty
|
|
|
|
|
|
|
|
## 'state' is of type <var BeaconState> which cannot be captured as it
|
|
|
|
## would violate memory safety, when using nested function approach in
|
|
|
|
## spec directly. That said, the spec approach evidently is not meant,
|
|
|
|
## based on its abundant and pointless memory copies, for production.
|
2019-01-29 04:15:00 +00:00
|
|
|
var eligible_indices : seq[ValidatorIndex] = @[]
|
2019-01-16 13:39:34 +00:00
|
|
|
for i in 0 ..< len(state.validator_registry):
|
2019-01-29 04:15:00 +00:00
|
|
|
eligible_indices.add i.ValidatorIndex
|
2019-01-16 13:39:34 +00:00
|
|
|
|
|
|
|
## TODO figure out that memory safety issue, which would come up again when
|
|
|
|
## sorting, and then actually do withdrawals
|
|
|
|
|
2018-12-19 04:36:10 +00:00
|
|
|
func get_initial_beacon_state*(
|
|
|
|
initial_validator_deposits: openArray[Deposit],
|
|
|
|
genesis_time: uint64,
|
2019-01-18 00:14:22 +00:00
|
|
|
latest_eth1_data: Eth1Data,
|
2018-12-27 23:40:22 +00:00
|
|
|
flags: UpdateFlags = {}): BeaconState =
|
2018-11-29 05:23:40 +00:00
|
|
|
## 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.
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2018-11-29 05:23:40 +00:00
|
|
|
# Induct validators
|
2018-12-03 17:46:22 +00:00
|
|
|
# Not in spec: the system doesn't work unless there are at least EPOCH_LENGTH
|
2018-11-29 22:11:05 +00:00
|
|
|
# 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 :)
|
2018-12-13 16:00:55 +00:00
|
|
|
assert initial_validator_deposits.len >= EPOCH_LENGTH
|
2018-11-29 05:23:40 +00:00
|
|
|
|
2018-12-13 16:00:55 +00:00
|
|
|
var state = BeaconState(
|
|
|
|
# Misc
|
2019-01-16 10:21:06 +00:00
|
|
|
slot: GENESIS_SLOT,
|
2018-12-13 16:00:55 +00:00
|
|
|
genesis_time: genesis_time,
|
2019-01-29 03:22:22 +00:00
|
|
|
fork: Fork(
|
2019-01-29 04:15:00 +00:00
|
|
|
previous_version: GENESIS_FORK_VERSION,
|
|
|
|
current_version: GENESIS_FORK_VERSION,
|
2019-01-30 08:41:07 +00:00
|
|
|
epoch: GENESIS_EPOCH,
|
2018-12-13 16:00:55 +00:00
|
|
|
),
|
2018-12-03 21:41:24 +00:00
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
validator_registry_update_epoch: GENESIS_EPOCH,
|
2018-12-03 21:41:24 +00:00
|
|
|
validator_registry_exit_count: 0,
|
|
|
|
validator_registry_delta_chain_tip: ZERO_HASH,
|
|
|
|
|
2019-01-16 11:39:16 +00:00
|
|
|
# Randomness and committees
|
|
|
|
previous_epoch_start_shard: GENESIS_START_SHARD,
|
|
|
|
current_epoch_start_shard: GENESIS_START_SHARD,
|
2019-01-29 03:22:22 +00:00
|
|
|
previous_calculation_epoch: GENESIS_EPOCH,
|
|
|
|
current_calculation_epoch: GENESIS_EPOCH,
|
|
|
|
previous_epoch_seed: ZERO_HASH,
|
|
|
|
current_epoch_seed: ZERO_HASH,
|
2019-01-16 11:39:16 +00:00
|
|
|
|
2018-12-03 21:41:24 +00:00
|
|
|
# Finality
|
2019-01-29 03:22:22 +00:00
|
|
|
previous_justified_epoch: GENESIS_EPOCH,
|
|
|
|
justified_epoch: GENESIS_EPOCH,
|
2019-01-16 11:39:16 +00:00
|
|
|
justification_bitfield: 0,
|
2019-01-29 03:22:22 +00:00
|
|
|
finalized_epoch: GENESIS_EPOCH,
|
2018-12-03 21:41:24 +00:00
|
|
|
|
2019-01-16 11:39:16 +00:00
|
|
|
# Deposit root
|
2019-01-18 00:14:22 +00:00
|
|
|
latest_eth1_data: latest_eth1_data,
|
2018-11-29 05:23:40 +00:00
|
|
|
)
|
|
|
|
|
2019-01-16 11:39:16 +00:00
|
|
|
# Process initial deposits
|
2018-12-13 16:00:55 +00:00
|
|
|
for deposit in initial_validator_deposits:
|
2019-01-30 08:41:07 +00:00
|
|
|
process_deposit(
|
2018-12-13 16:00:55 +00:00
|
|
|
state,
|
2018-12-27 20:14:37 +00:00
|
|
|
deposit.deposit_data.deposit_input.pubkey,
|
2019-01-16 10:21:06 +00:00
|
|
|
deposit.deposit_data.amount,
|
2018-12-27 20:14:37 +00:00
|
|
|
deposit.deposit_data.deposit_input.proof_of_possession,
|
|
|
|
deposit.deposit_data.deposit_input.withdrawal_credentials,
|
2018-12-27 23:40:22 +00:00
|
|
|
deposit.deposit_data.deposit_input.randao_commitment,
|
2018-12-13 16:00:55 +00:00
|
|
|
)
|
2019-01-16 12:20:44 +00:00
|
|
|
|
|
|
|
# Process initial activations
|
2019-01-21 18:26:58 +00:00
|
|
|
for validator_index in 0 ..< state.validator_registry.len:
|
2019-01-29 04:15:00 +00:00
|
|
|
let vi = validator_index.ValidatorIndex
|
2019-01-30 08:41:07 +00:00
|
|
|
if get_effective_balance(state, vi) >= MAX_DEPOSIT_AMOUNT:
|
2019-01-21 18:26:58 +00:00
|
|
|
activate_validator(state, vi, true)
|
2018-12-13 16:00:55 +00:00
|
|
|
|
|
|
|
state
|
|
|
|
|
2018-12-11 21:53:18 +00:00
|
|
|
func get_block_root*(state: BeaconState,
|
2018-12-03 21:41:24 +00:00
|
|
|
slot: uint64): Eth2Digest =
|
2018-12-21 22:37:46 +00:00
|
|
|
doAssert state.slot <= slot + LATEST_BLOCK_ROOTS_LENGTH
|
2018-12-14 16:12:39 +00:00
|
|
|
doAssert slot < state.slot
|
2018-12-21 22:37:46 +00:00
|
|
|
state.latest_block_roots[slot mod LATEST_BLOCK_ROOTS_LENGTH]
|
2018-11-29 05:23:40 +00:00
|
|
|
|
2018-12-04 18:45:30 +00:00
|
|
|
func get_attestation_participants*(state: BeaconState,
|
2018-12-03 21:41:24 +00:00
|
|
|
attestation_data: AttestationData,
|
2019-01-29 04:15:00 +00:00
|
|
|
aggregation_bitfield: seq[byte]): seq[ValidatorIndex] =
|
2018-11-29 18:18:12 +00:00
|
|
|
## 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
|
2018-11-29 22:11:05 +00:00
|
|
|
# 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
|
2019-01-26 19:32:10 +00:00
|
|
|
|
|
|
|
# Find the committee in the list with the desired shard
|
|
|
|
let crosslink_committees = get_crosslink_committees_at_slot(state, attestation_data.slot)
|
|
|
|
|
|
|
|
# TODO investigate functional library / approach to help avoid loop bugs
|
|
|
|
assert any(
|
|
|
|
crosslink_committees,
|
2019-01-29 04:15:00 +00:00
|
|
|
func (x: tuple[a: seq[ValidatorIndex], b: uint64]): bool = x[1] == attestation_data.shard)
|
2019-01-26 19:32:10 +00:00
|
|
|
let crosslink_committee = mapIt(
|
|
|
|
filterIt(crosslink_committees, it.b == attestation_data.shard),
|
|
|
|
it.a)[0]
|
|
|
|
assert len(aggregation_bitfield) == (len(crosslink_committee) + 7) div 8
|
|
|
|
|
|
|
|
# Find the participating attesters in the committee
|
|
|
|
result = @[]
|
|
|
|
for i, validator_index in crosslink_committee:
|
|
|
|
let aggregation_bit = (aggregation_bitfield[i div 8] shr (7 - (i mod 8))) mod 2
|
|
|
|
if aggregation_bit == 1:
|
|
|
|
result.add(validator_index)
|
2018-12-04 18:45:30 +00:00
|
|
|
|
2018-12-11 17:55:45 +00:00
|
|
|
func process_ejections*(state: var BeaconState) =
|
|
|
|
## Iterate through the validator registry
|
|
|
|
## and eject active validators with balance below ``EJECTION_BALANCE``.
|
|
|
|
|
2019-01-17 20:09:07 +00:00
|
|
|
for index in get_active_validator_indices(state.validator_registry, state.slot):
|
2018-12-27 20:14:37 +00:00
|
|
|
if state.validator_balances[index] < EJECTION_BALANCE:
|
2019-01-17 21:01:55 +00:00
|
|
|
exit_validator(state, index)
|
2018-12-11 17:55:45 +00:00
|
|
|
|
|
|
|
func update_validator_registry*(state: var BeaconState) =
|
2018-12-27 20:14:37 +00:00
|
|
|
let
|
2019-01-29 03:22:22 +00:00
|
|
|
current_epoch = get_current_epoch(state)
|
|
|
|
next_epoch = current_epoch + 1
|
2018-12-27 20:14:37 +00:00
|
|
|
active_validator_indices =
|
2019-01-17 20:09:07 +00:00
|
|
|
get_active_validator_indices(state.validator_registry, state.slot)
|
2018-12-27 20:14:37 +00:00
|
|
|
# The total effective balance of active validators
|
|
|
|
total_balance = sum_effective_balances(state, active_validator_indices)
|
|
|
|
|
|
|
|
# The maximum balance churn in Gwei (for deposits and exits separately)
|
|
|
|
max_balance_churn = max(
|
2019-01-21 18:26:58 +00:00
|
|
|
MAX_DEPOSIT_AMOUNT,
|
2018-12-27 20:14:37 +00:00
|
|
|
total_balance div (2 * MAX_BALANCE_CHURN_QUOTIENT)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Activate validators within the allowable balance churn
|
|
|
|
var balance_churn = 0'u64
|
|
|
|
for index, validator in state.validator_registry:
|
2019-01-29 03:22:22 +00:00
|
|
|
if validator.activation_epoch > get_entry_exit_effect_epoch(current_epoch) and
|
2019-01-21 18:26:58 +00:00
|
|
|
state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
2018-12-27 20:14:37 +00:00
|
|
|
# Check the balance churn would be within the allowance
|
2019-01-29 04:15:00 +00:00
|
|
|
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
2018-12-27 20:14:37 +00:00
|
|
|
if balance_churn > max_balance_churn:
|
|
|
|
break
|
|
|
|
|
|
|
|
# Activate validator
|
2019-01-29 04:15:00 +00:00
|
|
|
activate_validator(state, index.ValidatorIndex, false)
|
2018-12-27 20:14:37 +00:00
|
|
|
|
|
|
|
# Exit validators within the allowable balance churn
|
|
|
|
balance_churn = 0
|
|
|
|
for index, validator in state.validator_registry:
|
2019-01-29 03:22:22 +00:00
|
|
|
if validator.exit_epoch > get_entry_exit_effect_epoch(current_epoch) and
|
2019-01-16 12:57:49 +00:00
|
|
|
((validator.status_flags and INITIATED_EXIT) == INITIATED_EXIT):
|
2018-12-27 20:14:37 +00:00
|
|
|
# Check the balance churn would be within the allowance
|
2019-01-29 04:15:00 +00:00
|
|
|
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
2018-12-27 20:14:37 +00:00
|
|
|
if balance_churn > max_balance_churn:
|
|
|
|
break
|
|
|
|
|
|
|
|
# Exit validator
|
2019-01-29 04:15:00 +00:00
|
|
|
exit_validator(state, index.ValidatorIndex)
|
2018-12-27 20:14:37 +00:00
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
state.validator_registry_update_epoch = current_epoch
|
|
|
|
|
2019-01-16 11:07:41 +00:00
|
|
|
# Perform additional updates
|
2019-01-29 03:22:22 +00:00
|
|
|
state.current_calculation_epoch = next_epoch
|
|
|
|
state.current_epoch_start_shard = (state.current_epoch_start_shard + get_current_epoch_committee_count(state)) mod SHARD_COUNT
|
|
|
|
state.current_epoch_seed = generate_seed(state, state.current_calculation_epoch)
|
2019-01-16 11:07:41 +00:00
|
|
|
|
|
|
|
# TODO "If a validator registry update does not happen do the following: ..."
|
|
|
|
|
2019-01-16 14:50:54 +00:00
|
|
|
process_penalties_and_exits(state)
|
2019-01-16 11:07:41 +00:00
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
func get_epoch_start_slot*(epoch: EpochNumber): SlotNumber =
|
|
|
|
epoch * EPOCH_LENGTH
|
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
proc checkAttestation*(
|
|
|
|
state: BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
2018-12-11 17:55:45 +00:00
|
|
|
## Check that an attestation follows the rules of being included in the state
|
2018-12-27 20:14:37 +00:00
|
|
|
## at the current slot. When acting as a proposer, the same rules need to
|
|
|
|
## be followed!
|
2018-12-11 17:55:45 +00:00
|
|
|
##
|
|
|
|
## https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#attestations-1
|
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
if not (attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot):
|
2018-12-13 16:00:55 +00:00
|
|
|
warn("Attestation too new",
|
|
|
|
attestation_slot = attestation.data.slot, state_slot = state.slot)
|
2018-12-11 17:55:45 +00:00
|
|
|
return
|
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
if not (attestation.data.slot + EPOCH_LENGTH >= state.slot):
|
2018-12-13 16:00:55 +00:00
|
|
|
warn("Attestation too old",
|
|
|
|
attestation_slot = attestation.data.slot, state_slot = state.slot)
|
2018-12-11 17:55:45 +00:00
|
|
|
return
|
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
let expected_justified_epoch =
|
|
|
|
if attestation.data.slot >= get_epoch_start_slot(get_current_epoch(state)):
|
|
|
|
state.justified_epoch
|
2018-12-11 17:55:45 +00:00
|
|
|
else:
|
2019-01-29 03:22:22 +00:00
|
|
|
state.previous_justified_epoch
|
2018-12-11 17:55:45 +00:00
|
|
|
|
2019-01-29 03:22:22 +00:00
|
|
|
if not (attestation.data.justified_epoch == expected_justified_epoch):
|
|
|
|
warn("Unexpected justified epoch",
|
|
|
|
attestation_justified_epoch = attestation.data.justified_epoch,
|
|
|
|
expected_justified_epoch)
|
2018-12-11 17:55:45 +00:00
|
|
|
return
|
|
|
|
|
2018-12-11 21:53:18 +00:00
|
|
|
let expected_justified_block_root =
|
2019-01-29 03:22:22 +00:00
|
|
|
get_block_root(state, get_epoch_start_slot(attestation.data.justified_epoch))
|
2018-12-27 23:40:22 +00:00
|
|
|
if not (attestation.data.justified_block_root == expected_justified_block_root):
|
2018-12-13 16:00:55 +00:00
|
|
|
warn("Unexpected justified block root",
|
|
|
|
attestation_justified_block_root = attestation.data.justified_block_root,
|
|
|
|
expected_justified_block_root)
|
2018-12-11 17:55:45 +00:00
|
|
|
return
|
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
if not (state.latest_crosslinks[attestation.data.shard].shard_block_root in [
|
2018-12-11 21:53:18 +00:00
|
|
|
attestation.data.latest_crosslink_root,
|
2018-12-27 23:40:22 +00:00
|
|
|
attestation.data.shard_block_root]):
|
2018-12-13 16:00:55 +00:00
|
|
|
warn("Unexpected crosslink shard_block_root")
|
2018-12-11 17:55:45 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
let
|
|
|
|
participants = get_attestation_participants(
|
|
|
|
state, attestation.data, attestation.participation_bitfield)
|
2018-12-27 23:40:22 +00:00
|
|
|
group_public_key = bls_aggregate_pubkeys(
|
|
|
|
participants.mapIt(state.validator_registry[it].pubkey))
|
|
|
|
|
|
|
|
if skipValidation notin flags:
|
|
|
|
# Verify that aggregate_signature verifies using the group pubkey.
|
|
|
|
let msg = hash_tree_root_final(attestation.data)
|
|
|
|
|
|
|
|
if not bls_verify(
|
|
|
|
group_public_key, @(msg.data) & @[0'u8], attestation.aggregate_signature,
|
2019-02-05 16:13:29 +00:00
|
|
|
0, # TODO: get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION)
|
2018-12-27 23:40:22 +00:00
|
|
|
):
|
|
|
|
warn("Invalid attestation group signature")
|
|
|
|
return
|
2018-12-11 17:55:45 +00:00
|
|
|
|
|
|
|
# To be removed in Phase1:
|
2018-12-11 21:53:18 +00:00
|
|
|
if attestation.data.shard_block_root != ZERO_HASH:
|
2018-12-13 16:00:55 +00:00
|
|
|
warn("Invalid shard block root")
|
2018-12-11 17:55:45 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
true
|