Complete scan through v0.3.0 spec (#141)
* Complete scan through v0.3.0 spec; remaining known discreptancy is in bls_verify_multiple * switch remaining slot-misuses of get_active_validator_indices to epochs * spec workaround * finish first 0.3.0 pass by getting slow, naive version of bls_verify_multiple running
This commit is contained in:
parent
125231d321
commit
1cfea240ed
|
@ -295,7 +295,9 @@ func process_ejections*(state: var BeaconState) =
|
|||
## Iterate through the validator registry
|
||||
## and eject active validators with balance below ``EJECTION_BALANCE``.
|
||||
|
||||
for index in get_active_validator_indices(state.validator_registry, state.slot):
|
||||
for index in get_active_validator_indices(
|
||||
# TODO v0.3.0 spec bug, has this as current_epoch(state)
|
||||
state.validator_registry, get_current_epoch(state)):
|
||||
if state.validator_balances[index] < EJECTION_BALANCE:
|
||||
exit_validator(state, index)
|
||||
|
||||
|
@ -304,12 +306,15 @@ func get_total_balance*(state: BeaconState, validators: seq[ValidatorIndex]): Gw
|
|||
# Return the combined effective balance of an array of validators.
|
||||
foldl(validators, a + get_effective_balance(state, b), 0'u64)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||
func update_validator_registry*(state: var BeaconState) =
|
||||
## Update validator registry.
|
||||
## Note that this function mutates ``state``.
|
||||
let
|
||||
current_epoch = get_current_epoch(state)
|
||||
next_epoch = current_epoch + 1
|
||||
# The active validators
|
||||
active_validator_indices =
|
||||
get_active_validator_indices(state.validator_registry, state.slot)
|
||||
get_active_validator_indices(state.validator_registry, current_epoch)
|
||||
# The total effective balance of active validators
|
||||
total_balance = get_total_balance(state, active_validator_indices)
|
||||
|
||||
|
@ -347,13 +352,6 @@ func update_validator_registry*(state: var BeaconState) =
|
|||
|
||||
state.validator_registry_update_epoch = current_epoch
|
||||
|
||||
# Perform additional updates
|
||||
state.current_shuffling_epoch = next_epoch
|
||||
state.current_shuffling_start_shard = (state.current_shuffling_start_shard + get_current_epoch_committee_count(state)) mod SHARD_COUNT
|
||||
state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch)
|
||||
|
||||
# TODO "If a validator registry update does not happen do the following: ..."
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestations-1
|
||||
proc checkAttestation*(
|
||||
state: BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Copyright (c) 2018-2019 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).
|
||||
|
@ -45,6 +45,7 @@
|
|||
|
||||
|
||||
import
|
||||
sequtils,
|
||||
hashes,
|
||||
blscurve, json_serialization
|
||||
|
||||
|
@ -84,14 +85,22 @@ func bls_verify*(
|
|||
# name from spec!
|
||||
sig.verify(msg, domain, pubkey)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify_multiple
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/bls_signature.md#bls_verify_multiple
|
||||
func bls_verify_multiple*(
|
||||
pubkeys: seq[ValidatorPubKey], messages: seq[array[0..31, byte]],
|
||||
pubkeys: seq[ValidatorPubKey], message_hashes: seq[array[0..31, byte]],
|
||||
sig: ValidatorSig, domain: uint64): bool =
|
||||
let L = len(pubkeys)
|
||||
assert L == len(messages)
|
||||
doAssert L == len(message_hashes)
|
||||
|
||||
# TODO optimize using multiPairing
|
||||
for pubkey_message_hash in zip(pubkeys, message_hashes):
|
||||
let (pubkey, message_hash) = pubkey_message_hash
|
||||
# TODO spec doesn't say to handle this specially, but it's silly to
|
||||
# validate without any actual public keys.
|
||||
if pubkey != ValidatorPubKey() and
|
||||
not sig.verify(message_hash, domain, pubkey):
|
||||
return false
|
||||
|
||||
# TODO calculate product of ate pairings; check how sig.verify works
|
||||
true
|
||||
|
||||
func bls_sign*(key: ValidatorPrivKey, msg: openarray[byte],
|
||||
|
|
|
@ -420,10 +420,10 @@ type
|
|||
## Epoch when validator exited
|
||||
|
||||
withdrawable_epoch*: uint64 ##\
|
||||
## Epoch when validator withdrew
|
||||
## Epoch when validator is eligible to withdraw
|
||||
|
||||
slashed_epoch*: uint64 ##\
|
||||
## Epoch when validator penalized
|
||||
## Epoch when validator slashed
|
||||
|
||||
status_flags*: uint64
|
||||
|
||||
|
|
|
@ -711,9 +711,6 @@ func processEpoch(state: var BeaconState) =
|
|||
get_total_balance(
|
||||
statePtr[], attesting_validator_indices(crosslink_committee))
|
||||
|
||||
func total_balance_sac(crosslink_committee: CrosslinkCommittee): uint64 =
|
||||
get_total_balance(statePtr[], crosslink_committee.committee)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#eth1-data-1
|
||||
block:
|
||||
if next_epoch mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0:
|
||||
|
@ -791,11 +788,12 @@ func processEpoch(state: var BeaconState) =
|
|||
return a.inclusion_slot - a.data.slot
|
||||
doAssert false
|
||||
|
||||
let active_validator_indices =
|
||||
get_active_validator_indices(state.validator_registry, state.slot)
|
||||
|
||||
block: # Justification and finalization
|
||||
let epochs_since_finality = next_epoch - state.finalized_epoch
|
||||
let
|
||||
active_validator_indices =
|
||||
get_active_validator_indices(
|
||||
state.validator_registry, slot_to_epoch(state.slot))
|
||||
epochs_since_finality = next_epoch - state.finalized_epoch
|
||||
|
||||
proc update_balance(attesters: openArray[ValidatorIndex], attesting_balance: uint64) =
|
||||
# TODO Spec - add helper?
|
||||
|
@ -810,6 +808,7 @@ func processEpoch(state: var BeaconState) =
|
|||
statePtr.validator_balances[v] -= base_reward(statePtr[], v)
|
||||
|
||||
if epochs_since_finality <= 4'u64:
|
||||
# Case 1: epochs_since_finality <= 4
|
||||
# Expected FFG source
|
||||
update_balance(
|
||||
previous_epoch_attester_indices,
|
||||
|
@ -832,6 +831,7 @@ func processEpoch(state: var BeaconState) =
|
|||
MIN_ATTESTATION_INCLUSION_DELAY div inclusion_distance(state, v)
|
||||
|
||||
else:
|
||||
# Case 2: epochs_since_finality > 4
|
||||
for index in active_validator_indices:
|
||||
# TODO underflows?
|
||||
if index notin previous_epoch_attester_indices:
|
||||
|
@ -841,29 +841,36 @@ func processEpoch(state: var BeaconState) =
|
|||
state.validator_balances[index] -=
|
||||
inactivity_penalty(state, index, epochs_since_finality)
|
||||
if index notin previous_epoch_head_attester_indices:
|
||||
state.validator_balances[index] -= base_reward(state, index)
|
||||
if state.validator_registry[index].slashed_epoch <= current_epoch:
|
||||
state.validator_balances[index] -=
|
||||
inactivity_penalty(state, index, epochs_since_finality)
|
||||
2'u64 * inactivity_penalty(
|
||||
state, index, epochs_since_finality) + base_reward(state, index)
|
||||
if index in previous_epoch_attester_indices:
|
||||
state.validator_balances[index] -=
|
||||
base_reward(state, index) -
|
||||
base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
|
||||
inclusion_distance(state, index)
|
||||
|
||||
block: # Attestation inclusion
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestation-inclusion
|
||||
block:
|
||||
for v in previous_epoch_attester_indices:
|
||||
let proposer_index =
|
||||
get_beacon_proposer_index(state, inclusion_slot(state, v))
|
||||
state.validator_balances[proposer_index] +=
|
||||
base_reward(state, v) div ATTESTATION_INCLUSION_REWARD_QUOTIENT
|
||||
|
||||
block: # Crosslinks
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks-1
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#crosslinks-1
|
||||
block:
|
||||
for slot in get_epoch_start_slot(previous_epoch) ..< get_epoch_start_slot(current_epoch):
|
||||
let crosslink_committees_at_slot = get_crosslink_committees_at_slot(state, slot)
|
||||
for crosslink_committee in crosslink_committees_at_slot:
|
||||
# TODO https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks-1
|
||||
# but this is a best guess based on reasonableness of what "index" is
|
||||
for index in crosslink_committee.committee:
|
||||
if index in attesting_validators(crosslink_committee):
|
||||
state.validator_balances[index.int] +=
|
||||
base_reward(state, index) *
|
||||
total_attesting_balance(crosslink_committee) div
|
||||
total_balance_sac(crosslink_committee)
|
||||
get_total_balance(state, crosslink_committee.committee)
|
||||
else:
|
||||
# TODO underflows?
|
||||
state.validator_balances[index] -= base_reward(state, index)
|
||||
|
@ -877,13 +884,17 @@ func processEpoch(state: var BeaconState) =
|
|||
state.previous_shuffling_start_shard = state.current_shuffling_start_shard
|
||||
state.previous_shuffling_seed = state.current_shuffling_seed
|
||||
|
||||
# TODO verify this shard list
|
||||
if state.finalized_epoch > state.validator_registry_update_epoch and
|
||||
allIt(
|
||||
0 ..< get_current_epoch_committee_count(state).int * SLOTS_PER_EPOCH,
|
||||
state.latest_crosslinks[(state.current_shuffling_start_shard + it.uint64) mod SHARD_COUNT].epoch > state.validator_registry_update_epoch):
|
||||
0 ..< get_current_epoch_committee_count(state).int,
|
||||
state.latest_crosslinks[
|
||||
(state.current_shuffling_start_shard + it.uint64) mod
|
||||
SHARD_COUNT].epoch > state.validator_registry_update_epoch):
|
||||
|
||||
# update the validator registry and associated fields by running
|
||||
update_validator_registry(state)
|
||||
|
||||
# and perform the following updates
|
||||
state.current_shuffling_epoch = next_epoch
|
||||
state.current_shuffling_start_shard =
|
||||
(state.current_shuffling_start_shard +
|
||||
|
@ -892,8 +903,10 @@ func processEpoch(state: var BeaconState) =
|
|||
state, state.current_shuffling_epoch)
|
||||
else:
|
||||
# If a validator registry change does NOT happen
|
||||
let epochs_since_last_registry_change = current_epoch - state.validator_registry_update_epoch
|
||||
if is_power_of_2(epochs_since_last_registry_change):
|
||||
let epochs_since_last_registry_update =
|
||||
current_epoch - state.validator_registry_update_epoch
|
||||
if epochs_since_last_registry_update > 1'u64 and
|
||||
is_power_of_2(epochs_since_last_registry_update):
|
||||
state.current_shuffling_epoch = next_epoch
|
||||
state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch)
|
||||
# /Note/ that state.current_shuffling_start_shard is left unchanged
|
||||
|
|
|
@ -187,12 +187,15 @@ proc makeAttestation*(
|
|||
bitSet(aggregation_bitfield, sac_index)
|
||||
|
||||
let
|
||||
msg = hash_tree_root_final(data)
|
||||
# TODO: domain
|
||||
domain = 0'u64
|
||||
msg = hash_tree_root_final(AttestationDataAndCustodyBit(data: data, custody_bit: false))
|
||||
sig =
|
||||
if skipValidation notin flags:
|
||||
bls_sign(hackPrivKey(validator), @(msg.data) & @[0'u8], domain)
|
||||
bls_sign(
|
||||
hackPrivKey(validator), @(msg.data),
|
||||
get_domain(
|
||||
state.fork,
|
||||
slot_to_epoch(state.slot),
|
||||
DOMAIN_ATTESTATION))
|
||||
else:
|
||||
ValidatorSig()
|
||||
|
||||
|
|
Loading…
Reference in New Issue