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:
Dustin Brody 2019-02-28 21:24:43 +00:00 committed by Jacek Sieka
parent 125231d321
commit 1cfea240ed
5 changed files with 63 additions and 40 deletions

View File

@ -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 =

View File

@ -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],

View File

@ -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

View File

@ -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

View File

@ -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()