More 0.6.1 updates (#274)

* implement get_churn_limit from 0.6.1; update initiate_validator_exit and get_previous_epoch to 0.6.1; remove obsoleted/non-spec reduce_balance, replaced by decrease_balance; mark BeaconBlock as 0.6.1

* rename get_block_root to get_block_root_at_slot and introduce epoch-oriented get_block_root; implement get_attestation_slot, get_matching_source_attestations, get_matching_target_attestations, get_matching_head_attestations, 0.6.1 get_attesting_indices, get_unslashed_attesting_indices, get_attestation_deltas, process_rewards_and_penalties; rm get_inactivity_penalty

* update Validator and processVoluntaryExits to 0.6.1; rm obsolete inclusion_slots/inclusion_distances

* rm removed activate_validator; mark DepositData, misc values, Gwei values, Randao processing, state caching as 0.6.1; update GENESIS_SLOT to 64, since it doesn't quite yet work at 0

* mark BeaconBlockHeader as 0.6.1; update BeaconBlockBody to 0.6.1; rename WHISTLEBLOWER_REWARD_QUOTIENT to WHISTLEBLOWING_REWARD_QUOTIENT; update slash_validator to 0.6.1

* implement 0.6.2 is_slashable_validator; update processProposerSlashings to 0.6.2; mark state caching as 0.6.2

* mark get_total_active_balance and process_slashings as 0.6.2; update get_base_reward to 0.6.2

* rm prepare_validator_for_withdrawal, process_exit_queue; mark mainnet misc constants as 0.6.2; update process block header to 0.6.2

* address mratsim's code review comment
This commit is contained in:
Dustin Brody 2019-05-29 10:08:56 +00:00 committed by GitHub
parent f679677995
commit 6a47ca3c46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 340 additions and 371 deletions

View File

@ -497,7 +497,6 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
# revisit this - we should be able to advance behind
node.blockPool.withState(node.stateCache, BlockSlot(blck: head, slot: slot)):
let
# TODO this probably isn't correct, check re blob/v0.5.1
proposerIdx = get_beacon_proposer_index(state)
validator = node.getAttachedValidator(state, proposerIdx)

View File

@ -120,27 +120,43 @@ func get_delayed_activation_exit_epoch*(epoch: Epoch): Epoch =
## takes effect.
epoch + 1 + ACTIVATION_EXIT_DELAY
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#activate_validator
func activate_validator(state: var BeaconState,
index: ValidatorIndex,
is_genesis: bool) =
## Activate the validator with the given ``index``.
## Note that this function mutates ``state``.
let validator = addr state.validator_registry[index]
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_churn_limit
func get_churn_limit(state: BeaconState): uint64 =
max(
MIN_PER_EPOCH_CHURN_LIMIT,
len(get_active_validator_indices(state, get_current_epoch(state))) div
CHURN_LIMIT_QUOTIENT
).uint64
validator.activation_epoch =
if is_genesis:
GENESIS_EPOCH
else:
get_delayed_activation_exit_epoch(get_current_epoch(state))
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#initiate_validator_exit
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/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.initiated_exit = true
# Initiate the validator of the given ``index``.
# Return if validator already initiated exit
let validator = addr state.validator_registry[index]
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return
# Compute exit queue epoch
let exit_epochs = mapIt(
filterIt(state.validator_registry, it.exit_epoch != FAR_FUTURE_EPOCH),
it.exit_epoch)
var exit_queue_epoch =
max(max(exit_epochs),
get_delayed_activation_exit_epoch(get_current_epoch(state)))
let exit_queue_churn = foldl(
state.validator_registry,
a + (if b.exit_epoch == exit_queue_epoch: 1'u64 else: 0'u64),
0'u64)
if exit_queue_churn >= get_churn_limit(state):
exit_queue_epoch += 1
# Set validator exit epoch and withdrawable epoch
validator.exit_epoch = exit_queue_epoch
validator.withdrawable_epoch =
validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#exit_validator
func exit_validator*(state: var BeaconState,
@ -159,37 +175,28 @@ func exit_validator*(state: var BeaconState,
validator.exit_epoch = delayed_activation_exit_epoch
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/v0.5.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``.
let 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)
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#slash_validator
func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex) =
# Slash the validator with index ``index``.
let current_epoch = get_current_epoch(state)
initiate_validator_exit(state, slashed_index)
state.validator_registry[slashed_index].slashed = true
state.validator_registry[slashed_index].withdrawable_epoch =
current_epoch + LATEST_SLASHED_EXIT_LENGTH
let slashed_balance =
state.validator_registry[slashed_index].effective_balance
state.latest_slashed_balances[current_epoch mod LATEST_SLASHED_EXIT_LENGTH] +=
slashed_balance
let
whistleblower_index = get_beacon_proposer_index(state)
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.balances[whistleblower_index] += whistleblower_reward
reduce_balance(state.balances[index], whistleblower_reward)
validator.slashed = true
validator.withdrawable_epoch =
get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
proposer_index = get_beacon_proposer_index(state)
whistleblower_index = proposer_index
whistleblowing_reward = slashed_balance div WHISTLEBLOWING_REWARD_QUOTIENT
proposer_reward = whistleblowing_reward div PROPOSER_REWARD_QUOTIENT
increase_balance(state, proposer_index, proposer_reward)
increase_balance(
state, whistleblower_index, whistleblowing_reward - proposer_reward)
decrease_balance(state, slashed_index, whistleblowing_reward)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#get_temporary_block_header
func get_temporary_block_header*(blck: BeaconBlock): BeaconBlockHeader =
@ -284,9 +291,10 @@ func get_genesis_beacon_state*(
# Process genesis activations
for validator_index in 0 ..< state.validator_registry.len:
let vi = validator_index.ValidatorIndex
if get_effective_balance(state, vi) >= MAX_EFFECTIVE_BALANCE:
activate_validator(state, vi, true)
let validator = addr state.validator_registry[validator_index]
if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = GENESIS_EPOCH
validator.activation_epoch = GENESIS_EPOCH
let genesis_active_index_root = hash_tree_root(
get_active_validator_indices(state, GENESIS_EPOCH))
@ -306,15 +314,37 @@ func get_initial_beacon_block*(state: BeaconState): BeaconBlock =
# initialized to default values.
)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_block_root
func get_block_root*(state: BeaconState,
slot: Slot): Eth2Digest =
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_attestation_slot
func get_attestation_slot*(state: BeaconState,
attestation: Attestation|PendingAttestation,
committee_count: uint64): Slot =
let
epoch = attestation.data.target_epoch
offset = (attestation.data.shard + SHARD_COUNT -
get_epoch_start_shard(state, epoch)) mod SHARD_COUNT
result = get_epoch_start_slot(epoch) + offset div (committee_count div SLOTS_PER_EPOCH)
# This is the slower (O(n)), spec-compatible signature.
func get_attestation_slot*(state: BeaconState,
attestation: Attestation|PendingAttestation): Slot =
let epoch = attestation.data.target_epoch
get_attestation_slot(
state, attestation, get_epoch_committee_count(state, epoch))
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: BeaconState,
slot: Slot): Eth2Digest =
# Return the block root at a recent ``slot``.
doAssert state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
doAssert slot < state.slot
state.latest_block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT]
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_block_root
func get_block_root*(state: BeaconState, epoch: Epoch): Eth2Digest =
# Return the block root at a recent ``epoch``.
get_block_root_at_slot(state, get_epoch_start_slot(epoch))
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#get_attestation_participants
func get_attestation_participants*(state: BeaconState,
attestation_data: AttestationData,
@ -443,13 +473,13 @@ func update_validator_registry*(state: var BeaconState) =
break
# Activate validator
activate_validator(state, index.ValidatorIndex, false)
state.validator_registry[index].activation_eligibility_epoch =
get_current_epoch(state)
# Exit validators within the allowable balance churn
balance_churn = 0
for index, validator in state.validator_registry:
if validator.activation_epoch == FAR_FUTURE_EPOCH and
validator.initiated_exit:
if validator.activation_epoch == FAR_FUTURE_EPOCH:
# Check the balance churn would be within the allowance
balance_churn += get_effective_balance(state, index.ValidatorIndex)
if balance_churn > max_balance_churn:
@ -609,15 +639,6 @@ proc checkAttestation*(
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#prepare_validator_for_withdrawal
func prepare_validator_for_withdrawal*(state: var BeaconState, index: ValidatorIndex) =
## Set the validator with the given ``index`` as withdrawable
## ``MIN_VALIDATOR_WITHDRAWABILITY_DELAY`` after the current epoch.
## Note that this function mutates ``state``.
var validator = addr state.validator_registry[index]
validator.withdrawable_epoch = get_current_epoch(state) +
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
proc makeAttestationData*(
state: BeaconState, shard: uint64,
beacon_block_root: Eth2Digest): AttestationData =
@ -629,7 +650,7 @@ proc makeAttestationData*(
epoch_start_slot = get_epoch_start_slot(slot_to_epoch(state.slot))
target_root =
if epoch_start_slot == state.slot: beacon_block_root
else: get_block_root(state, epoch_start_slot)
else: get_block_root_at_slot(state, epoch_start_slot)
AttestationData(
slot: state.slot,
@ -639,5 +660,6 @@ proc makeAttestationData*(
crosslink_data_root: Eth2Digest(), # Stub in phase0
previous_crosslink: state.latest_crosslinks[shard],
source_epoch: state.current_justified_epoch,
source_root: state.current_justified_root
source_root: state.current_justified_root,
target_epoch: slot_to_epoch(epoch_start_slot)
)

View File

@ -53,7 +53,7 @@ else:
{.fatal: "Preset \"" & const_preset ".nim\" is not supported.".}
const
SPEC_VERSION* = "0.5.1" ## \
SPEC_VERSION* = "0.6.1" ## \
## Spec version we're aiming to be compatible with, right now
## TODO: improve this scheme once we can negotiate versions in protocol
@ -68,7 +68,7 @@ const
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#gwei-values
# TODO remove erstwhile blob/v0.5.0
# TODO remove erstwhile blob/v0.6.2
FORK_CHOICE_BALANCE_INCREMENT* = 2'u64^0 * 10'u64^9
# Initial values
@ -141,6 +141,7 @@ type
# FFG vote
source_epoch*: Epoch
source_root*: Eth2Digest
target_epoch*: Epoch
target_root*: Eth2Digest
# Crosslink vote
@ -164,7 +165,7 @@ type
data*: DepositData ##\
## Data
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#depositdata
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#depositdata
DepositData* = object
pubkey*: ValidatorPubKey ##\
## BLS pubkey
@ -212,7 +213,7 @@ type
signature*: ValidatorSig ##\
## Sender signature
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblock
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beaconblock
BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose
## a new block. Once the block as been proposed, it is transmitted to
@ -233,7 +234,7 @@ type
signature*: ValidatorSig ##\
## Proposer signature
#https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblockheader
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beaconblockheader
BeaconBlockHeader* = object
slot*: Slot
previous_block_root*: Eth2Digest
@ -256,10 +257,11 @@ type
signature*: ValidatorSig
body*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblockbody
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beaconblockbody
BeaconBlockBody* = object
randao_reveal*: ValidatorSig
eth1_data*: Eth1Data
graffiti*: Eth2Digest
proposer_slashings*: seq[ProposerSlashing]
attester_slashings*: seq[AttesterSlashing]
attestations*: seq[Attestation]
@ -321,7 +323,7 @@ type
eth1_data_votes*: seq[Eth1Data]
deposit_index*: uint64
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#validator
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#validator
Validator* = object
pubkey*: ValidatorPubKey ##\
## BLS public key
@ -341,9 +343,6 @@ type
withdrawable_epoch*: Epoch ##\
## Epoch when validator is eligible to withdraw
initiated_exit*: bool ##\
## Did the validator initiate an exit
slashed*: bool ##\
## Was the validator slashed
@ -365,7 +364,11 @@ type
PendingAttestation* = object
aggregation_bitfield*: BitField ## Attester participation bitfield
data*: AttestationData ## Attestation data
# TODO remove
inclusion_slot*: Slot ## Inclusion slot
inclusion_delay*: uint64 ## Inclusion delay
proposer_index*: ValidatorIndex ## Proposer index
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.0/specs/core/0_beacon-chain.md#historicalbatch

View File

@ -26,7 +26,7 @@ type
const
# Misc
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#misc
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#misc
SHARD_COUNT* {.intdefine.} = 1024 ##\
## Number of shards supported by the network - validators will jump around
@ -66,7 +66,7 @@ const
# Gwei values
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#gwei-values
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/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
@ -86,7 +86,7 @@ const
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#initial-values
GENESIS_FORK_VERSION* = [0'u8, 0'u8, 0'u8, 0'u8]
GENESIS_SLOT* = (2'u64^32).Slot
GENESIS_SLOT* = 64.Slot
FAR_FUTURE_EPOCH* = (not 0'u64).Epoch # 2^64 - 1 in spec
BLS_WITHDRAWAL_PREFIX_BYTE* = 0'u8
@ -150,7 +150,7 @@ const
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
BASE_REWARD_QUOTIENT* = 2'u64^5
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
WHISTLEBLOWING_REWARD_QUOTIENT* = 2'u64^9
PROPOSER_REWARD_QUOTIENT* = 2'u64^3
INACTIVITY_PENALTY_QUOTIENT* = 2'u64^25
MIN_PENALTY_QUOTIENT* = 32 # 2^5

View File

@ -26,7 +26,7 @@ type
const
# Misc
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#misc
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#misc
# Changed
SHARD_COUNT* {.intdefine.} = 8
@ -51,7 +51,7 @@ const
# Gwei values
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#gwei-values
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#gwei-values
# Unchanged
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9
@ -65,7 +65,7 @@ const
# Unchanged
GENESIS_FORK_VERSION* = [0'u8, 0'u8, 0'u8, 0'u8]
GENESIS_SLOT* = (2'u64^32).Slot
GENESIS_SLOT* = 64.Slot
FAR_FUTURE_EPOCH* = (not 0'u64).Epoch # 2^64 - 1 in spec
BLS_WITHDRAWAL_PREFIX_BYTE* = 0'u8
@ -109,7 +109,7 @@ const
# Unchanged
BASE_REWARD_QUOTIENT* = 2'u64^5
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
WHISTLEBLOWING_REWARD_QUOTIENT* = 2'u64^9
PROPOSER_REWARD_QUOTIENT* = 2'u64^3
INACTIVITY_PENALTY_QUOTIENT* = 2'u64^25
MIN_PENALTY_QUOTIENT* = 32 # 2^5

View File

@ -138,17 +138,15 @@ func get_shuffling*(seed: Eth2Digest,
result = split(shuffled_seq, committees_per_epoch)
doAssert result.len() == committees_per_epoch # what split should do..
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_previous_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_previous_epoch
func get_previous_epoch*(state: BeaconState): Epoch =
## Return the previous epoch of the given ``state``.
# Note: This is allowed to underflow internally (this is why GENESIS_EPOCH != 0)
# however when interfacing with peers for example for attestations
# this should not underflow.
# TODO or not - it causes issues: https://github.com/ethereum/eth2.0-specs/issues/849
let epoch = get_current_epoch(state)
max(GENESIS_EPOCH, epoch - 1) # TODO max here to work around the above issue
## Return the current epoch if it's genesis epoch.
let current_epoch = get_current_epoch(state)
if current_epoch > GENESIS_EPOCH:
current_epoch - 1
else:
current_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_crosslink_committees_at_slot
func get_crosslink_committees_at_slot*(state: BeaconState, slot: Slot|uint64,
@ -258,7 +256,7 @@ func get_shard_delta(state: BeaconState, epoch: Epoch): uint64 =
(SHARD_COUNT - SHARD_COUNT div SLOTS_PER_EPOCH).uint64)
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_epoch_start_shard
func get_epoch_start_shard(state: BeaconState, epoch: Epoch): Shard =
func get_epoch_start_shard*(state: BeaconState, epoch: Epoch): Shard =
doAssert epoch <= get_current_epoch(state) + 1
var
check_epoch = get_current_epoch(state) + 1
@ -284,7 +282,7 @@ func compute_committee(indices: seq[ValidatorIndex], seed: Eth2Digest,
get_shuffled_index(it.ValidatorIndex, len(indices).uint64, seed).int])
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_crosslink_committee
func get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard):
func get_crosslink_committee*(state: BeaconState, epoch: Epoch, shard: Shard):
seq[ValidatorIndex] =
compute_committee(
get_active_validator_indices(state, epoch),

View File

@ -264,7 +264,7 @@ proc readValue*(r: var SszReader, result: var auto) =
# Sample hash_tree_root implementation based on:
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.0/specs/simple-serialize.md
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/utils/phase0/minimal_ssz.py
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/test_libs/pyspec/eth2spec/utils/minimal_ssz.py
# TODO Probably wrong - the spec is pretty bare-bones and no test vectors yet
const

View File

@ -31,11 +31,11 @@
# now.
import
algorithm, collections/sets, chronicles, math, options, sequtils, tables,
algorithm, collections/sets, chronicles, math, options, sequtils, sets, tables,
./extras, ./ssz, ./beacon_node_types,
./spec/[beaconstate, bitfield, crypto, datatypes, digest, helpers, validator]
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#block-header
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#block-header
proc processBlockHeader(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
# Verify that the slots match
@ -45,7 +45,7 @@ proc processBlockHeader(
state_slot = humaneSlotNum(state.slot)
return false
# state_root not set yet, when skipping validation
# Verify that the parent matches
if skipValidation notin flags and not (blck.previous_block_root ==
signing_root(state.latest_block_header)):
notice "Block header: previous block root mismatch",
@ -54,15 +54,25 @@ proc processBlockHeader(
latest_block_header_root = shortLog(signing_root(state.latest_block_header))
return false
state.latest_block_header = get_temporary_block_header(blck)
# Save current block as the new latest block
state.latest_block_header = BeaconBlockHeader(
slot: blck.slot,
previous_block_root: blck.previous_block_root,
block_body_root: hash_tree_root(blck.body),
)
let proposer =
state.validator_registry[get_beacon_proposer_index(state)]
# Verify proposer is not slashed
let proposer = state.validator_registry[get_beacon_proposer_index(state)]
if proposer.slashed:
notice "Block header: proposer slashed"
return false
# Verify proposer signature
if skipValidation notin flags and not bls_verify(
proposer.pubkey,
signing_root(blck).data,
blck.signature,
get_domain(state, DOMAIN_BEACON_PROPOSER, get_current_epoch(state))):
get_domain(state, DOMAIN_BEACON_PROPOSER)):
notice "Block header: invalid block header",
proposer_pubkey = proposer.pubkey,
block_root = shortLog(signing_root(blck)),
@ -71,13 +81,14 @@ proc processBlockHeader(
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#randao
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#randao
proc processRandao(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
let
proposer_index = get_beacon_proposer_index(state)
proposer = addr state.validator_registry[proposer_index]
# Verify that the provided randao value is valid
if skipValidation notin flags:
if not bls_verify(
proposer.pubkey,
@ -95,7 +106,6 @@ proc processRandao(
# Mix it in
let
mix = get_current_epoch(state) mod LATEST_RANDAO_MIXES_LENGTH
# TODO hash_tree_root has some overloading for this
rr = eth2hash(blck.body.randao_reveal.getBytes()).data
for i, b in state.latest_randao_mixes[mix].data:
@ -110,7 +120,14 @@ func processEth1Data(state: var BeaconState, blck: BeaconBlock) =
SLOTS_PER_ETH1_VOTING_PERIOD:
state.latest_eth1_data = blck.body.eth1_data
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#proposer-slashings
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#is_slashable_validator
func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
# Check if ``validator`` is slashable.
(not validator.slashed) and
(validator.activation_epoch <= epoch) and
(epoch < validator.withdrawable_epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#proposer-slashings
proc processProposerSlashings(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
@ -121,19 +138,23 @@ proc processProposerSlashings(
for proposer_slashing in blck.body.proposer_slashings:
let proposer = state.validator_registry[proposer_slashing.proposer_index.int]
# Verify that the epoch is the same
if not (slot_to_epoch(proposer_slashing.header_1.slot) ==
slot_to_epoch(proposer_slashing.header_2.slot)):
notice "PropSlash: epoch mismatch"
return false
# But the headers are different
if not (proposer_slashing.header_1 != proposer_slashing.header_2):
notice "PropSlash: headers not different"
return false
if not (proposer.slashed == false):
# Check proposer is slashable
if not is_slashable_validator(proposer, get_current_epoch(state)):
notice "PropSlash: slashed proposer"
return false
# Signatures are valid
if skipValidation notin flags:
for i, header in @[proposer_slashing.header_1, proposer_slashing.header_2]:
if not bls_verify(
@ -265,11 +286,23 @@ proc processAttestations(
# All checks passed - update state
# Apply the attestations
var committee_count_cache = initTable[Epoch, uint64]()
for attestation in blck.body.attestations:
let
epoch = attestation.data.target_epoch
committee_count = if epoch in committee_count_cache:
committee_count_cache[epoch]
else:
get_epoch_committee_count(state, epoch)
committee_count_cache[epoch] = committee_count
let attestation_slot =
get_attestation_slot(state, attestation, committee_count)
let pending_attestation = PendingAttestation(
data: attestation.data,
aggregation_bitfield: attestation.aggregation_bitfield,
inclusion_slot: state.slot,
inclusion_delay: state.slot - attestation_slot,
proposer_index: get_beacon_proposer_index(state),
)
@ -293,11 +326,10 @@ proc processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#voluntary-exits
proc processExits(
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#voluntary-exits
proc processVoluntaryExits(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
## Process ``VoluntaryExit`` transaction.
## Note that this function mutates ``state``.
# Process ``VoluntaryExit`` transaction.
if len(blck.body.voluntary_exits) > MAX_VOLUNTARY_EXITS:
notice "Exit: too many!"
return false
@ -305,23 +337,23 @@ proc processExits(
for exit in blck.body.voluntary_exits:
let validator = state.validator_registry[exit.validator_index.int]
# Verify the validator is active
if not is_active_validator(validator, get_current_epoch(state)):
notice "Exit: validator not active"
return false
# Verify the validator has not yet exited
if not (validator.exit_epoch == FAR_FUTURE_EPOCH):
notice "Exit: validator has exited"
return false
# Verify the validator has not initiated an exit
if not (not validator.initiated_exit):
notice "Exit: validator has initiated an exit"
return false
## Exits must specify an epoch when they become valid; they are not valid
## before then
if not (get_current_epoch(state) >= exit.epoch):
notice "Exit: exit epoch not passed"
return false
# Must have been in the validator set long enough
# Verify the validator has been active long enough
if not (get_current_epoch(state) - validator.activation_epoch >=
PERSISTENT_COMMITTEE_PERIOD):
notice "Exit: not in validator set long enough"
@ -335,7 +367,7 @@ proc processExits(
notice "Exit: invalid signature"
return false
# Run the exit
# Initiate exit
initiate_validator_exit(state, exit.validator_index.ValidatorIndex)
true
@ -445,7 +477,7 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock,
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#per-slot-processing
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#per-slot-processing
func advance_slot(state: var BeaconState) =
## Time on the beacon chain moves in slots. Every time we make it to a new
## slot, a proposer creates a block to represent the state of the beacon
@ -454,7 +486,7 @@ func advance_slot(state: var BeaconState) =
state.slot += 1
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#state-caching
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#state-caching
func cacheState(state: var BeaconState) =
let previous_slot_state_root = hash_tree_root(state)
@ -504,7 +536,7 @@ proc processBlock(
debug "[Block processing] Deposit processing failure", slot = humaneSlotNum(state.slot)
return false
if not processExits(state, blck, flags):
if not processVoluntaryExits(state, blck, flags):
debug "[Block processing] Exit processing failure", slot = humaneSlotNum(state.slot)
return false
@ -514,17 +546,54 @@ proc processBlock(
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#helper-functions-1
func get_current_total_balance(state: BeaconState): Gwei =
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#helper-functions-1
func get_total_active_balance(state: BeaconState): Gwei =
return get_total_balance(
state,
get_active_validator_indices(state, get_current_epoch(state)))
func get_previous_total_balance(state: BeaconState): Gwei =
get_total_balance(
state,
get_active_validator_indices(state, get_previous_epoch(state)))
func get_matching_source_attestations(state: BeaconState, epoch: Epoch):
seq[PendingAttestation] =
doAssert epoch in @[get_current_epoch(state), get_previous_epoch(state)]
if epoch == get_current_epoch(state):
state.current_epoch_attestations
else:
state.previous_epoch_attestations
func get_matching_target_attestations(state: BeaconState, epoch: Epoch):
seq[PendingAttestation] =
filterIt(
get_matching_source_attestations(state, epoch),
it.data.target_root == get_block_root(state, epoch)
)
func get_matching_head_attestations(state: BeaconState, epoch: Epoch):
seq[PendingAttestation] =
filterIt(
get_matching_source_attestations(state, epoch),
it.data.beacon_block_root ==
get_block_root_at_slot(state, get_attestation_slot(state, it))
)
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_attesting_indices
func get_attesting_indices(state: BeaconState,
attestation_data: AttestationData,
bitfield: BitField): HashSet[ValidatorIndex] =
## Return the sorted attesting indices corresponding to ``attestation_data``
## and ``bitfield``.
## The spec goes through a lot of hoops to sort things, and sometimes
## constructs sets from the results here. The basic idea is to always
## just do the right thing and keep it in a HashSet.
result = initSet[ValidatorIndex]()
let committee =
get_crosslink_committee(state, attestation_data.target_epoch,
attestation_data.shard)
doAssert verify_bitfield(bitfield, len(committee))
for i, index in committee:
if get_bitfield_bit(bitfield, i):
result.incl index
# TODO remove this 0.5ish one when callers disappear
func get_attesting_indices(
state: BeaconState,
attestations: openArray[PendingAttestation]): HashSet[ValidatorIndex] =
@ -535,6 +604,7 @@ func get_attesting_indices(
state, attestation.data, attestation.aggregation_bitfield):
result.incl validator_index
# TODO this cached version corresponds to the 0.5ish get_attesting_indices
func get_attesting_indices_cached(
state: BeaconState,
attestations: openArray[PendingAttestation], cache: var StateCache):
@ -547,6 +617,24 @@ func get_attesting_indices_cached(
cache):
result.incl validator_index
func get_unslashed_attesting_indices(
state: BeaconState, attestations: seq[PendingAttestation]):
HashSet[ValidatorIndex] =
result = initSet[ValidatorIndex]()
for a in attestations:
result = result.union(get_attesting_indices(
state, a.data, a.aggregation_bitfield))
for index in result:
if state.validator_registry[index].slashed:
result.excl index
# TODO check for blob/v0.5.0 removal
func get_previous_total_balance(state: BeaconState): Gwei =
get_total_balance(
state,
get_active_validator_indices(state, get_previous_epoch(state)))
func get_attesting_balance(state: BeaconState,
attestations: seq[PendingAttestation]): Gwei =
get_total_balance(state, get_attesting_indices(state, attestations))
@ -561,7 +649,7 @@ func get_current_epoch_boundary_attestations(state: BeaconState):
seq[PendingAttestation] =
filterIt(
state.current_epoch_attestations,
it.data.target_root == get_block_root(
it.data.target_root == get_block_root_at_slot(
state, get_epoch_start_slot(get_current_epoch(state))))
func get_previous_epoch_boundary_attestations(state: BeaconState):
@ -569,13 +657,13 @@ func get_previous_epoch_boundary_attestations(state: BeaconState):
filterIt(
state.previous_epoch_attestations,
it.data.target_root ==
get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))))
get_block_root_at_slot(state, get_epoch_start_slot(get_previous_epoch(state))))
func get_previous_epoch_matching_head_attestations(state: BeaconState):
seq[PendingAttestation] =
filterIt(
state.previous_epoch_attestations,
it.data.beacon_block_root == get_block_root(state, it.data.slot))
it.data.beacon_block_root == get_block_root_at_slot(state, it.data.slot))
# Not exactly in spec, but for get_winning_root_and_participants
func lowerThan(candidate, current: Eth2Digest): bool =
@ -632,33 +720,8 @@ func get_winning_root_and_participants(
state,
attestations_for.getOrDefault(winning_root), cache))
# Combination of earliest_attestation and inclusion_slot avoiding O(n^2)
# TODO merge/refactor these two functions, which differ only very slightly.
func inclusion_slots(state: BeaconState): auto =
result = initTable[ValidatorIndex, Slot]()
for a in sorted(state.previous_epoch_attestations,
func (x, y: PendingAttestation): auto =
system.cmp(x.inclusion_slot, y.inclusion_slot)):
for v in get_attestation_participants(
state, a.data, a.aggregation_bitfield):
if v notin result:
result[v] = a.inclusion_slot
# Combination of earliest_attestation and inclusion_distance avoiding O(n^2)
func inclusion_distances(state: BeaconState): auto =
result = initTable[ValidatorIndex, Slot]()
for a in sorted(state.previous_epoch_attestations,
func (x, y: PendingAttestation): auto =
system.cmp(x.inclusion_slot, y.inclusion_slot)):
for v in get_attestation_participants(
state, a.data, a.aggregation_bitfield):
if v notin result:
result[v] = Slot(a.inclusion_slot - a.data.slot)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#justification
func update_justification_and_finalization(state: var BeaconState) =
func process_justification_and_finalization(state: var BeaconState) =
var
new_justified_epoch = state.current_justified_epoch
new_finalized_epoch = state.finalized_epoch
@ -681,7 +744,7 @@ func update_justification_and_finalization(state: var BeaconState) =
get_attesting_balance(
state, get_current_epoch_boundary_attestations(state))
if current_boundary_attesting_balance * 3'u64 >=
get_current_total_balance(state) * 2'u64:
get_total_active_balance(state) * 2'u64:
new_justified_epoch = get_current_epoch(state)
state.justification_bitfield = state.justification_bitfield or 1
@ -720,11 +783,11 @@ func update_justification_and_finalization(state: var BeaconState) =
if new_justified_epoch != state.current_justified_epoch:
state.current_justified_epoch = new_justified_epoch
state.current_justified_root =
get_block_root(state, get_epoch_start_slot(new_justified_epoch))
get_block_root_at_slot(state, get_epoch_start_slot(new_justified_epoch))
if new_finalized_epoch != state.finalized_epoch:
state.finalized_epoch = new_finalized_epoch
state.finalized_root =
get_block_root(state, get_epoch_start_slot(new_finalized_epoch))
get_block_root_at_slot(state, get_epoch_start_slot(new_finalized_epoch))
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#crosslinks
func process_crosslinks(
@ -769,170 +832,92 @@ func process_crosslinks(
crosslink_data_root: winning_root
)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#rewards-and-penalties
func get_base_reward(state: BeaconState, index: ValidatorIndex): uint64 =
if get_previous_total_balance(state) == 0:
return 0
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#rewards-and-penalties
func get_base_reward(state: BeaconState, index: ValidatorIndex): Gwei =
let adjusted_quotient =
integer_squareroot(get_previous_total_balance(state)) div
BASE_REWARD_QUOTIENT
get_effective_balance(state, index) div adjusted_quotient.uint64 div 5
integer_squareroot(get_total_active_balance(state)) div BASE_REWARD_QUOTIENT
if adjusted_quotient == 0:
return 0
state.validator_registry[index].effective_balance div adjusted_quotient div
BASE_REWARDS_PER_EPOCH
func get_inactivity_penalty(
state: BeaconState, index: ValidatorIndex,
epochs_since_finality: uint64): uint64 =
# TODO Left/right associativity sensitivity on * and div?
get_base_reward(state, index) +
get_effective_balance(state, index) * epochs_since_finality div
INACTIVITY_PENALTY_QUOTIENT div 2
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#justification-and-finalization
func compute_normal_justification_and_finalization_deltas(state: BeaconState):
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#rewards-and-penalties
func get_attestation_deltas(state: BeaconState):
tuple[a: seq[Gwei], b: seq[Gwei]] =
# deltas[0] for rewards
# deltas[1] for penalties
var deltas = (
repeat(0'u64, len(state.validator_registry)),
repeat(0'u64, len(state.validator_registry))
)
# Some helper variables
let
boundary_attestations = get_previous_epoch_boundary_attestations(state)
boundary_attesting_balance =
get_attesting_balance(state, boundary_attestations)
total_balance = get_previous_total_balance(state)
total_attesting_balance =
get_attesting_balance(state, state.previous_epoch_attestations)
previous_epoch = get_previous_epoch(state)
total_balance = get_total_active_balance(state)
var
rewards = repeat(0'u64, len(state.validator_registry))
penalties = repeat(0'u64, len(state.validator_registry))
eligible_validator_indices : seq[ValidatorIndex] = @[]
for index, v in state.validator_registry:
if is_active_validator(v, previous_epoch) or
(v.slashed and previous_epoch + 1 < v.withdrawable_epoch):
eligible_validator_indices.add index.ValidatorIndex
# Micro-incentives for matching FFG source, FFG target, and head
let
matching_source_attestations =
get_matching_source_attestations(state, previous_epoch)
matching_target_attestations =
get_matching_target_attestations(state, previous_epoch)
matching_head_attestations =
get_previous_epoch_matching_head_attestations(state)
matching_head_balance =
get_attesting_balance(state, matching_head_attestations)
get_matching_head_attestations(state, previous_epoch)
for attestations in
@[matching_source_attestations, matching_target_attestations,
matching_head_attestations]:
let
unslashed_attesting_indices =
get_unslashed_attesting_indices(state, attestations)
attesting_balance = get_attesting_balance(state, attestations)
for index in eligible_validator_indices:
if index in unslashed_attesting_indices:
rewards[index] +=
get_base_reward(state, index) * attesting_balance div total_balance
else:
penalties[index] += get_base_reward(state, index)
let
inclusion_distance = inclusion_distances(state)
inclusion_slot = inclusion_slots(state)
previous_epoch_attestation_indices =
get_attesting_indices(state, state.previous_epoch_attestations)
boundary_attestation_indices =
get_attesting_indices(state, boundary_attestations)
matching_head_attestation_indices =
get_attesting_indices(state, matching_head_attestations)
# Process rewards or penalties for all validators
for index in get_active_validator_indices(state, get_previous_epoch(state)):
# Expected FFG source
if index in previous_epoch_attestation_indices:
deltas[0][index] +=
get_base_reward(state, index) * total_attesting_balance div
total_balance
# Inclusion speed bonus
deltas[0][index] += (
get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
inclusion_distance[index]
)
else:
deltas[1][index] += get_base_reward(state, index)
# Expected FFG target
if index in boundary_attestation_indices:
deltas[0][index] +=
get_base_reward(state, index) * boundary_attesting_balance div
total_balance
else:
deltas[1][index] += get_base_reward(state, index)
# Expected head
if index in matching_head_attestation_indices:
deltas[0][index] +=
get_base_reward(state, index) *
matching_head_balance div total_balance
else:
deltas[1][index] += get_base_reward(state, index)
# Proposer bonus
if index in previous_epoch_attestation_indices:
let proposer_index =
get_beacon_proposer_index(state)
deltas[0][proposer_index] +=
get_base_reward(state, index) div PROPOSER_REWARD_QUOTIENT
deltas
if matching_source_attestations.len == 0:
return (rewards, penalties)
func compute_inactivity_leak_deltas(state: BeaconState):
tuple[a: seq[Gwei], b: seq[Gwei]] =
# When blocks are not finalizing normally
# deltas[0] for rewards
# deltas[1] for penalties
var deltas = (
repeat(0'u64, len(state.validator_registry)),
repeat(0'u64, len(state.validator_registry))
)
# Proposer and inclusion delay micro-rewards
for index in get_unslashed_attesting_indices(state, matching_source_attestations):
doAssert matching_source_attestations.len > 0
var attestation = matching_source_attestations[0]
for a in matching_source_attestations:
if index notin get_attesting_indices(state, a.data, a.aggregation_bitfield):
continue
if a.inclusion_delay < attestation.inclusion_delay:
attestation = a
rewards[attestation.proposer_index] += get_base_reward(state, index) div
PROPOSER_REWARD_QUOTIENT
rewards[index] +=
get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
attestation.inclusion_delay
let
boundary_attestations = get_previous_epoch_boundary_attestations(state)
matching_head_attestations =
get_previous_epoch_matching_head_attestations(state)
active_validator_indices = toSet(get_active_validator_indices(
state, get_previous_epoch(state)))
epochs_since_finality =
get_current_epoch(state) + 1 - state.finalized_epoch
let
inclusion_distance = inclusion_distances(state)
previous_epoch_attestation_indices =
get_attesting_indices(state, state.previous_epoch_attestations)
boundary_attestation_indices =
get_attesting_indices(state, boundary_attestations)
matching_head_attestation_indices =
get_attesting_indices(state, matching_head_attestations)
for index in active_validator_indices:
if index notin previous_epoch_attestation_indices:
deltas[1][index] +=
get_inactivity_penalty(state, index, epochs_since_finality)
else:
## If a validator did attest, apply a small penalty for getting
## attestations included late
deltas[0][index] += (
get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
inclusion_distance[index]
)
deltas[1][index] += get_base_reward(state, index)
if index notin boundary_attestation_indices:
deltas[1][index] +=
get_inactivity_penalty(state, index, epochs_since_finality)
if index notin matching_head_attestation_indices:
deltas[1][index] += get_base_reward(state, index)
# Inactivity penalty
let finality_delay = previous_epoch - state.finalized_epoch
if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY:
let matching_target_attesting_indices =
get_unslashed_attesting_indices(state, matching_target_attestations)
for index in eligible_validator_indices:
penalties[index] +=
BASE_REWARDS_PER_EPOCH.uint64 * get_base_reward(state, index)
if index notin matching_target_attesting_indices:
penalties[index] +=
state.validator_registry[index].effective_balance *
finality_delay div INACTIVITY_PENALTY_QUOTIENT
## Penalize slashed-but-inactive validators as though they were active but
## offline
for index in 0 ..< len(state.validator_registry):
let eligible = (
index.ValidatorIndex notin active_validator_indices and
state.validator_registry[index].slashed and
get_current_epoch(state) <
state.validator_registry[index].withdrawable_epoch
)
if eligible:
deltas[1][index] += (
2'u64 * get_inactivity_penalty(
state, index.ValidatorIndex, epochs_since_finality) +
get_base_reward(state, index.ValidatorIndex)
)
deltas
(rewards, penalties)
func get_justification_and_finalization_deltas(state: BeaconState):
tuple[a: seq[Gwei], b: seq[Gwei]] =
let epochs_since_finality =
get_current_epoch(state) + 1 - state.finalized_epoch
if epochs_since_finality <= 4:
compute_normal_justification_and_finalization_deltas(state)
else:
compute_inactivity_leak_deltas(state)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#crosslinks-1
# blob/0.5.1
func get_crosslink_deltas(state: BeaconState, cache: var StateCache):
tuple[a: seq[Gwei], b: seq[Gwei]] =
# deltas[0] for rewards
# deltas[1] for penalties
var deltas = (
repeat(0'u64, len(state.validator_registry)),
repeat(0'u64, len(state.validator_registry))
)
var
rewards = repeat(0'u64, len(state.validator_registry))
penalties = repeat(0'u64, len(state.validator_registry))
let
previous_epoch_start_slot =
get_epoch_start_slot(get_previous_epoch(state))
@ -952,30 +937,26 @@ func get_crosslink_deltas(state: BeaconState, cache: var StateCache):
total_balance = get_total_balance(state, crosslink_committee)
for index in crosslink_committee:
if index in participants:
deltas[0][index] +=
rewards[index] +=
get_base_reward(state, index) * participating_balance div
total_balance
else:
deltas[1][index] += get_base_reward(state, index)
penalties[index] += get_base_reward(state, index)
deltas
(rewards, penalties)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#apply-rewards
func apply_rewards(state: var BeaconState, cache: var StateCache) =
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#rewards-and-penalties
func process_rewards_and_penalties(
state: var BeaconState, cache: var StateCache) =
let
deltas1 = get_justification_and_finalization_deltas(state)
deltas2 = get_crosslink_deltas(state, cache)
(rewards1, penalties1) = get_attestation_deltas(state)
(rewards2, penalties2) = get_crosslink_deltas(state, cache)
for i in 0 ..< len(state.validator_registry):
state.balances[i] =
max(
0'u64,
state.balances[i] + deltas1[0][i] + deltas2[0][i] -
deltas1[1][i] - deltas2[1][i])
increase_balance(state, i.ValidatorIndex, rewards1[i] + rewards2[i])
decrease_balance(state, i.ValidatorIndex, penalties1[i] + penalties2[i])
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#slashings-and-exit-queue
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#slashings
func process_slashings(state: var BeaconState) =
## Process the slashings.
## Note that this function mutates ``state``.
let
current_epoch = get_current_epoch(state)
active_validator_indices = get_active_validator_indices(
@ -999,40 +980,7 @@ func process_slashings(state: var BeaconState) =
min(total_penalties * 3, total_balance) div total_balance,
get_effective_balance(state, index.ValidatorIndex) div
MIN_PENALTY_QUOTIENT)
reduce_balance(state.balances[index], penalty)
func process_exit_queue(state: var BeaconState) =
## Process the exit queue.
## Note that this function mutates ``state``.
func eligible(index: ValidatorIndex): bool =
let validator = state.validator_registry[index]
# Filter out dequeued validators
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 +
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
var eligible_indices: seq[ValidatorIndex]
for vi in 0 ..< len(state.validator_registry):
if eligible(vi.ValidatorIndex):
eligible_indices.add vi.ValidatorIndex
let
## Sort in order of exit epoch, and validators that exit within the same
## epoch exit in order of validator index
sorted_indices = sorted(
eligible_indices,
func(x, y: ValidatorIndex): int =
system.cmp(
state.validator_registry[x].exit_epoch,
state.validator_registry[y].exit_epoch))
for dequeues, index in sorted_indices:
if dequeues >= MIN_PER_EPOCH_CHURN_LIMIT:
break
prepare_validator_for_withdrawal(state, index)
decrease_balance(state, index.ValidatorIndex, penalty)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#final-updates
func finish_epoch_update(state: var BeaconState) =
@ -1081,16 +1029,16 @@ func processEpoch(state: var BeaconState) =
(state.slot + 1) mod SLOTS_PER_EPOCH == 0):
return
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#justification
update_justification_and_finalization(state)
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#justification-and-finalization
process_justification_and_finalization(state)
var per_epoch_cache = get_empty_per_epoch_cache()
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#crosslinks
process_crosslinks(state, per_epoch_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#apply-rewards
apply_rewards(state, per_epoch_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#rewards-and-penalties
process_rewards_and_penalties(state, per_epoch_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#ejections
process_ejections(state)
@ -1101,7 +1049,6 @@ func processEpoch(state: var BeaconState) =
## Regardless of whether or not a validator set change happens run
## process_slashings(state) and process_exit_queue(state)
process_slashings(state)
process_exit_queue(state)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#final-updates
finish_epoch_update(state)
@ -1211,7 +1158,7 @@ proc skipSlots*(state: var BeaconState, slot: Slot,
# TODO hashed versions of above - not in spec
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#state-caching
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.2/specs/core/0_beacon-chain.md#state-caching
func cacheState(state: var HashedBeaconState) =
let previous_slot_state_root = state.root
@ -1367,7 +1314,7 @@ proc skipSlots*(state: var HashedBeaconState, slot: Slot,
# Dec 21 13:31
# how does that interact then with the following check:
# Verify that attestation.data.justified_block_root is equal to get_block_root(state, attestation.data.justified_slot).
# Verify that attestation.data.justified_block_root is equal to get_block_root_at_slot(state, attestation.data.justified_slot).
# Danny Ryan
# @djrtwo

View File

@ -52,7 +52,7 @@ type
LATEST_ACTIVE_INDEX_ROOTS_LENGTH*: int
LATEST_SLASHED_EXIT_LENGTH*: int
BASE_REWARD_QUOTIENT*: uint64
WHISTLEBLOWER_REWARD_QUOTIENT*: uint64
WHISTLEBLOWING_REWARD_QUOTIENT*: uint64
PROPOSER_REWARD_QUOTIENT*: uint64
INACTIVITY_PENALTY_QUOTIENT*: uint64
MIN_PENALTY_QUOTIENT*: int

View File

@ -80,7 +80,7 @@ suite "Official - State tests": # Initializing a beacon state from the deposits
# check:
# ok
# tcase.expected_state.eth1_data_votes.len == state.eth1_data_votes.len + 1
# get_block_root(tcase.expected_state, state.slot) == blck.previous_block_root
# get_block_root_at_slot(tcase.expected_state, state.slot) == blck.previous_block_root
suite "[For information - non-blocking] Extra state tests":
var initialState: BeaconState