spec version 0.4.0 update: shard_block_root -> crosslink_data_root; switch from validator.slashed_epoch -> validator.slashed approach; a couple assert -> doAssert; note fix for underflow-prone spec changes in checkAttestation; GENESIS_SLOT change from 2^63 to 2^32; refactor Proposer and ProposalSlashing structure; add signed_root; remove duplicate slashValidator (#159)
* spec version 0.4.0 update: shard_block_root -> crosslink_data_root; switch from validator.slashed_epoch -> validator.slashed approach; a couple assert -> doAssert; note fix for underflow-prone spec changes in checkAttestation; GENESIS_SLOT change from 2^63 to 2^32; refactor Proposer and ProposalSlashing structure; add signed_root; remove duplicate slashValidator * re-apply shard_block_root -> crosslink_data_root * remove incorrect humaneSlotNum * add (run-time only, alas) sanity check on signed_root
This commit is contained in:
parent
6bcefc0e42
commit
1afdcda62d
|
@ -274,7 +274,7 @@ proc makeAttestation(node: BeaconNode,
|
|||
shard: shard,
|
||||
beacon_block_root: node.state.blck.root,
|
||||
epoch_boundary_root: Eth2Digest(), # TODO
|
||||
shard_block_root: Eth2Digest(), # TODO
|
||||
crosslink_data_root: Eth2Digest(), # TODO
|
||||
latest_crosslink: state.latest_crosslinks[shard],
|
||||
justified_epoch: state.justified_epoch,
|
||||
justified_block_root: justifiedBlockRoot)
|
||||
|
|
|
@ -16,43 +16,25 @@ func get_effective_balance*(state: BeaconState, index: ValidatorIndex): uint64 =
|
|||
## validator with the given ``index``.
|
||||
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validate_proof_of_possession
|
||||
func validate_proof_of_possession(state: BeaconState,
|
||||
pubkey: ValidatorPubKey,
|
||||
proof_of_possession: ValidatorSig,
|
||||
withdrawal_credentials: Eth2Digest): bool =
|
||||
let proof_of_possession_data = DepositInput(
|
||||
pubkey: pubkey,
|
||||
withdrawal_credentials: withdrawal_credentials,
|
||||
proof_of_possession: ValidatorSig(),
|
||||
)
|
||||
|
||||
bls_verify(
|
||||
pubkey,
|
||||
hash_tree_root_final(proof_of_possession_data).data,
|
||||
proof_of_possession,
|
||||
get_domain(
|
||||
state.fork,
|
||||
get_current_epoch(state),
|
||||
DOMAIN_DEPOSIT,
|
||||
)
|
||||
)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#process_deposit
|
||||
func process_deposit(state: var BeaconState,
|
||||
pubkey: ValidatorPubKey,
|
||||
amount: Gwei,
|
||||
proof_of_possession: ValidatorSig,
|
||||
withdrawal_credentials: Eth2Digest) =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#process_deposit
|
||||
func process_deposit(state: var BeaconState, deposit: Deposit) =
|
||||
## Process a deposit from Ethereum 1.0.
|
||||
## Note that this function mutates ``state``.
|
||||
|
||||
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)
|
||||
let deposit_input = deposit.deposit_data.deposit_input
|
||||
|
||||
let validator_pubkeys = state.validator_registry.mapIt(it.pubkey)
|
||||
## if not validate_proof_of_possession(
|
||||
## state, pubkey, proof_of_possession, withdrawal_credentials):
|
||||
## return
|
||||
## TODO re-enable (but it wasn't running to begin with, and
|
||||
## PoP isn't really a phase 0 concern, so this isn't meaningful
|
||||
## regardless.
|
||||
|
||||
let
|
||||
validator_pubkeys = state.validator_registry.mapIt(it.pubkey)
|
||||
pubkey = deposit_input.pubkey
|
||||
amount = deposit.deposit_data.amount
|
||||
withdrawal_credentials = deposit_input.withdrawal_credentials
|
||||
|
||||
if pubkey notin validator_pubkeys:
|
||||
# Add new validator
|
||||
|
@ -62,8 +44,8 @@ func process_deposit(state: var BeaconState,
|
|||
activation_epoch: FAR_FUTURE_EPOCH,
|
||||
exit_epoch: FAR_FUTURE_EPOCH,
|
||||
withdrawable_epoch: FAR_FUTURE_EPOCH,
|
||||
slashed_epoch: FAR_FUTURE_EPOCH,
|
||||
status_flags: 0,
|
||||
initiated_exit: false,
|
||||
slashed: false,
|
||||
)
|
||||
|
||||
## Note: In phase 2 registry indices that have been withdrawn for a long
|
||||
|
@ -74,7 +56,7 @@ func process_deposit(state: var BeaconState,
|
|||
# Increase balance by deposit amount
|
||||
let index = validator_pubkeys.find(pubkey)
|
||||
let validator = addr state.validator_registry[index]
|
||||
assert state.validator_registry[index].withdrawal_credentials ==
|
||||
doAssert state.validator_registry[index].withdrawal_credentials ==
|
||||
withdrawal_credentials
|
||||
|
||||
state.validator_balances[index] += amount
|
||||
|
@ -99,13 +81,13 @@ func activate_validator(state: var BeaconState,
|
|||
else:
|
||||
get_entry_exit_effect_epoch(get_current_epoch(state))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#initiate_validator_exit
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#initiate_validator_exit
|
||||
func initiate_validator_exit*(state: var BeaconState,
|
||||
index: ValidatorIndex) =
|
||||
## Initiate exit for the validator with the given ``index``.
|
||||
## Note that this function mutates ``state``.
|
||||
var validator = addr state.validator_registry[index]
|
||||
validator.status_flags = validator.status_flags or INITIATED_EXIT
|
||||
validator.initiated_exit = true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#exit_validator
|
||||
func exit_validator*(state: var BeaconState,
|
||||
|
@ -125,6 +107,7 @@ func reduce_balance*(balance: var uint64, amount: uint64) =
|
|||
# Not in spec, but useful to avoid underflow.
|
||||
balance -= min(amount, balance)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slash_validator
|
||||
func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
|
||||
## Slash the validator with index ``index``.
|
||||
## Note that this function mutates ``state``.
|
||||
|
@ -143,13 +126,14 @@ func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
|
|||
whistleblower_reward = get_effective_balance(state, index) div
|
||||
WHISTLEBLOWER_REWARD_QUOTIENT
|
||||
|
||||
## TODO here and elsewhere, if reduce_balance can't reduce balance by full
|
||||
## whistleblower_reward (to prevent underflow) should increase be full? It
|
||||
## seems wrong for the amounts to differ.
|
||||
state.validator_balances[whistleblower_index] += whistleblower_reward
|
||||
reduce_balance(state.validator_balances[index], whistleblower_reward)
|
||||
validator.slashed_epoch = get_current_epoch(state)
|
||||
|
||||
# Spec bug in v0.3.0, fixed since: it has LATEST_PENALIZED_EXIT_LENGTH
|
||||
validator.withdrawable_epoch = get_current_epoch(state) +
|
||||
LATEST_SLASHED_EXIT_LENGTH
|
||||
validator.slashed = true
|
||||
validator.withdrawable_epoch =
|
||||
get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
|
||||
|
||||
func update_shuffling_cache*(state: var BeaconState) =
|
||||
let
|
||||
|
@ -171,9 +155,9 @@ func update_shuffling_cache*(state: var BeaconState) =
|
|||
state.shuffling_cache.shuffling_1 = shuffling_seq
|
||||
state.shuffling_cache.index = 1 - state.shuffling_cache.index
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#on-genesis
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#on-genesis
|
||||
func get_genesis_beacon_state*(
|
||||
initial_validator_deposits: openArray[Deposit],
|
||||
genesis_validator_deposits: openArray[Deposit],
|
||||
genesis_time: uint64,
|
||||
latest_eth1_data: Eth1Data,
|
||||
flags: UpdateFlags = {}): BeaconState =
|
||||
|
@ -191,7 +175,7 @@ func get_genesis_beacon_state*(
|
|||
# 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_deposits.len >= SLOTS_PER_EPOCH
|
||||
doAssert genesis_validator_deposits.len >= SLOTS_PER_EPOCH
|
||||
|
||||
var state = BeaconState(
|
||||
# Misc
|
||||
|
@ -234,19 +218,13 @@ func get_genesis_beacon_state*(
|
|||
|
||||
for i in 0 ..< SHARD_COUNT:
|
||||
state.latest_crosslinks[i] = Crosslink(
|
||||
epoch: GENESIS_EPOCH, shard_block_root: ZERO_HASH)
|
||||
epoch: GENESIS_EPOCH, crosslink_data_root: ZERO_HASH)
|
||||
|
||||
# Process initial deposits
|
||||
for deposit in initial_validator_deposits:
|
||||
process_deposit(
|
||||
state,
|
||||
deposit.deposit_data.deposit_input.pubkey,
|
||||
deposit.deposit_data.amount,
|
||||
deposit.deposit_data.deposit_input.proof_of_possession,
|
||||
deposit.deposit_data.deposit_input.withdrawal_credentials,
|
||||
)
|
||||
# Process genesis deposits
|
||||
for deposit in genesis_validator_deposits:
|
||||
process_deposit(state, deposit)
|
||||
|
||||
# Process initial activations
|
||||
# Process genesis activations
|
||||
for validator_index in 0 ..< state.validator_registry.len:
|
||||
let vi = validator_index.ValidatorIndex
|
||||
if get_effective_balance(state, vi) >= MAX_DEPOSIT_AMOUNT:
|
||||
|
@ -258,6 +236,7 @@ func get_genesis_beacon_state*(
|
|||
state.latest_active_index_roots[index] = genesis_active_index_root
|
||||
state.current_shuffling_seed = generate_seed(state, GENESIS_EPOCH)
|
||||
|
||||
# Not in spec.
|
||||
update_shuffling_cache(state)
|
||||
|
||||
state
|
||||
|
@ -317,15 +296,13 @@ func get_attestation_participants*(state: BeaconState,
|
|||
if aggregation_bit == 1:
|
||||
result.add(validator_index)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#ejections
|
||||
func process_ejections*(state: var BeaconState, active_validator_indices: auto) =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#ejections
|
||||
func process_ejections*(state: var BeaconState) =
|
||||
## Iterate through the validator registry and eject active validators with
|
||||
## balance below ``EJECTION_BALANCE``
|
||||
##
|
||||
## `active_validator_indices` was already computed in `processEpoch`. Reuse.
|
||||
## Spec recomputes. This is called before validator reshuffling, so use that
|
||||
## cached version from beginning of `processEpoch`.
|
||||
for index in active_validator_indices:
|
||||
for index in get_active_validator_indices(
|
||||
# Spec bug in 0.4.0: is just current_epoch(state)
|
||||
state.validator_registry, get_current_epoch(state)):
|
||||
if state.validator_balances[index] < EJECTION_BALANCE:
|
||||
exit_validator(state, index)
|
||||
|
||||
|
@ -334,7 +311,7 @@ func get_total_balance*(state: BeaconState, validators: auto): Gwei =
|
|||
# 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
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.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``.
|
||||
|
@ -355,7 +332,7 @@ func update_validator_registry*(state: var BeaconState) =
|
|||
# Activate validators within the allowable balance churn
|
||||
var balance_churn = 0'u64
|
||||
for index, validator in state.validator_registry:
|
||||
if validator.activation_epoch > get_entry_exit_effect_epoch(current_epoch) and
|
||||
if validator.activation_epoch == FAR_FUTURE_EPOCH and
|
||||
state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
||||
# Check the balance churn would be within the allowance
|
||||
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
||||
|
@ -368,8 +345,8 @@ func update_validator_registry*(state: var BeaconState) =
|
|||
# Exit validators within the allowable balance churn
|
||||
balance_churn = 0
|
||||
for index, validator in state.validator_registry:
|
||||
if validator.exit_epoch > get_entry_exit_effect_epoch(current_epoch) and
|
||||
((validator.status_flags and INITIATED_EXIT) == INITIATED_EXIT):
|
||||
if validator.activation_epoch == FAR_FUTURE_EPOCH and
|
||||
validator.initiated_exit:
|
||||
# Check the balance churn would be within the allowance
|
||||
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
||||
if balance_churn > max_balance_churn:
|
||||
|
@ -380,25 +357,26 @@ func update_validator_registry*(state: var BeaconState) =
|
|||
|
||||
state.validator_registry_update_epoch = current_epoch
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestations-1
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestations-1
|
||||
proc checkAttestation*(
|
||||
state: BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
||||
## Check that an attestation follows the rules of being included in the state
|
||||
## at the current slot. When acting as a proposer, the same rules need to
|
||||
## be followed!
|
||||
|
||||
# Can't underflow, because GENESIS_SLOT > MIN_ATTESTATION_INCLUSION_DELAY
|
||||
doAssert GENESIS_SLOT > MIN_ATTESTATION_INCLUSION_DELAY
|
||||
if not (attestation.data.slot >= GENESIS_SLOT):
|
||||
warn("Attestation predates genesis slot",
|
||||
attestation_slot = attestation.data.slot,
|
||||
state_slot = humaneSlotNum(state.slot))
|
||||
return
|
||||
|
||||
if not (attestation.data.slot <= state.slot - MIN_ATTESTATION_INCLUSION_DELAY):
|
||||
if not (attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot):
|
||||
warn("Attestation too new",
|
||||
attestation_slot = humaneSlotNum(attestation.data.slot),
|
||||
state_slot = humaneSlotNum(state.slot))
|
||||
return
|
||||
|
||||
# Can't underflow, because GENESIS_SLOT > MIN_ATTESTATION_INCLUSION_DELAY
|
||||
if not (state.slot - MIN_ATTESTATION_INCLUSION_DELAY <
|
||||
attestation.data.slot + SLOTS_PER_EPOCH):
|
||||
if not (state.slot < attestation.data.slot + SLOTS_PER_EPOCH):
|
||||
warn("Attestation too old",
|
||||
attestation_slot = humaneSlotNum(attestation.data.slot),
|
||||
state_slot = humaneSlotNum(state.slot))
|
||||
|
@ -428,14 +406,14 @@ proc checkAttestation*(
|
|||
if not (state.latest_crosslinks[attestation.data.shard] in [
|
||||
attestation.data.latest_crosslink,
|
||||
Crosslink(
|
||||
shard_block_root: attestation.data.shard_block_root,
|
||||
crosslink_data_root: attestation.data.crosslink_data_root,
|
||||
epoch: slot_to_epoch(attestation.data.slot))]):
|
||||
warn("Unexpected crosslink shard",
|
||||
state_latest_crosslinks_attestation_data_shard =
|
||||
state.latest_crosslinks[attestation.data.shard],
|
||||
attestation_data_latest_crosslink = attestation.data.latest_crosslink,
|
||||
epoch = humaneEpochNum(slot_to_epoch(attestation.data.slot)),
|
||||
shard_block_root = attestation.data.shard_block_root)
|
||||
crosslink_data_root = attestation.data.crosslink_data_root)
|
||||
return
|
||||
|
||||
assert allIt(attestation.custody_bitfield, it == 0) #TO BE REMOVED IN PHASE 1
|
||||
|
@ -478,9 +456,6 @@ proc checkAttestation*(
|
|||
custody_bit_1_participants: seq[ValidatorIndex] = @[]
|
||||
custody_bit_0_participants = participants
|
||||
|
||||
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.
|
||||
assert bls_verify_multiple(
|
||||
|
@ -502,8 +477,8 @@ proc checkAttestation*(
|
|||
)
|
||||
|
||||
# To be removed in Phase1:
|
||||
if attestation.data.shard_block_root != ZERO_HASH:
|
||||
warn("Invalid shard block root")
|
||||
if attestation.data.crosslink_data_root != ZERO_HASH:
|
||||
warn("Invalid crosslink data root")
|
||||
return
|
||||
|
||||
true
|
||||
|
@ -517,4 +492,4 @@ func prepare_validator_for_withdrawal*(state: var BeaconState, index: ValidatorI
|
|||
|
||||
# Bug in 0.3.0 spec; constant got renamed. Use 0.3.0 name.
|
||||
validator.withdrawable_epoch = get_current_epoch(state) +
|
||||
MIN_VALIDATOR_WITHDRAWAL_DELAY
|
||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
|
|
|
@ -40,12 +40,12 @@ import
|
|||
# TODO Many of these constants should go into a config object that can be used
|
||||
# to run.. well.. a chain with different constants!
|
||||
const
|
||||
SPEC_VERSION* = "0.3.0" ## \
|
||||
SPEC_VERSION* = "0.4.0" ## \
|
||||
## Spec version we're aiming to be compatible with, right now
|
||||
## TODO: improve this scheme once we can negotiate versions in protocol
|
||||
|
||||
# Misc
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#misc
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#misc
|
||||
SHARD_COUNT* {.intdefine.} = 1024 ##\
|
||||
## Number of shards supported by the network - validators will jump around
|
||||
## between these shards and provide attestations to their state.
|
||||
|
@ -71,18 +71,16 @@ const
|
|||
MAX_INDICES_PER_SLASHABLE_VOTE* = 2^12 ##\
|
||||
## votes
|
||||
|
||||
MAX_WITHDRAWALS_PER_EPOCH* = 4 # withdrawals
|
||||
|
||||
MAX_EXIT_DEQUEUES_PER_EPOCH* = 4
|
||||
|
||||
SHUFFLE_ROUND_COUNT* = 90
|
||||
|
||||
# Deposit contract
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#deposit-contract
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#deposit-contract
|
||||
DEPOSIT_CONTRACT_TREE_DEPTH* = 2^5
|
||||
|
||||
# Gwei values
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#gwei-values
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#gwei-values
|
||||
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 ##\
|
||||
## Minimum amounth of ETH that can be deposited in one call - deposits can
|
||||
## be used either to top up an existing validator or commit to a new one
|
||||
|
@ -103,9 +101,9 @@ const
|
|||
## Compile with -d:SLOTS_PER_EPOCH=4 for shorter epochs
|
||||
|
||||
# Initial values
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#initial-values
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#initial-values
|
||||
GENESIS_FORK_VERSION* = 0'u64
|
||||
GENESIS_SLOT* = 2'u64^63
|
||||
GENESIS_SLOT* = 2'u64^32
|
||||
GENESIS_EPOCH* = GENESIS_SLOT div SLOTS_PER_EPOCH # slot_to_epoch(GENESIS_SLOT)
|
||||
GENESIS_START_SHARD* = 0'u64
|
||||
FAR_FUTURE_EPOCH* = not 0'u64 # 2^64 - 1 in spec
|
||||
|
@ -114,7 +112,7 @@ const
|
|||
BLS_WITHDRAWAL_PREFIX_BYTE* = 0'u8
|
||||
|
||||
# Time parameters
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#time-parameters
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#time-parameters
|
||||
SECONDS_PER_SLOT*{.intdefine.} = 6'u64 # Compile with -d:SECONDS_PER_SLOT=1 for 6x faster slots
|
||||
## TODO consistent time unit across projects, similar to C++ chrono?
|
||||
|
||||
|
@ -130,6 +128,8 @@ const
|
|||
## wait towards the end of the slot and still have time to publish the
|
||||
## attestation.
|
||||
|
||||
# SLOTS_PER_EPOCH is defined above.
|
||||
|
||||
MIN_SEED_LOOKAHEAD* = 1 ##\
|
||||
## epochs (~6.4 minutes)
|
||||
|
||||
|
@ -139,18 +139,18 @@ const
|
|||
EPOCHS_PER_ETH1_VOTING_PERIOD* = 2'u64^4 ##\
|
||||
## epochs (~1.7 hours)
|
||||
|
||||
MIN_VALIDATOR_WITHDRAWAL_DELAY* = 2'u64^8 ##\
|
||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY* = 2'u64^8 ##\
|
||||
## epochs (~27 hours)
|
||||
|
||||
# State list lengths
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#state-list-lengths
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#state-list-lengths
|
||||
LATEST_BLOCK_ROOTS_LENGTH* = 2'u64^13
|
||||
LATEST_RANDAO_MIXES_LENGTH* = 2'u64^13
|
||||
LATEST_ACTIVE_INDEX_ROOTS_LENGTH* = 8192 # 2'u64^13, epochs
|
||||
LATEST_SLASHED_EXIT_LENGTH* = 8192 # epochs
|
||||
|
||||
# Reward and penalty quotients
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
|
||||
BASE_REWARD_QUOTIENT* = 2'u64^5 ##\
|
||||
## The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It
|
||||
## corresponds to ~2.54% annual interest assuming 10 million participating
|
||||
|
@ -160,12 +160,8 @@ const
|
|||
INACTIVITY_PENALTY_QUOTIENT* = 2'u64^24
|
||||
MIN_PENALTY_QUOTIENT* = 32 # 2^5
|
||||
|
||||
# Status flags
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#status-flags
|
||||
INITIATED_EXIT* = 1'u64
|
||||
|
||||
# Max transactions per block
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#max-transactions-per-block
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#max-transactions-per-block
|
||||
MAX_PROPOSER_SLASHINGS* = 2^4
|
||||
MAX_ATTESTER_SLASHINGS* = 2^0
|
||||
MAX_ATTESTATIONS* = 2^7
|
||||
|
@ -184,15 +180,18 @@ type
|
|||
Epoch* = uint64
|
||||
Gwei* = uint64
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposerslashing
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposerslashing
|
||||
ProposerSlashing* = object
|
||||
proposer_index*: uint64
|
||||
proposal_data_1*: ProposalSignedData
|
||||
proposal_signature_1*: ValidatorSig
|
||||
proposal_data_2*: ProposalSignedData
|
||||
proposal_signature_2*: ValidatorSig
|
||||
proposer_index*: uint64 ##\
|
||||
## Proposer index
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attesterslashing
|
||||
proposal_1*: Proposal ##\
|
||||
# First proposal
|
||||
|
||||
proposal_2*: Proposal ##\
|
||||
# Second proposal
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attesterslashing
|
||||
AttesterSlashing* = object
|
||||
slashable_attestation_1*: SlashableAttestation ## \
|
||||
## First slashable attestation
|
||||
|
@ -227,7 +226,7 @@ type
|
|||
aggregate_signature*: ValidatorSig ##\
|
||||
## BLS aggregate signature
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestationdata
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestationdata
|
||||
AttestationData* = object
|
||||
slot*: uint64 ##\
|
||||
## Slot number
|
||||
|
@ -241,8 +240,8 @@ type
|
|||
epoch_boundary_root*: Eth2Digest ##\
|
||||
## Hash of root of the ancestor at the epoch boundary
|
||||
|
||||
shard_block_root*: Eth2Digest ##\
|
||||
## Shard block's hash of root
|
||||
crosslink_data_root*: Eth2Digest ##\
|
||||
## Data from the shard since the last attestation
|
||||
|
||||
latest_crosslink*: Crosslink ##\
|
||||
## Last crosslink
|
||||
|
@ -253,7 +252,7 @@ type
|
|||
justified_block_root*: Eth2Digest ##\
|
||||
## Hash of the last justified beacon block
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestationdataandcustodybit
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestationdataandcustodybit
|
||||
AttestationDataAndCustodyBit* = object
|
||||
data*: AttestationData
|
||||
custody_bit*: bool
|
||||
|
@ -360,6 +359,20 @@ type
|
|||
voluntary_exits*: seq[VoluntaryExit]
|
||||
transfers*: seq[Transfer]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposal
|
||||
Proposal* = object
|
||||
slot*: uint64 ##\
|
||||
## Slot number
|
||||
|
||||
shard*: uint64 ##\
|
||||
## Shard number (`BEACON_CHAIN_SHARD_NUMBER` for beacon chain)
|
||||
|
||||
block_root*: Eth2Digest ##\
|
||||
## Block root
|
||||
|
||||
signature*: ValidatorSig ##\
|
||||
## Signature
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposalsigneddata
|
||||
ProposalSignedData* = object
|
||||
slot*: uint64
|
||||
|
@ -420,7 +433,7 @@ type
|
|||
# Not in spec. TODO: don't serialize or deserialize this.
|
||||
shuffling_cache*: ShufflingCache
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator
|
||||
Validator* = object
|
||||
pubkey*: ValidatorPubKey ##\
|
||||
## BLS public key
|
||||
|
@ -437,18 +450,19 @@ type
|
|||
withdrawable_epoch*: uint64 ##\
|
||||
## Epoch when validator is eligible to withdraw
|
||||
|
||||
slashed_epoch*: uint64 ##\
|
||||
## Epoch when validator slashed
|
||||
initiated_exit*: bool ##\
|
||||
## Did the validator initiate an exit
|
||||
|
||||
status_flags*: uint64
|
||||
slashed*: bool ##\
|
||||
## Was the validator slashed
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#crosslink
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#crosslink
|
||||
Crosslink* = object
|
||||
epoch*: uint64 ##\
|
||||
## Epoch number
|
||||
|
||||
shard_block_root*: Eth2Digest ##\
|
||||
## Shard block root
|
||||
crosslink_data_root*: Eth2Digest ##\
|
||||
## Shard data since the previous crosslink
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#pendingattestation
|
||||
PendingAttestation* = object
|
||||
|
@ -485,7 +499,7 @@ type
|
|||
Activation = 0
|
||||
Exit = 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#signature-domains
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#signature-domains
|
||||
SignatureDomain* {.pure.} = enum
|
||||
DOMAIN_DEPOSIT = 0
|
||||
DOMAIN_ATTESTATION = 1
|
||||
|
|
|
@ -138,7 +138,7 @@ func is_double_vote*(attestation_data_1: AttestationData,
|
|||
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||
target_epoch_1 == target_epoch_2
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#is_surround_vote
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#is_surround_vote
|
||||
func is_surround_vote*(attestation_data_1: AttestationData,
|
||||
attestation_data_2: AttestationData): bool =
|
||||
## Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||
|
|
|
@ -290,6 +290,21 @@ func hash_tree_root*[T: object|tuple](x: T): array[32, byte] =
|
|||
for field in x.fields:
|
||||
h.update hash_tree_root(field)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/simple-serialize.md#signed-roots
|
||||
func signed_root*[T: object](x: T, field_name: string): array[32, byte] =
|
||||
# TODO write tests for this (check vs hash_tree_root)
|
||||
|
||||
var found_field_name = false
|
||||
|
||||
withHash:
|
||||
for name, field in x.fieldPairs:
|
||||
if name == field_name:
|
||||
found_field_name = true
|
||||
break
|
||||
h.update hash_tree_root(field)
|
||||
|
||||
doAssert found_field_name
|
||||
|
||||
# #################################
|
||||
# hash_tree_root not part of official spec
|
||||
func hash_tree_root*(x: enum): array[8, byte] =
|
||||
|
|
|
@ -106,32 +106,7 @@ func processDepositRoot(state: var BeaconState, blck: BeaconBlock) =
|
|||
vote_count: 1
|
||||
)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#slashValidator
|
||||
func slashValidator(state: var BeaconState, index: ValidatorIndex) =
|
||||
## Slash the validator of the given ``index``.
|
||||
## Note that this function mutates ``state``.
|
||||
var validator = addr state.validator_registry[index]
|
||||
|
||||
doAssert state.slot < get_epoch_start_slot(validator.withdrawable_epoch) ##\
|
||||
## [TO BE REMOVED IN PHASE 2]
|
||||
|
||||
exit_validator(state, index)
|
||||
state.latest_slashed_balances[(get_current_epoch(state) mod
|
||||
LATEST_SLASHED_EXIT_LENGTH).int] += get_effective_balance(state,
|
||||
index.ValidatorIndex)
|
||||
|
||||
let
|
||||
whistleblower_index = get_beacon_proposer_index(state, state.slot)
|
||||
whistleblower_reward = get_effective_balance(state, index) div
|
||||
WHISTLEBLOWER_REWARD_QUOTIENT
|
||||
state.validator_balances[whistleblower_index] += whistleblower_reward
|
||||
reduce_balance(state.validator_balances[index], whistleblower_reward)
|
||||
validator.slashed_epoch = get_current_epoch(state)
|
||||
|
||||
# v0.3.0 spec bug, fixed later, involving renamed constants. Use v0.3.0 name.
|
||||
validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposer-slashings-1
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposer-slashings-1
|
||||
proc processProposerSlashings(
|
||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
|
||||
|
@ -141,48 +116,49 @@ proc processProposerSlashings(
|
|||
|
||||
for proposer_slashing in blck.body.proposer_slashings:
|
||||
let proposer = state.validator_registry[proposer_slashing.proposer_index.int]
|
||||
|
||||
if not (proposer_slashing.proposal_1.slot ==
|
||||
proposer_slashing.proposal_2.slot):
|
||||
notice "PropSlash: slot mismatch"
|
||||
return false
|
||||
|
||||
if not (proposer_slashing.proposal_1.shard ==
|
||||
proposer_slashing.proposal_2.shard):
|
||||
notice "PropSlash: shard mismatch"
|
||||
return false
|
||||
|
||||
if not (proposer_slashing.proposal_1.block_root !=
|
||||
proposer_slashing.proposal_2.block_root):
|
||||
notice "PropSlash: block root mismatch"
|
||||
return false
|
||||
|
||||
if not (proposer.slashed == false):
|
||||
notice "PropSlash: slashed proposer"
|
||||
return false
|
||||
|
||||
if skipValidation notin flags:
|
||||
if not bls_verify(
|
||||
proposer.pubkey,
|
||||
hash_tree_root_final(proposer_slashing.proposal_data_1).data,
|
||||
proposer_slashing.proposal_signature_1,
|
||||
signed_root(proposer_slashing.proposal_1, "signature"),
|
||||
proposer_slashing.proposal_1.signature,
|
||||
get_domain(
|
||||
state.fork, slot_to_epoch(proposer_slashing.proposal_data_1.slot),
|
||||
state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot),
|
||||
DOMAIN_PROPOSAL)):
|
||||
notice "PropSlash: invalid signature 1"
|
||||
return false
|
||||
if not bls_verify(
|
||||
proposer.pubkey,
|
||||
hash_tree_root_final(proposer_slashing.proposal_data_2).data,
|
||||
proposer_slashing.proposal_signature_2,
|
||||
signed_root(proposer_slashing.proposal_2, "signature"),
|
||||
proposer_slashing.proposal_2.signature,
|
||||
get_domain(
|
||||
state.fork, slot_to_epoch(proposer_slashing.proposal_data_2.slot),
|
||||
state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot),
|
||||
DOMAIN_PROPOSAL)):
|
||||
notice "PropSlash: invalid signature 2"
|
||||
return false
|
||||
|
||||
if not (proposer_slashing.proposal_data_1.slot ==
|
||||
proposer_slashing.proposal_data_2.slot):
|
||||
notice "PropSlash: slot mismatch"
|
||||
return false
|
||||
|
||||
if not (proposer_slashing.proposal_data_1.shard ==
|
||||
proposer_slashing.proposal_data_2.shard):
|
||||
notice "PropSlash: shard mismatch"
|
||||
return false
|
||||
|
||||
if not (proposer_slashing.proposal_data_1.block_root ==
|
||||
proposer_slashing.proposal_data_2.block_root):
|
||||
notice "PropSlash: block root mismatch"
|
||||
return false
|
||||
|
||||
if not (proposer.slashed_epoch > get_current_epoch(state)):
|
||||
notice "PropSlash: penalized slot"
|
||||
return false
|
||||
|
||||
slashValidator(state, proposer_slashing.proposer_index.ValidatorIndex)
|
||||
|
||||
return true
|
||||
true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#verify_slashable_attestation
|
||||
func verify_slashable_attestation(state: BeaconState, slashable_attestation: SlashableAttestation): bool =
|
||||
|
@ -233,7 +209,7 @@ func verify_slashable_attestation(state: BeaconState, slashable_attestation: Sla
|
|||
),
|
||||
)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attester-slashings-1
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attester-slashings-1
|
||||
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
||||
if len(blck.body.attester_slashings) > MAX_ATTESTER_SLASHINGS:
|
||||
notice "CaspSlash: too many!"
|
||||
|
@ -263,7 +239,7 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
|||
return false
|
||||
|
||||
let
|
||||
indices2 = slashable_attestation_2.validator_indices
|
||||
indices2 = toSet(slashable_attestation_2.validator_indices)
|
||||
slashable_indices =
|
||||
slashable_attestation_1.validator_indices.filterIt(it in indices2)
|
||||
|
||||
|
@ -272,7 +248,7 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
|||
return false
|
||||
|
||||
for index in slashable_indices:
|
||||
if state.validator_registry[index.int].slashed_epoch > get_current_epoch(state):
|
||||
if state.validator_registry[index.int].slashed:
|
||||
slash_validator(state, index.ValidatorIndex)
|
||||
|
||||
true
|
||||
|
@ -413,7 +389,7 @@ func processSlot(state: var BeaconState, previous_block_root: Eth2Digest) =
|
|||
## chain at that time. In case the proposer is missing, it may happen that
|
||||
## the no block is produced during the slot.
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#slot
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slot
|
||||
state.slot += 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#block-roots
|
||||
|
@ -503,13 +479,13 @@ func boundary_attestations(
|
|||
|
||||
func lowerThan(candidate, current: Eth2Digest): bool =
|
||||
# return true iff candidate is "lower" than current, per spec rule:
|
||||
# "ties broken by favoring lower `shard_block_root` values"
|
||||
# "ties broken by favoring lower `crosslink_data_root` values"
|
||||
# TODO spec - clarify hash ordering..
|
||||
for i, v in current.data:
|
||||
if v > candidate.data[i]: return true
|
||||
false
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||
func process_slashings(state: var BeaconState) =
|
||||
## Process the slashings.
|
||||
## Note that this function mutates ``state``.
|
||||
|
@ -517,12 +493,12 @@ func process_slashings(state: var BeaconState) =
|
|||
current_epoch = get_current_epoch(state)
|
||||
active_validator_indices = get_active_validator_indices(
|
||||
state.validator_registry, current_epoch)
|
||||
# TODO 0.3.0 spec doesn't use this helper function?
|
||||
# 0.4.0 spec doesn't use this helper function?
|
||||
total_balance = get_total_balance(state, active_validator_indices)
|
||||
|
||||
for index, validator in state.validator_registry:
|
||||
if current_epoch ==
|
||||
validator.slashed_epoch + LATEST_SLASHED_EXIT_LENGTH div 2:
|
||||
if validator.slashed and current_epoch == validator.withdrawable_epoch -
|
||||
LATEST_SLASHED_EXIT_LENGTH div 2:
|
||||
let
|
||||
epoch_index = current_epoch mod LATEST_SLASHED_EXIT_LENGTH
|
||||
total_at_start = state.latest_slashed_balances[
|
||||
|
@ -543,14 +519,12 @@ func process_exit_queue(state: var BeaconState) =
|
|||
func eligible(index: ValidatorIndex): bool =
|
||||
let validator = state.validator_registry[index]
|
||||
# Filter out dequeued validators
|
||||
if validator.withdrawable_epoch < FAR_FUTURE_EPOCH:
|
||||
if validator.withdrawable_epoch != FAR_FUTURE_EPOCH:
|
||||
return false
|
||||
# Dequeue if the minimum amount of time has passed
|
||||
else:
|
||||
return get_current_epoch(state) >= validator.exit_epoch +
|
||||
# TODO in future versions, remove workaround for 0.3.0 spec bug
|
||||
# but for 0.3.0 use MIN_VALIDATOR_WITHDRAWAL_DELAY constant
|
||||
MIN_VALIDATOR_WITHDRAWAL_DELAY
|
||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
|
||||
# TODO try again with filterIt
|
||||
var eligible_indices: seq[ValidatorIndex]
|
||||
|
@ -661,22 +635,22 @@ func processEpoch(state: var BeaconState) =
|
|||
# these closures outside this scope, but still..
|
||||
let statePtr = state.addr
|
||||
func attesting_validator_indices(
|
||||
crosslink_committee: CrosslinkCommittee, shard_block_root: Eth2Digest): seq[ValidatorIndex] =
|
||||
crosslink_committee: CrosslinkCommittee, crosslink_data_root: Eth2Digest): seq[ValidatorIndex] =
|
||||
let shard_block_attestations =
|
||||
concat(current_epoch_attestations, previous_epoch_attestations).
|
||||
filterIt(it.data.shard == crosslink_committee.shard and
|
||||
it.data.shard_block_root == shard_block_root)
|
||||
it.data.crosslink_data_root == crosslink_data_root)
|
||||
get_attester_indices(statePtr[], shard_block_attestations)
|
||||
|
||||
func winning_root(crosslink_committee: CrosslinkCommittee): Eth2Digest =
|
||||
# * Let `winning_root(crosslink_committee)` be equal to the value of
|
||||
# `shard_block_root` such that
|
||||
# `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, shard_block_root)])`
|
||||
# is maximized (ties broken by favoring lower `shard_block_root` values).
|
||||
# `crosslink_data_root` such that
|
||||
# `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, crosslink_data_root)])`
|
||||
# is maximized (ties broken by favoring lower `crosslink_data_root` values).
|
||||
let candidates =
|
||||
concat(current_epoch_attestations, previous_epoch_attestations).
|
||||
filterIt(it.data.shard == crosslink_committee.shard).
|
||||
mapIt(it.data.shard_block_root)
|
||||
mapIt(it.data.crosslink_data_root)
|
||||
|
||||
# TODO not covered by spec!
|
||||
if candidates.len == 0:
|
||||
|
@ -750,7 +724,7 @@ func processEpoch(state: var BeaconState) =
|
|||
2'u64 * get_total_balance(state, crosslink_committee.committee):
|
||||
state.latest_crosslinks[crosslink_committee.shard] = Crosslink(
|
||||
epoch: slot_to_epoch(slot),
|
||||
shard_block_root: winning_root(crosslink_committee))
|
||||
crosslink_data_root: winning_root(crosslink_committee))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#rewards-and-penalties
|
||||
## First, we define some additional helpers
|
||||
|
@ -768,22 +742,7 @@ func processEpoch(state: var BeaconState) =
|
|||
get_effective_balance(state, index) * epochs_since_finality div
|
||||
INACTIVITY_PENALTY_QUOTIENT div 2
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#justification-and-finalization
|
||||
## TODO remove inclusion_{slot,distance} when fully replaced, but note
|
||||
## intentional absence, for spec sync purposes. Both positively invite
|
||||
## quadratic behavior.
|
||||
func inclusion_slot(state: BeaconState, v: ValidatorIndex): uint64 =
|
||||
for a in previous_epoch_attestations:
|
||||
if v in get_attestation_participants(state, a.data, a.aggregation_bitfield):
|
||||
return a.inclusion_slot
|
||||
doAssert false
|
||||
|
||||
func inclusion_distance(state: BeaconState, v: ValidatorIndex): uint64 =
|
||||
for a in previous_epoch_attestations:
|
||||
if v in get_attestation_participants(state, a.data, a.aggregation_bitfield):
|
||||
return a.inclusion_slot - a.data.slot
|
||||
doAssert false
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#justification-and-finalization
|
||||
func inclusion_distances(state: BeaconState): auto =
|
||||
result = initTable[ValidatorIndex, uint64]()
|
||||
|
||||
|
@ -797,6 +756,12 @@ func processEpoch(state: var BeaconState) =
|
|||
let
|
||||
epochs_since_finality = next_epoch - state.finalized_epoch
|
||||
|
||||
## Note: Rewards and penalties are for participation in the previous
|
||||
## epoch, so the "active validator" set is drawn from
|
||||
## get_active_validator_indices(state.validator_registry, previous_epoch).
|
||||
active_validator_indices =
|
||||
get_active_validator_indices(state.validator_registry, previous_epoch)
|
||||
|
||||
proc update_balance(attesters: HashSet[ValidatorIndex], attesting_balance: uint64) =
|
||||
# TODO Spec - add helper?
|
||||
for v in attesters:
|
||||
|
@ -827,18 +792,17 @@ func processEpoch(state: var BeaconState) =
|
|||
previous_epoch_head_attesting_balance)
|
||||
|
||||
# Inclusion distance
|
||||
let distances = inclusion_distances(state)
|
||||
# Strange plural (non)convention, but match spec name.
|
||||
let inclusion_distance = inclusion_distances(state)
|
||||
|
||||
for v in previous_epoch_attester_indices:
|
||||
statePtr.validator_balances[v] +=
|
||||
base_reward(state, v) *
|
||||
MIN_ATTESTATION_INCLUSION_DELAY div distances[v]
|
||||
when false:
|
||||
doAssert inclusion_distance(state, v) == distances[v]
|
||||
MIN_ATTESTATION_INCLUSION_DELAY div inclusion_distance[v]
|
||||
|
||||
else:
|
||||
# Case 2: epochs_since_finality > 4
|
||||
let distances =
|
||||
let inclusion_distance =
|
||||
if previous_epoch_attester_indices.len > 0:
|
||||
inclusion_distances(state)
|
||||
else:
|
||||
|
@ -858,7 +822,7 @@ func processEpoch(state: var BeaconState) =
|
|||
if index notin previous_epoch_head_attester_indices:
|
||||
reduce_balance(
|
||||
state.validator_balances[index], base_reward(state, index))
|
||||
if state.validator_registry[index].slashed_epoch <= current_epoch:
|
||||
if state.validator_registry[index].slashed:
|
||||
reduce_balance(
|
||||
state.validator_balances[index],
|
||||
2'u64 * inactivity_penalty(
|
||||
|
@ -866,11 +830,10 @@ func processEpoch(state: var BeaconState) =
|
|||
if index in previous_epoch_attester_indices:
|
||||
reduce_balance(
|
||||
state.validator_balances[index],
|
||||
# TODO spec issue? depends on left/right associativity of * and /
|
||||
base_reward(state, index) -
|
||||
base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
|
||||
distances[index])
|
||||
when false:
|
||||
doAssert inclusion_distance(state, index) == distances[index]
|
||||
inclusion_distance[index])
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestation-inclusion
|
||||
block:
|
||||
|
@ -935,8 +898,8 @@ func processEpoch(state: var BeaconState) =
|
|||
reduce_balance(
|
||||
state.validator_balances[index], base_reward(state, index))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#ejections
|
||||
process_ejections(state, active_validator_indices)
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#ejections
|
||||
process_ejections(state)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||
block:
|
||||
|
|
|
@ -175,7 +175,7 @@ proc makeAttestation*(
|
|||
beacon_block_root: beacon_block_root,
|
||||
epoch_boundary_root: Eth2Digest(), # TODO
|
||||
latest_crosslink: state.latest_crosslinks[sac.shard],
|
||||
shard_block_root: Eth2Digest(), # TODO
|
||||
crosslink_data_root: Eth2Digest(), # TODO
|
||||
justified_epoch: state.justified_epoch,
|
||||
justified_block_root: get_block_root(state, get_epoch_start_slot(state.justified_epoch)),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue