proposed structure for altair (#2323)
* proposed structure for hf1 * refactor datatypes.nim into datatypes/{base, phase0, hf1}.nim * hf1 is Altair * some syncing with alpha 2 * adjust epoch processing to disambiguate access to RewardFlags * relocate StateData to stay consistent with meaning phase 0 StateData * passes v1.1.0 alpha 5 SSZ consensus object tests * Altair block header test fixtures work * fix slash_validator() so that Altair attester slashings, proposer slashings, and voluntary exit textures work * deposit operation Altair test fixtures work * slot sanity and all but a couple epoch transition tests switched to Altair * attestation Altair test fixtures work * Altair block sanity test fixtures work * add working altair sync committee tests * improve workarounds for sum-types-across-modules Nim bug; incorporate SignedBeaconBlock root reconstuction to SSZ byte reader
This commit is contained in:
parent
46c5a0110a
commit
c06ffc7804
|
@ -66,7 +66,6 @@ FixtureAll-mainnet
|
|||
+ [Invalid] Official - Sanity - Blocks - invalid_state_root [Preset: mainnet] OK
|
||||
+ [Invalid] Official - Sanity - Blocks - parent_from_same_slot [Preset: mainnet] OK
|
||||
+ [Invalid] Official - Sanity - Blocks - prev_slot_block_transition [Preset: mainnet] OK
|
||||
+ [Invalid] Official - Sanity - Blocks - proposal_for_genesis_slot [Preset: mainnet] OK
|
||||
+ [Invalid] Official - Sanity - Blocks - same_slot_block_transition [Preset: mainnet] OK
|
||||
+ [Invalid] Official - Sanity - Blocks - slash_and_exit_same_index [Preset: mainnet] OK
|
||||
+ [Invalid] Official - Sanity - Blocks - zero_block_sig [Preset: mainnet] OK
|
||||
|
@ -108,6 +107,9 @@ FixtureAll-mainnet
|
|||
+ [Invalid] invalid_sig_1_and_2_swap OK
|
||||
+ [Invalid] invalid_sig_2 OK
|
||||
+ [Invalid] invalid_signature OK
|
||||
+ [Invalid] invalid_signature_extra_participant OK
|
||||
+ [Invalid] invalid_signature_missing_participant OK
|
||||
+ [Invalid] invalid_signature_past_block OK
|
||||
+ [Invalid] invalid_slot_block_header OK
|
||||
+ [Invalid] mismatched_target_and_slot OK
|
||||
+ [Invalid] new_source_epoch OK
|
||||
|
@ -151,10 +153,6 @@ FixtureAll-mainnet
|
|||
+ [Valid] Official - Sanity - Blocks - deposit_top_up [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - empty_block_transition [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - empty_epoch_transition [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - full_random_operations_0 [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - full_random_operations_1 [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - full_random_operations_2 [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - full_random_operations_3 [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - high_proposer_index [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - historical_batch [Preset: mainnet] OK
|
||||
+ [Valid] Official - Sanity - Blocks - multiple_attester_slashings_no_overlap [Preset: mai OK
|
||||
|
@ -193,8 +191,11 @@ FixtureAll-mainnet
|
|||
+ [Valid] success_slashed_and_proposer_index_the_same OK
|
||||
+ [Valid] success_surround OK
|
||||
+ [Valid] success_with_effective_balance_disparity OK
|
||||
+ [Valid] sync_committee_rewards_duplicate_committee OK
|
||||
+ [Valid] sync_committee_rewards_empty_participants OK
|
||||
+ [Valid] sync_committee_rewards_not_full_participants OK
|
||||
```
|
||||
OK: 191/191 Fail: 0/191 Skip: 0/191
|
||||
OK: 192/192 Fail: 0/192 Skip: 0/192
|
||||
## Official - Epoch Processing - Effective balance updates [Preset: mainnet]
|
||||
```diff
|
||||
+ Effective balance updates - effective_balance_hysteresis [Preset: mainnet] OK
|
||||
|
@ -211,24 +212,6 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
|
|||
+ Historical roots update - historical_root_accumulator [Preset: mainnet] OK
|
||||
```
|
||||
OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||
## Official - Epoch Processing - Justification & Finalization [Preset: mainnet]
|
||||
```diff
|
||||
+ Justification & Finalization - 123_ok_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 123_poor_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 12_ok_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 12_ok_support_messed_target [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 12_poor_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 234_ok_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 234_poor_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 23_ok_support [Preset: mainnet] OK
|
||||
+ Justification & Finalization - 23_poor_support [Preset: mainnet] OK
|
||||
```
|
||||
OK: 9/9 Fail: 0/9 Skip: 0/9
|
||||
## Official - Epoch Processing - Participation record updates [Preset: mainnet]
|
||||
```diff
|
||||
+ Participation record updates - updated_participation_record [Preset: mainnet] OK
|
||||
```
|
||||
OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||
## Official - Epoch Processing - RANDAO mixes reset [Preset: mainnet]
|
||||
```diff
|
||||
+ RANDAO mixes reset - updated_randao_mixes [Preset: mainnet] OK
|
||||
|
@ -246,14 +229,6 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
|||
+ Registry updates - ejection_past_churn_limit [Preset: mainnet] OK
|
||||
```
|
||||
OK: 8/8 Fail: 0/8 Skip: 0/8
|
||||
## Official - Epoch Processing - Slashings [Preset: mainnet]
|
||||
```diff
|
||||
+ Slashings - low_penalty [Preset: mainnet] OK
|
||||
+ Slashings - max_penalties [Preset: mainnet] OK
|
||||
+ Slashings - minimal_penalty [Preset: mainnet] OK
|
||||
+ Slashings - scaled_penalties [Preset: mainnet] OK
|
||||
```
|
||||
OK: 4/4 Fail: 0/4 Skip: 0/4
|
||||
## Official - Epoch Processing - Slashings reset [Preset: mainnet]
|
||||
```diff
|
||||
+ Slashings reset - flush_slashings [Preset: mainnet] OK
|
||||
|
@ -261,4 +236,4 @@ OK: 4/4 Fail: 0/4 Skip: 0/4
|
|||
OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||
|
||||
---TOTAL---
|
||||
OK: 219/219 Fail: 0/219 Skip: 0/219
|
||||
OK: 206/206 Fail: 0/206 Skip: 0/206
|
||||
|
|
|
@ -11,6 +11,7 @@ FixtureSSZConsensus-mainnet
|
|||
+ Testing BeaconBlockHeader OK
|
||||
+ Testing BeaconState OK
|
||||
+ Testing Checkpoint OK
|
||||
+ Testing ContributionAndProof OK
|
||||
+ Testing Deposit OK
|
||||
+ Testing DepositData OK
|
||||
+ Testing DepositMessage OK
|
||||
|
@ -20,17 +21,25 @@ FixtureSSZConsensus-mainnet
|
|||
+ Testing ForkData OK
|
||||
+ Testing HistoricalBatch OK
|
||||
+ Testing IndexedAttestation OK
|
||||
+ Testing LightClientSnapshot OK
|
||||
+ Testing LightClientUpdate OK
|
||||
+ Testing PendingAttestation OK
|
||||
+ Testing ProposerSlashing OK
|
||||
+ Testing SignedAggregateAndProof OK
|
||||
+ Testing SignedBeaconBlock OK
|
||||
+ Testing SignedBeaconBlockHeader OK
|
||||
+ Testing SignedContributionAndProof OK
|
||||
+ Testing SignedVoluntaryExit OK
|
||||
+ Testing SigningData OK
|
||||
+ Testing SyncAggregate OK
|
||||
+ Testing SyncAggregatorSelectionData OK
|
||||
+ Testing SyncCommittee OK
|
||||
+ Testing SyncCommitteeContribution OK
|
||||
+ Testing SyncCommitteeSignature OK
|
||||
+ Testing Validator OK
|
||||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 27/27 Fail: 0/27 Skip: 0/27
|
||||
OK: 36/36 Fail: 0/36 Skip: 0/36
|
||||
|
||||
---TOTAL---
|
||||
OK: 27/27 Fail: 0/27 Skip: 0/27
|
||||
OK: 36/36 Fail: 0/36 Skip: 0/36
|
||||
|
|
|
@ -13,9 +13,11 @@ import
|
|||
json_serialization/std/sets,
|
||||
chronicles,
|
||||
../extras, ../ssz/merkleization,
|
||||
./crypto, ./datatypes, ./digest, ./helpers, ./signatures, ./validator,
|
||||
./crypto, ./datatypes/[phase0, altair], ./digest, ./helpers, ./signatures, ./validator,
|
||||
../../nbench/bench_lab
|
||||
|
||||
import blscurve # TODO bad
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#is_valid_merkle_branch
|
||||
func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openArray[Eth2Digest],
|
||||
depth: int, index: uint64,
|
||||
|
@ -41,7 +43,7 @@ func increase_balance*(balance: var Gwei, delta: Gwei) =
|
|||
balance += delta
|
||||
|
||||
func increase_balance*(
|
||||
state: var BeaconState, index: ValidatorIndex, delta: Gwei) =
|
||||
state: var SomeBeaconState, index: ValidatorIndex, delta: Gwei) =
|
||||
## Increase the validator balance at index ``index`` by ``delta``.
|
||||
if delta != 0: # avoid dirtying the balance cache if not needed
|
||||
increase_balance(state.balances[index], delta)
|
||||
|
@ -55,13 +57,14 @@ func decrease_balance*(balance: var Gwei, delta: Gwei) =
|
|||
balance - delta
|
||||
|
||||
func decrease_balance*(
|
||||
state: var BeaconState, index: ValidatorIndex, delta: Gwei) =
|
||||
state: var SomeBeaconState, index: ValidatorIndex, delta: Gwei) =
|
||||
## Decrease the validator balance at index ``index`` by ``delta``, with
|
||||
## underflow protection.
|
||||
if delta != 0: # avoid dirtying the balance cache if not needed
|
||||
decrease_balance(state.balances[index], delta)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#deposits
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#modified-process_deposit
|
||||
func get_validator_from_deposit(deposit: DepositData):
|
||||
Validator =
|
||||
let
|
||||
|
@ -80,7 +83,7 @@ func get_validator_from_deposit(deposit: DepositData):
|
|||
)
|
||||
|
||||
proc process_deposit*(preset: RuntimePreset,
|
||||
state: var BeaconState,
|
||||
state: var SomeBeaconState,
|
||||
deposit: Deposit,
|
||||
flags: UpdateFlags = {}): Result[void, cstring] {.nbench.}=
|
||||
## Process an Eth1 deposit, registering a validator or increasing its balance.
|
||||
|
@ -128,6 +131,14 @@ proc process_deposit*(preset: RuntimePreset,
|
|||
static: doAssert state.balances.maxLen == state.validators.maxLen
|
||||
raiseAssert "adding validator succeeded, so should balances"
|
||||
|
||||
when state is altair.BeaconState:
|
||||
if not state.previous_epoch_participation.add(ParticipationFlags(0)):
|
||||
return err("process_deposit: too many validators (previous_epoch_participation)")
|
||||
if not state.current_epoch_participation.add(ParticipationFlags(0)):
|
||||
return err("process_deposit: too many validators (current_epoch_participation)")
|
||||
if not state.inactivity_scores.add(0'u64):
|
||||
return err("process_deposit: too many validators (inactivity_scores)")
|
||||
|
||||
doAssert state.validators.len == state.balances.len
|
||||
else:
|
||||
# Deposits may come with invalid signatures - in that case, they are not
|
||||
|
@ -145,7 +156,8 @@ func compute_activation_exit_epoch(epoch: Epoch): Epoch =
|
|||
epoch + 1 + MAX_SEED_LOOKAHEAD
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_validator_churn_limit
|
||||
func get_validator_churn_limit(state: BeaconState, cache: var StateCache): uint64 =
|
||||
func get_validator_churn_limit(state: SomeBeaconState, cache: var StateCache):
|
||||
uint64 =
|
||||
## Return the validator churn limit for the current epoch.
|
||||
max(
|
||||
MIN_PER_EPOCH_CHURN_LIMIT,
|
||||
|
@ -153,7 +165,7 @@ func get_validator_churn_limit(state: BeaconState, cache: var StateCache): uint6
|
|||
state, state.get_current_epoch(), cache) div CHURN_LIMIT_QUOTIENT)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#initiate_validator_exit
|
||||
func initiate_validator_exit*(state: var BeaconState,
|
||||
func initiate_validator_exit*(state: var SomeBeaconState,
|
||||
index: ValidatorIndex, cache: var StateCache) =
|
||||
## Initiate the exit of the validator with index ``index``.
|
||||
|
||||
|
@ -193,7 +205,8 @@ func initiate_validator_exit*(state: var BeaconState,
|
|||
validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slash_validator
|
||||
proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#modified-slash_validator
|
||||
proc slash_validator*(state: var SomeBeaconState, slashed_index: ValidatorIndex,
|
||||
cache: var StateCache) =
|
||||
## Slash the validator with index ``index``.
|
||||
let epoch = get_current_epoch(state)
|
||||
|
@ -214,8 +227,17 @@ proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
|
|||
max(validator.withdrawable_epoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR)
|
||||
state.slashings[int(epoch mod EPOCHS_PER_SLASHINGS_VECTOR)] +=
|
||||
validator.effective_balance
|
||||
decrease_balance(state, slashed_index,
|
||||
validator.effective_balance div MIN_SLASHING_PENALTY_QUOTIENT)
|
||||
|
||||
# TODO Consider whether this is better than splitting the functions apart; in
|
||||
# each case, tradeoffs. Here, it's just changing a couple of constants.
|
||||
when state is phase0.BeaconState:
|
||||
decrease_balance(state, slashed_index,
|
||||
validator.effective_balance div MIN_SLASHING_PENALTY_QUOTIENT)
|
||||
elif state is altair.BeaconState:
|
||||
decrease_balance(state, slashed_index,
|
||||
validator.effective_balance div MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR)
|
||||
else:
|
||||
raiseAssert "invalid BeaconState type"
|
||||
|
||||
# The rest doesn't make sense without there being any proposer index, so skip
|
||||
let proposer_index = get_beacon_proposer_index(state, cache)
|
||||
|
@ -227,14 +249,21 @@ proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
|
|||
let
|
||||
# Spec has whistleblower_index as optional param, but it's never used.
|
||||
whistleblower_index = proposer_index.get
|
||||
whistleblowing_reward =
|
||||
whistleblower_reward =
|
||||
(validator.effective_balance div WHISTLEBLOWER_REWARD_QUOTIENT).Gwei
|
||||
proposer_reward = whistleblowing_reward div PROPOSER_REWARD_QUOTIENT
|
||||
proposer_reward =
|
||||
when state is phase0.BeaconState:
|
||||
whistleblower_reward div PROPOSER_REWARD_QUOTIENT
|
||||
elif state is altair.BeaconState:
|
||||
whistleblower_reward * PROPOSER_WEIGHT div WEIGHT_DENOMINATOR
|
||||
else:
|
||||
raiseAssert "invalid BeaconState type"
|
||||
|
||||
increase_balance(state, proposer_index.get, proposer_reward)
|
||||
# TODO: evaluate if spec bug / underflow can be triggered
|
||||
doAssert(whistleblowing_reward >= proposer_reward, "Spec bug: underflow in slash_validator")
|
||||
doAssert(whistleblower_reward >= proposer_reward, "Spec bug: underflow in slash_validator")
|
||||
increase_balance(
|
||||
state, whistleblower_index, whistleblowing_reward - proposer_reward)
|
||||
state, whistleblower_index, whistleblower_reward - proposer_reward)
|
||||
|
||||
func genesis_time_from_eth1_timestamp*(preset: RuntimePreset, eth1_timestamp: uint64): uint64 =
|
||||
eth1_timestamp + preset.GENESIS_DELAY
|
||||
|
@ -245,7 +274,7 @@ proc initialize_beacon_state_from_eth1*(
|
|||
eth1_block_hash: Eth2Digest,
|
||||
eth1_timestamp: uint64,
|
||||
deposits: openArray[DepositData],
|
||||
flags: UpdateFlags = {}): BeaconStateRef {.nbench.} =
|
||||
flags: UpdateFlags = {}): phase0.BeaconStateRef {.nbench.} =
|
||||
## Get the genesis ``BeaconState``.
|
||||
##
|
||||
## Before the beacon chain starts, validators will register in the Eth1 chain
|
||||
|
@ -262,7 +291,7 @@ proc initialize_beacon_state_from_eth1*(
|
|||
# at that point :)
|
||||
doAssert deposits.lenu64 >= SLOTS_PER_EPOCH
|
||||
|
||||
var state = BeaconStateRef(
|
||||
var state = phase0.BeaconStateRef(
|
||||
fork: Fork(
|
||||
previous_version: preset.GENESIS_FORK_VERSION,
|
||||
current_version: preset.GENESIS_FORK_VERSION,
|
||||
|
@ -272,7 +301,7 @@ proc initialize_beacon_state_from_eth1*(
|
|||
Eth1Data(block_hash: eth1_block_hash, deposit_count: uint64(len(deposits))),
|
||||
latest_block_header:
|
||||
BeaconBlockHeader(
|
||||
body_root: hash_tree_root(BeaconBlockBody())))
|
||||
body_root: hash_tree_root(default(phase0.BeaconBlockBody))))
|
||||
|
||||
# Seed RANDAO with Eth1 entropy
|
||||
state.randao_mixes.fill(eth1_block_hash)
|
||||
|
@ -334,23 +363,26 @@ proc initialize_hashed_beacon_state_from_eth1*(
|
|||
eth1_block_hash: Eth2Digest,
|
||||
eth1_timestamp: uint64,
|
||||
deposits: openArray[DepositData],
|
||||
flags: UpdateFlags = {}): HashedBeaconState =
|
||||
flags: UpdateFlags = {}): phase0.HashedBeaconState =
|
||||
let genesisState = initialize_beacon_state_from_eth1(
|
||||
preset, eth1_block_hash, eth1_timestamp, deposits, flags)
|
||||
HashedBeaconState(data: genesisState[], root: hash_tree_root(genesisState[]))
|
||||
phase0.HashedBeaconState(
|
||||
data: genesisState[], root: hash_tree_root(genesisState[]))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#genesis-block
|
||||
func get_initial_beacon_block*(state: BeaconState): TrustedSignedBeaconBlock =
|
||||
func get_initial_beacon_block*(state: phase0.BeaconState):
|
||||
phase0.TrustedSignedBeaconBlock =
|
||||
# The genesis block is implicitly trusted
|
||||
let message = TrustedBeaconBlock(
|
||||
let message = phase0.TrustedBeaconBlock(
|
||||
slot: state.slot,
|
||||
state_root: hash_tree_root(state),)
|
||||
# parent_root, randao_reveal, eth1_data, signature, and body automatically
|
||||
# initialized to default values.
|
||||
TrustedSignedBeaconBlock(message: message, root: hash_tree_root(message))
|
||||
phase0.TrustedSignedBeaconBlock(
|
||||
message: message, root: hash_tree_root(message))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_block_root_at_slot
|
||||
func get_block_root_at_slot*(state: BeaconState,
|
||||
func get_block_root_at_slot*(state: SomeBeaconState,
|
||||
slot: Slot): Eth2Digest =
|
||||
## Return the block root at a recent ``slot``.
|
||||
|
||||
|
@ -363,12 +395,12 @@ func get_block_root_at_slot*(state: BeaconState,
|
|||
state.block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_block_root
|
||||
func get_block_root*(state: BeaconState, epoch: Epoch): Eth2Digest =
|
||||
func get_block_root*(state: SomeBeaconState, epoch: Epoch): Eth2Digest =
|
||||
## Return the block root at the start of a recent ``epoch``.
|
||||
get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_total_balance
|
||||
func get_total_balance*(state: BeaconState, validators: auto): Gwei =
|
||||
func get_total_balance*(state: SomeBeaconState, validators: auto): Gwei =
|
||||
## Return the combined effective balance of the ``indices``.
|
||||
## ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
|
||||
## Math safe up to ~10B ETH, afterwhich this overflows uint64.
|
||||
|
@ -383,7 +415,7 @@ func is_eligible_for_activation_queue(validator: Validator): bool =
|
|||
validator.effective_balance == MAX_EFFECTIVE_BALANCE
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#is_eligible_for_activation
|
||||
func is_eligible_for_activation(state: BeaconState, validator: Validator):
|
||||
func is_eligible_for_activation(state: SomeBeaconState, validator: Validator):
|
||||
bool =
|
||||
## Check if ``validator`` is eligible for activation.
|
||||
|
||||
|
@ -393,7 +425,7 @@ func is_eligible_for_activation(state: BeaconState, validator: Validator):
|
|||
validator.activation_epoch == FAR_FUTURE_EPOCH
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#registry-updates
|
||||
proc process_registry_updates*(state: var BeaconState,
|
||||
proc process_registry_updates*(state: var SomeBeaconState,
|
||||
cache: var StateCache) {.nbench.} =
|
||||
## Process activation eligibility and ejections
|
||||
|
||||
|
@ -444,7 +476,7 @@ proc process_registry_updates*(state: var BeaconState,
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#is_valid_indexed_attestation
|
||||
proc is_valid_indexed_attestation*(
|
||||
state: BeaconState, indexed_attestation: SomeIndexedAttestation,
|
||||
state: SomeBeaconState, indexed_attestation: SomeIndexedAttestation,
|
||||
flags: UpdateFlags): Result[void, cstring] =
|
||||
## Check if ``indexed_attestation`` is not empty, has sorted and unique
|
||||
## indices and has a valid aggregate signature.
|
||||
|
@ -481,7 +513,7 @@ proc is_valid_indexed_attestation*(
|
|||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_attesting_indices
|
||||
iterator get_attesting_indices*(state: BeaconState,
|
||||
iterator get_attesting_indices*(state: SomeBeaconState,
|
||||
data: AttestationData,
|
||||
bits: CommitteeValidatorsBits,
|
||||
cache: var StateCache): ValidatorIndex =
|
||||
|
@ -498,7 +530,7 @@ iterator get_attesting_indices*(state: BeaconState,
|
|||
inc i
|
||||
|
||||
proc is_valid_indexed_attestation*(
|
||||
state: BeaconState, attestation: SomeAttestation, flags: UpdateFlags,
|
||||
state: SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] =
|
||||
# This is a variation on `is_valid_indexed_attestation` that works directly
|
||||
# with an attestation instead of first constructing an `IndexedAttestation`
|
||||
|
@ -567,9 +599,71 @@ func check_attestation_index(
|
|||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_attestation_participation_flag_indices
|
||||
func get_attestation_participation_flag_indices(state: altair.BeaconState,
|
||||
data: AttestationData,
|
||||
inclusion_delay: uint64): seq[int] =
|
||||
## Return the flag indices that are satisfied by an attestation.
|
||||
let justified_checkpoint =
|
||||
if data.target.epoch == get_current_epoch(state):
|
||||
state.current_justified_checkpoint
|
||||
else:
|
||||
state.previous_justified_checkpoint
|
||||
|
||||
# Matching roots
|
||||
let
|
||||
is_matching_source = data.source == justified_checkpoint
|
||||
is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch)
|
||||
is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(state, data.slot)
|
||||
|
||||
# TODO probably this needs to be robustly failable
|
||||
doAssert is_matching_source
|
||||
|
||||
var participation_flag_indices: seq[int]
|
||||
if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH):
|
||||
participation_flag_indices.add(TIMELY_SOURCE_FLAG_INDEX)
|
||||
if is_matching_target and inclusion_delay <= SLOTS_PER_EPOCH:
|
||||
participation_flag_indices.add(TIMELY_TARGET_FLAG_INDEX)
|
||||
if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY:
|
||||
participation_flag_indices.add(TIMELY_HEAD_FLAG_INDEX)
|
||||
|
||||
participation_flag_indices
|
||||
|
||||
# TODO these aren't great here
|
||||
# TODO these duplicate some stuff in state_transition_epoch which uses TotalBalances
|
||||
# better to centralize around that if feasible
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_total_active_balance
|
||||
func get_total_active_balance*(state: SomeBeaconState, cache: var StateCache): Gwei =
|
||||
## Return the combined effective balance of the active validators.
|
||||
# Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei
|
||||
# minimum to avoid divisions by zero.
|
||||
|
||||
let epoch = state.get_current_epoch()
|
||||
|
||||
get_total_balance(
|
||||
state, cache.get_shuffled_active_validator_indices(state, epoch))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_base_reward_per_increment
|
||||
func get_base_reward_per_increment*(state: altair.BeaconState, cache: var StateCache): Gwei =
|
||||
EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR div
|
||||
integer_squareroot(get_total_active_balance(state, cache))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_base_reward
|
||||
func get_base_reward(state: altair.BeaconState, index: ValidatorIndex, cache: var StateCache): Gwei =
|
||||
## Return the base reward for the validator defined by ``index`` with respect to the current ``state``.
|
||||
|
||||
# Note: An optimally performing validator can earn one base reward per
|
||||
# epoch over a long time horizon. This takes into account both per-epoch
|
||||
# (e.g. attestation) and intermittent duties (e.g. block proposal and sync
|
||||
# committees).
|
||||
let increments =
|
||||
state.validators[index].effective_balance div EFFECTIVE_BALANCE_INCREMENT
|
||||
increments * get_base_reward_per_increment(state, cache)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#attestations
|
||||
proc check_attestation*(
|
||||
state: BeaconState, attestation: SomeAttestation, flags: UpdateFlags,
|
||||
state: SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] =
|
||||
## 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
|
||||
|
@ -603,7 +697,7 @@ proc check_attestation*(
|
|||
ok()
|
||||
|
||||
proc process_attestation*(
|
||||
state: var BeaconState, attestation: SomeAttestation, flags: UpdateFlags,
|
||||
state: var SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
||||
# In the spec, attestation validation is mixed with state mutation, so here
|
||||
# we've split it into two functions so that the validation logic can be
|
||||
|
@ -615,6 +709,11 @@ proc process_attestation*(
|
|||
|
||||
? check_attestation(state, attestation, flags, cache)
|
||||
|
||||
# TODO this should be split between two functions, but causes type errors
|
||||
# in state_transition_block.process_operations()
|
||||
# TODO investigate and, if real, file Nim bug
|
||||
|
||||
# For phase0
|
||||
template addPendingAttestation(attestations: typed) =
|
||||
# The genericSeqAssign generated by the compiler to copy the attestation
|
||||
# data sadly is a processing hotspot - the business with the addDefault
|
||||
|
@ -627,9 +726,172 @@ proc process_attestation*(
|
|||
pa[].inclusion_delay = state.slot - attestation.data.slot
|
||||
pa[].proposer_index = proposer_index.get().uint64
|
||||
|
||||
if attestation.data.target.epoch == get_current_epoch(state):
|
||||
addPendingAttestation(state.current_epoch_attestations)
|
||||
# For Altair
|
||||
template updateParticipationFlags(epoch_participation: untyped) =
|
||||
var proposer_reward_numerator = 0'u64
|
||||
|
||||
# Participation flag indices
|
||||
let participation_flag_indices = get_attestation_participation_flag_indices(state, attestation.data, state.slot - attestation.data.slot)
|
||||
|
||||
for index in get_attesting_indices(state, attestation.data, attestation.aggregation_bits, cache):
|
||||
for flag_index, weight in PARTICIPATION_FLAG_WEIGHTS:
|
||||
if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
|
||||
epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||
proposer_reward_numerator += get_base_reward(state, index, cache) * weight.uint64 # these are all valid, #TODO statically verify or do it type-safely
|
||||
|
||||
# Reward proposer
|
||||
let
|
||||
# TODO use correct type at source
|
||||
proposer_reward_denominator = (WEIGHT_DENOMINATOR.uint64 - PROPOSER_WEIGHT.uint64) * WEIGHT_DENOMINATOR.uint64 div PROPOSER_WEIGHT.uint64
|
||||
proposer_reward = Gwei(proposer_reward_numerator div proposer_reward_denominator)
|
||||
increase_balance(state, proposer_index.get, proposer_reward)
|
||||
|
||||
when state is phase0.BeaconState:
|
||||
if attestation.data.target.epoch == get_current_epoch(state):
|
||||
addPendingAttestation(state.current_epoch_attestations)
|
||||
else:
|
||||
addPendingAttestation(state.previous_epoch_attestations)
|
||||
elif state is altair.BeaconState:
|
||||
if attestation.data.target.epoch == get_current_epoch(state):
|
||||
updateParticipationFlags(state.current_epoch_participation)
|
||||
else:
|
||||
updateParticipationFlags(state.previous_epoch_participation)
|
||||
else:
|
||||
addPendingAttestation(state.previous_epoch_attestations)
|
||||
static: doAssert false
|
||||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.3/specs/altair/fork.md#upgrading-the-state
|
||||
func upgrade_to_altair(pre: phase0.BeaconState): altair.BeaconState =
|
||||
let epoch = get_current_epoch(pre)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.3/specs/altair/fork.md#configuration
|
||||
const ALTAIR_FORK_VERSION = Version [byte 1, 0, 0, 0]
|
||||
|
||||
var empty_participation =
|
||||
HashList[ParticipationFlags, Limit VALIDATOR_REGISTRY_LIMIT]()
|
||||
for _ in 0 ..< len(pre.validators):
|
||||
doAssert empty_participation.add 0.ParticipationFlags
|
||||
|
||||
altair.BeaconState(
|
||||
genesis_time: pre.genesis_time,
|
||||
genesis_validators_root: pre.genesis_validators_root,
|
||||
slot: pre.slot,
|
||||
fork: Fork(
|
||||
previous_version: pre.fork.current_version,
|
||||
current_version: ALTAIR_FORK_VERSION,
|
||||
epoch: epoch
|
||||
),
|
||||
|
||||
# History
|
||||
latest_block_header: pre.latest_block_header,
|
||||
block_roots: pre.block_roots,
|
||||
state_roots: pre.state_roots,
|
||||
historical_roots: pre.historical_roots,
|
||||
|
||||
# Eth1
|
||||
eth1_data: pre.eth1_data,
|
||||
eth1_data_votes: pre.eth1_data_votes,
|
||||
eth1_deposit_index: pre.eth1_deposit_index,
|
||||
|
||||
# Registry
|
||||
validators: pre.validators,
|
||||
balances: pre.balances,
|
||||
|
||||
# Randomness
|
||||
randao_mixes: pre.randao_mixes,
|
||||
|
||||
# Slashings
|
||||
slashings: pre.slashings,
|
||||
|
||||
# Attestations
|
||||
previous_epoch_participation: empty_participation,
|
||||
current_epoch_participation: empty_participation,
|
||||
|
||||
# Finality
|
||||
justification_bits: pre.justification_bits,
|
||||
previous_justified_checkpoint: pre.previous_justified_checkpoint,
|
||||
current_justified_checkpoint: pre.current_justified_checkpoint,
|
||||
finalized_checkpoint: pre.finalized_checkpoint
|
||||
)
|
||||
|
||||
#TODO
|
||||
# Fill in sync committees
|
||||
#post.current_sync_committee = get_sync_committee(post, get_current_epoch(post))
|
||||
#post.next_sync_committee = get_sync_committee(post, get_current_epoch(post) + EPOCHS_PER_SYNC_COMMITTEE_PERIOD)
|
||||
#post
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_next_sync_committee_indices
|
||||
func get_next_sync_committee_indices(state: altair.BeaconState): seq[ValidatorIndex] =
|
||||
## Return the sequence of sync committee indices (which may include
|
||||
## duplicate indices) for the next sync committee, given a ``state`` at a
|
||||
## sync committee period boundary.
|
||||
|
||||
# Note: Committee can contain duplicate indices for small validator sets
|
||||
# (< SYNC_COMMITTEE_SIZE + 128)
|
||||
let epoch = Epoch(get_current_epoch(state) + 1)
|
||||
|
||||
const MAX_RANDOM_BYTE = 255
|
||||
let
|
||||
active_validator_indices = get_active_validator_indices(state, epoch)
|
||||
active_validator_count = uint64(len(active_validator_indices))
|
||||
seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
|
||||
var
|
||||
i = 0'u64
|
||||
sync_committee_indices: seq[ValidatorIndex]
|
||||
hash_buffer: array[40, byte]
|
||||
hash_buffer[0..31] = seed.data
|
||||
while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE:
|
||||
hash_buffer[32..39] = uint_to_bytes8(uint64(i div 32))
|
||||
let
|
||||
shuffled_index = compute_shuffled_index(uint64(i mod active_validator_count), active_validator_count, seed)
|
||||
candidate_index = active_validator_indices[shuffled_index]
|
||||
random_byte = eth2digest(hash_buffer).data[i mod 32]
|
||||
effective_balance = state.validators[candidate_index].effective_balance
|
||||
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
sync_committee_indices.add candidate_index
|
||||
i += 1'u64
|
||||
sync_committee_indices
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_next_sync_committee
|
||||
proc get_next_sync_committee*(state: altair.BeaconState): SyncCommittee =
|
||||
## Return the *next* sync committee for a given ``state``.
|
||||
#
|
||||
# ``SyncCommittee`` contains an aggregate pubkey that enables
|
||||
# resource-constrained clients to save some computation when verifying the
|
||||
# sync committee's signature.
|
||||
#
|
||||
# ``SyncCommittee`` can also contain duplicate pubkeys, when
|
||||
# ``get_next_sync_committee_indices`` returns duplicate indices.
|
||||
# Implementations must take care when handling optimizations relating to
|
||||
# aggregation and verification in the presence of duplicates.
|
||||
#
|
||||
# Note: This function should only be called at sync committee period
|
||||
# boundaries by ``process_sync_committee_updates`` as
|
||||
# ``get_next_sync_committee_indices`` is not stable within a given period.
|
||||
let
|
||||
indices = get_next_sync_committee_indices(state)
|
||||
pubkeys = mapIt(indices, state.validators[it].pubkey)
|
||||
|
||||
# see signatures_batch, TODO shouldn't be here
|
||||
var
|
||||
aggregate_pubkey: blscurve.PublicKey
|
||||
attestersAgg: AggregatePublicKey
|
||||
let ck = pubkeys[0].loadWithCache()
|
||||
if ck.isNone:
|
||||
attestersAgg.init(ck.get)
|
||||
for i in 1 ..< pubkeys.len:
|
||||
let cookedKey = pubkeys[i].loadWithCache()
|
||||
if cookedKey.isNone():
|
||||
# TODO is this the correct failure handling?
|
||||
continue
|
||||
attestersAgg.aggregate(cookedKey.get)
|
||||
aggregate_pubkey.finish(attestersAgg)
|
||||
|
||||
var res = SyncCommittee(aggregate_pubkey: ValidatorPubKey(blob: aggregate_pubkey.exportRaw()))
|
||||
doAssert indices.len == SYNC_COMMITTEE_SIZE # needs to fill vector exactly
|
||||
doAssert pubkeys.len == SYNC_COMMITTEE_SIZE
|
||||
for i in 0 ..< SYNC_COMMITTEE_SIZE:
|
||||
# obviously ineffecient
|
||||
res.pubkeys[i] = pubkeys[i]
|
||||
res
|
||||
|
|
|
@ -24,29 +24,47 @@
|
|||
|
||||
{.push raises: [Defect].}
|
||||
|
||||
# std/[intsets, json, strutils, tables],
|
||||
# stew/byteutils,
|
||||
|
||||
import
|
||||
chronicles,
|
||||
std/macros,
|
||||
stew/assign2,
|
||||
stew/[assign2, bitops2],
|
||||
json_serialization/types as jsonTypes,
|
||||
../../ssz/types as sszTypes, ../crypto, ../digest, ../presets
|
||||
|
||||
import ./base
|
||||
import ./base, ./phase0
|
||||
export base
|
||||
|
||||
const
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#incentivization-weights
|
||||
TIMELY_HEAD_WEIGHT* = 12
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#incentivization-weights
|
||||
TIMELY_SOURCE_WEIGHT* = 12
|
||||
TIMELY_TARGET_WEIGHT* = 24
|
||||
TIMELY_HEAD_WEIGHT* = 12
|
||||
SYNC_REWARD_WEIGHT* = 8
|
||||
PROPOSER_WEIGHT* = 8
|
||||
WEIGHT_DENOMINATOR* = 64
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/validator.md#misc
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/validator.md#misc
|
||||
TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE* = 4
|
||||
SYNC_COMMITTEE_SUBNET_COUNT* = 8
|
||||
SYNC_COMMITTEE_SUBNET_COUNT* = 4
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/setup.py#L470
|
||||
FINALIZED_ROOT_INDEX* = 105'u16
|
||||
NEXT_SYNC_COMMITTEE_INDEX* = 55'u16
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#participation-flag-indices
|
||||
TIMELY_SOURCE_FLAG_INDEX* = 0
|
||||
TIMELY_TARGET_FLAG_INDEX* = 1
|
||||
TIMELY_HEAD_FLAG_INDEX* = 2
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#inactivity-penalties
|
||||
#INACTIVITY_SCORE_BIAS* = 4
|
||||
INACTIVITY_SCORE_RECOVERY_RATE* = 16
|
||||
|
||||
let
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#misc
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#misc
|
||||
# Cannot be computed at compile-time due to importc dependency
|
||||
G2_POINT_AT_INFINITY* = ValidatorSig.fromRaw([
|
||||
0xc0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -55,24 +73,26 @@ let
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0])
|
||||
|
||||
PARTICIPATION_FLAG_WEIGHTS* =
|
||||
[TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_WEIGHT, TIMELY_HEAD_WEIGHT]
|
||||
type
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#custom-types
|
||||
ParticipationFlags* = distinct uint8
|
||||
### New types
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#syncaggregate
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#custom-types
|
||||
# TODO could be distinct
|
||||
ParticipationFlags* = uint8
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#syncaggregate
|
||||
SyncAggregate* = object
|
||||
sync_committee_bits*: BitArray[SYNC_COMMITTEE_SIZE]
|
||||
sync_committee_signature*: ValidatorSig
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#synccommittee
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#synccommittee
|
||||
SyncCommittee* = object
|
||||
pubkeys*: HashArray[Limit SYNC_COMMITTEE_SIZE, ValidatorPubKey]
|
||||
pubkey_aggregates*:
|
||||
HashArray[
|
||||
Limit SYNC_COMMITTEE_SIZE div SYNC_PUBKEYS_PER_AGGREGATE,
|
||||
ValidatorPubKey]
|
||||
aggregate_pubkey*: ValidatorPubKey
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/validator.md#synccommitteesignature
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/validator.md#synccommitteesignature
|
||||
SyncCommitteeSignature* = object
|
||||
slot*: Slot ##\
|
||||
## Slot to which this contribution pertains
|
||||
|
@ -86,7 +106,7 @@ type
|
|||
signature*: ValidatorSig ##\
|
||||
## Signature by the validator over the block root of `slot`
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/validator.md#synccommitteecontribution
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/validator.md#synccommitteecontribution
|
||||
SyncCommitteeContribution* = object
|
||||
slot*: Slot ##\
|
||||
## Slot to which this contribution pertains
|
||||
|
@ -106,30 +126,345 @@ type
|
|||
signature*: ValidatorSig ##\
|
||||
## Signature by the validator(s) over the block root of `slot`
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/validator.md#contributionandproof
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/validator.md#contributionandproof
|
||||
ContributionAndProof* = object
|
||||
aggregator_index*: uint64
|
||||
contribution*: SyncCommitteeContribution
|
||||
selection_proof*: ValidatorSig
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/validator.md#signedcontributionandproof
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/validator.md#signedcontributionandproof
|
||||
SignedContributionAndProof* = object
|
||||
message*: ContributionAndProof
|
||||
signature*: ValidatorSig
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/validator.md#synccommitteesigningdata
|
||||
SyncCommitteeSigningData* = object
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/validator.md#syncaggregatorselectiondata
|
||||
SyncAggregatorSelectionData* = object
|
||||
slot*: Slot
|
||||
subcommittee_index*: uint64
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#participation-flag-indices
|
||||
ParticipationFlag* = enum
|
||||
TIMELY_HEAD_FLAG_INDEX = 0
|
||||
TIMELY_SOURCE_FLAG_INDEX = 1
|
||||
TIMELY_TARGET_FLAG_INDEX = 2
|
||||
### Modified/overloaded
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/sync-protocol.md#lightclientsnapshot
|
||||
LightClientSnapshot* = object
|
||||
header*: BeaconBlockHeader ##\
|
||||
## Beacon block header
|
||||
|
||||
current_sync_committee*: SyncCommittee ##\
|
||||
## Sync committees corresponding to the header
|
||||
|
||||
next_sync_committee*: SyncCommittee
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/sync-protocol.md#lightclientupdate
|
||||
LightClientUpdate* = object
|
||||
header*: BeaconBlockHeader ##\
|
||||
## Update beacon block header
|
||||
|
||||
next_sync_committee*: SyncCommittee ##\
|
||||
## Next sync committee corresponding to the header
|
||||
|
||||
next_sync_committee_branch*: array[log2trunc(NEXT_SYNC_COMMITTEE_INDEX), Eth2Digest] ##\
|
||||
## Finality proof for the update header
|
||||
|
||||
finality_header*: BeaconBlockHeader
|
||||
finality_branch*: array[log2trunc(FINALIZED_ROOT_INDEX), Eth2Digest]
|
||||
|
||||
sync_committee_bits*: BitArray[SYNC_COMMITTEE_SIZE] ##\
|
||||
## Sync committee aggregate signature
|
||||
|
||||
sync_committee_signature*: ValidatorSig
|
||||
|
||||
fork_version*: Version ##\
|
||||
## Fork version for the aggregate signature
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#beaconstate
|
||||
BeaconState* = object
|
||||
# Versioning
|
||||
genesis_time*: uint64
|
||||
genesis_validators_root*: Eth2Digest
|
||||
slot*: Slot
|
||||
fork*: Fork
|
||||
|
||||
# History
|
||||
latest_block_header*: BeaconBlockHeader ##\
|
||||
## `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||
|
||||
block_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] ##\
|
||||
## Needed to process attestations, older to newer
|
||||
|
||||
state_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
|
||||
historical_roots*: HashList[Eth2Digest, Limit HISTORICAL_ROOTS_LIMIT]
|
||||
|
||||
# Eth1
|
||||
eth1_data*: Eth1Data
|
||||
eth1_data_votes*:
|
||||
HashList[Eth1Data, Limit(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)]
|
||||
eth1_deposit_index*: uint64
|
||||
|
||||
# Registry
|
||||
validators*: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
|
||||
# Randomness
|
||||
randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]
|
||||
|
||||
# Slashings
|
||||
slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] ##\
|
||||
## Per-epoch sums of slashed effective balances
|
||||
|
||||
# Participation
|
||||
previous_epoch_participation*:
|
||||
HashList[ParticipationFlags, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
current_epoch_participation*:
|
||||
HashList[ParticipationFlags, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
|
||||
# Finality
|
||||
justification_bits*: uint8 ##\
|
||||
## Bit set for every recent justified epoch
|
||||
## Model a Bitvector[4] as a one-byte uint, which should remain consistent
|
||||
## with ssz/hashing.
|
||||
|
||||
previous_justified_checkpoint*: Checkpoint ##\
|
||||
## Previous epoch snapshot
|
||||
|
||||
current_justified_checkpoint*: Checkpoint
|
||||
finalized_checkpoint*: Checkpoint
|
||||
|
||||
# Inactivity
|
||||
inactivity_scores*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT] # [New in Altair]
|
||||
|
||||
# Light client sync committees
|
||||
current_sync_committee*: SyncCommittee # [New in Altair]
|
||||
next_sync_committee*: SyncCommittee # [New in Altair]
|
||||
|
||||
# TODO Careful, not nil analysis is broken / incomplete and the semantics will
|
||||
# likely change in future versions of the language:
|
||||
# https://github.com/nim-lang/RFCs/issues/250
|
||||
BeaconStateRef* = ref BeaconState not nil
|
||||
NilableBeaconStateRef* = ref BeaconState
|
||||
|
||||
HashedBeaconState* = object
|
||||
data*: BeaconState
|
||||
root*: Eth2Digest # hash_tree_root(data)
|
||||
|
||||
# HF1 implies knowledge of phase 0, and this saves creating some other
|
||||
# module to merge such knowledge. Another approach is to have imported
|
||||
# set of phase 0/HF1 symbols be independently combined by each module,
|
||||
# when necessary, but that spreads such detailed abstraction knowledge
|
||||
# more widely through codebase than strictly required. Do not export a
|
||||
# phase 0 version of symbols; anywhere which specially handles it will
|
||||
# have to do so itself.
|
||||
SomeBeaconState* = BeaconState | phase0.BeaconState
|
||||
SomeHashedBeaconState* = HashedBeaconState | phase0.HashedBeaconState # probably not useful long-term,
|
||||
## since process_slots will need to be StateData
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/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
|
||||
## validators that will have a chance to vote on it through attestations.
|
||||
## Each block collects attestations, or votes, on past blocks, thus a chain
|
||||
## is formed.
|
||||
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
|
||||
parent_root*: Eth2Digest ##\
|
||||
## Root hash of the previous block
|
||||
|
||||
state_root*: Eth2Digest ##\
|
||||
## The state root, _after_ this block has been processed
|
||||
|
||||
body*: BeaconBlockBody
|
||||
|
||||
SigVerifiedBeaconBlock* = object
|
||||
## A BeaconBlock that contains verified signatures
|
||||
## but that has not been verified for state transition
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
|
||||
parent_root*: Eth2Digest ##\
|
||||
## Root hash of the previous block
|
||||
|
||||
state_root*: Eth2Digest ##\
|
||||
## The state root, _after_ this block has been processed
|
||||
|
||||
body*: SigVerifiedBeaconBlockBody
|
||||
|
||||
TrustedBeaconBlock* = object
|
||||
## When we receive blocks from outside sources, they are untrusted and go
|
||||
## through several layers of validation. Blocks that have gone through
|
||||
## validations can be trusted to be well-formed, with a correct signature,
|
||||
## having a parent and applying cleanly to the state that their parent
|
||||
## left them with.
|
||||
##
|
||||
## When loading such blocks from the database, to rewind states for example,
|
||||
## it is expensive to redo the validations (in particular, the signature
|
||||
## checks), thus `TrustedBlock` uses a `TrustedSig` type to mark that these
|
||||
## checks can be skipped.
|
||||
##
|
||||
## TODO this could probably be solved with some type trickery, but there
|
||||
## too many bugs in nim around generics handling, and we've used up
|
||||
## the trickery budget in the serialization library already. Until
|
||||
## then, the type must be manually kept compatible with its untrusted
|
||||
## cousin.
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
parent_root*: Eth2Digest ##\
|
||||
state_root*: Eth2Digest ##\
|
||||
body*: TrustedBeaconBlockBody
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#beaconblockbody
|
||||
BeaconBlockBody* = object
|
||||
randao_reveal*: ValidatorSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[Attestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
# [New in Altair]
|
||||
sync_aggregate*: SyncAggregate
|
||||
|
||||
SigVerifiedBeaconBlockBody* = object
|
||||
## A BeaconBlock body with signatures verified
|
||||
## including:
|
||||
## - Randao reveal
|
||||
## - Attestations
|
||||
## - ProposerSlashing (SignedBeaconBlockHeader)
|
||||
## - AttesterSlashing (IndexedAttestation)
|
||||
## - SignedVoluntaryExits
|
||||
##
|
||||
## - ETH1Data (Deposits) can contain invalid BLS signatures
|
||||
##
|
||||
## The block state transition has NOT been verified
|
||||
randao_reveal*: TrustedSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
# [New in Altair]
|
||||
sync_aggregate*: SyncAggregate
|
||||
|
||||
TrustedBeaconBlockBody* = object
|
||||
## A full verified block
|
||||
randao_reveal*: TrustedSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
# [New in Altair]
|
||||
sync_aggregate*: SyncAggregate
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/phase0/beacon-chain.md#signedbeaconblock
|
||||
SignedBeaconBlock* = object
|
||||
message*: BeaconBlock
|
||||
signature*: ValidatorSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
SigVerifiedSignedBeaconBlock* = object
|
||||
## A SignedBeaconBlock with signatures verified
|
||||
## including:
|
||||
## - Block signature
|
||||
## - BeaconBlockBody
|
||||
## - Randao reveal
|
||||
## - Attestations
|
||||
## - ProposerSlashing (SignedBeaconBlockHeader)
|
||||
## - AttesterSlashing (IndexedAttestation)
|
||||
## - SignedVoluntaryExits
|
||||
##
|
||||
## - ETH1Data (Deposits) can contain invalid BLS signatures
|
||||
##
|
||||
## The block state transition has NOT been verified
|
||||
message*: SigVerifiedBeaconBlock
|
||||
signature*: TrustedSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
TrustedSignedBeaconBlock* = object
|
||||
message*: TrustedBeaconBlock
|
||||
signature*: TrustedSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
SomeSignedBeaconBlock* = SignedBeaconBlock | SigVerifiedSignedBeaconBlock | TrustedSignedBeaconBlock
|
||||
SomeBeaconBlock* = BeaconBlock | SigVerifiedBeaconBlock | TrustedBeaconBlock
|
||||
SomeBeaconBlockBody* = BeaconBlockBody | SigVerifiedBeaconBlockBody | TrustedBeaconBlockBody
|
||||
|
||||
# TODO rename
|
||||
|
||||
# TODO why does this fail?
|
||||
#SomeSomeBeaconBlock* = SomeBeaconBlock | phase0.SomeBeaconBlock
|
||||
SomeSomeBeaconBlock* =
|
||||
BeaconBlock | SigVerifiedBeaconBlock | TrustedBeaconBlock |
|
||||
phase0.BeaconBlock | phase0.SigVerifiedBeaconBlock | phase0.TrustedBeaconBlock
|
||||
|
||||
# TODO see above, re why does it fail
|
||||
SomeSomeBeaconBlockBody* =
|
||||
BeaconBlockBody | SigVerifiedBeaconBlockBody | TrustedBeaconBlockBody |
|
||||
phase0.BeaconBlockBody | phase0.SigVerifiedBeaconBlockBody | phase0.TrustedBeaconBlockBody
|
||||
#SomeSomeBeaconBlockBody* = SomeBeaconBlockBody | phase0.SomeBeaconBlockBody
|
||||
|
||||
SomeSomeSignedBeaconBlock* = SomeSignedBeaconBlock | phase0.SomeSignedBeaconBlock
|
||||
|
||||
# TODO when https://github.com/nim-lang/Nim/issues/14440 lands in Status's Nim,
|
||||
# switch proc {.noSideEffect.} to func.
|
||||
proc `or`*(x, y: ParticipationFlags) : ParticipationFlags {.borrow, noSideEffect.}
|
||||
proc `and`*(x, y: ParticipationFlags) : ParticipationFlags {.borrow, noSideEffect.}
|
||||
proc `==`*(x, y: ParticipationFlags) : bool {.borrow, noSideEffect.}
|
||||
when false:
|
||||
# TODO if ParticipationFlags is distinct
|
||||
proc `or`*(x, y: ParticipationFlags) : ParticipationFlags {.borrow, noSideEffect.}
|
||||
proc `and`*(x, y: ParticipationFlags) : ParticipationFlags {.borrow, noSideEffect.}
|
||||
proc `==`*(x, y: ParticipationFlags) : bool {.borrow, noSideEffect.}
|
||||
|
||||
chronicles.formatIt BeaconBlock: it.shortLog
|
||||
|
||||
Json.useCustomSerialization(BeaconState.justification_bits):
|
||||
read:
|
||||
let s = reader.readValue(string)
|
||||
|
||||
if s.len != 4:
|
||||
raiseUnexpectedValue(reader, "A string with 4 characters expected")
|
||||
|
||||
try:
|
||||
s.parseHexInt.uint8
|
||||
except ValueError:
|
||||
raiseUnexpectedValue(reader, "The `justification_bits` value must be a hex string")
|
||||
|
||||
write:
|
||||
writer.writeValue "0x" & value.toHex
|
||||
|
||||
func shortLog*(v: SomeBeaconBlock): auto =
|
||||
(
|
||||
slot: shortLog(v.slot),
|
||||
proposer_index: v.proposer_index,
|
||||
parent_root: shortLog(v.parent_root),
|
||||
state_root: shortLog(v.state_root),
|
||||
eth1data: v.body.eth1_data,
|
||||
graffiti: $v.body.graffiti,
|
||||
proposer_slashings_len: v.body.proposer_slashings.len(),
|
||||
attester_slashings_len: v.body.attester_slashings.len(),
|
||||
attestations_len: v.body.attestations.len(),
|
||||
deposits_len: v.body.deposits.len(),
|
||||
voluntary_exits_len: v.body.voluntary_exits.len(),
|
||||
)
|
||||
|
||||
func shortLog*(v: SomeSignedBeaconBlock): auto =
|
||||
(
|
||||
blck: shortLog(v.message),
|
||||
signature: shortLog(v.signature)
|
||||
)
|
||||
|
|
|
@ -61,7 +61,7 @@ const
|
|||
|
||||
# Not part of spec. Still useful, pending removing usage if appropriate.
|
||||
ZERO_HASH* = Eth2Digest()
|
||||
MAX_GRAFFITI_SIZE = 32
|
||||
MAX_GRAFFITI_SIZE* = 32
|
||||
FAR_FUTURE_SLOT* = (not 0'u64).Slot
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/p2p-interface.md#configuration
|
||||
|
@ -264,129 +264,6 @@ type
|
|||
|
||||
validator_index*: uint64
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/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
|
||||
## validators that will have a chance to vote on it through attestations.
|
||||
## Each block collects attestations, or votes, on past blocks, thus a chain
|
||||
## is formed.
|
||||
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
|
||||
parent_root*: Eth2Digest ##\
|
||||
## Root hash of the previous block
|
||||
|
||||
state_root*: Eth2Digest ##\
|
||||
## The state root, _after_ this block has been processed
|
||||
|
||||
body*: BeaconBlockBody
|
||||
|
||||
SigVerifiedBeaconBlock* = object
|
||||
## A BeaconBlock that contains verified signatures
|
||||
## but that has not been verified for state transition
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
|
||||
parent_root*: Eth2Digest ##\
|
||||
## Root hash of the previous block
|
||||
|
||||
state_root*: Eth2Digest ##\
|
||||
## The state root, _after_ this block has been processed
|
||||
|
||||
body*: SigVerifiedBeaconBlockBody
|
||||
|
||||
TrustedBeaconBlock* = object
|
||||
## When we receive blocks from outside sources, they are untrusted and go
|
||||
## through several layers of validation. Blocks that have gone through
|
||||
## validations can be trusted to be well-formed, with a correct signature,
|
||||
## having a parent and applying cleanly to the state that their parent
|
||||
## left them with.
|
||||
##
|
||||
## When loading such blocks from the database, to rewind states for example,
|
||||
## it is expensive to redo the validations (in particular, the signature
|
||||
## checks), thus `TrustedBlock` uses a `TrustedSig` type to mark that these
|
||||
## checks can be skipped.
|
||||
##
|
||||
## TODO this could probably be solved with some type trickery, but there
|
||||
## too many bugs in nim around generics handling, and we've used up
|
||||
## the trickery budget in the serialization library already. Until
|
||||
## then, the type must be manually kept compatible with its untrusted
|
||||
## cousin.
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
parent_root*: Eth2Digest ##\
|
||||
state_root*: Eth2Digest ##\
|
||||
body*: TrustedBeaconBlockBody
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblockheader
|
||||
BeaconBlockHeader* = object
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
parent_root*: Eth2Digest
|
||||
state_root*: Eth2Digest
|
||||
body_root*: Eth2Digest
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#signingdata
|
||||
SigningData* = object
|
||||
object_root*: Eth2Digest
|
||||
domain*: Eth2Domain
|
||||
|
||||
GraffitiBytes* = distinct array[MAX_GRAFFITI_SIZE, byte]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblockbody
|
||||
BeaconBlockBody* = object
|
||||
randao_reveal*: ValidatorSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[Attestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
SigVerifiedBeaconBlockBody* = object
|
||||
## A BeaconBlock body with signatures verified
|
||||
## including:
|
||||
## - Randao reveal
|
||||
## - Attestations
|
||||
## - ProposerSlashing (SignedBeaconBlockHeader)
|
||||
## - AttesterSlashing (IndexedAttestation)
|
||||
## - SignedVoluntaryExits
|
||||
##
|
||||
## - ETH1Data (Deposits) can contain invalid BLS signatures
|
||||
##
|
||||
## The block state transition has NOT been verified
|
||||
randao_reveal*: TrustedSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
TrustedBeaconBlockBody* = object
|
||||
## A full verified block
|
||||
randao_reveal*: TrustedSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
SomeSignedBeaconBlock* = SignedBeaconBlock | SigVerifiedSignedBeaconBlock | TrustedSignedBeaconBlock
|
||||
SomeBeaconBlock* = BeaconBlock | SigVerifiedBeaconBlock | TrustedBeaconBlock
|
||||
SomeBeaconBlockBody* = BeaconBlockBody | SigVerifiedBeaconBlockBody | TrustedBeaconBlockBody
|
||||
SomeAttestation* = Attestation | TrustedAttestation
|
||||
SomeIndexedAttestation* = IndexedAttestation | TrustedIndexedAttestation
|
||||
SomeProposerSlashing* = ProposerSlashing | TrustedProposerSlashing
|
||||
|
@ -394,65 +271,6 @@ type
|
|||
SomeSignedBeaconBlockHeader* = SignedBeaconBlockHeader | TrustedSignedBeaconBlockHeader
|
||||
SomeSignedVoluntaryExit* = SignedVoluntaryExit | TrustedSignedVoluntaryExit
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconstate
|
||||
BeaconState* = object
|
||||
# Versioning
|
||||
genesis_time*: uint64
|
||||
genesis_validators_root*: Eth2Digest
|
||||
slot*: Slot
|
||||
fork*: Fork
|
||||
|
||||
# History
|
||||
latest_block_header*: BeaconBlockHeader ##\
|
||||
## `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||
|
||||
block_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] ##\
|
||||
## Needed to process attestations, older to newer
|
||||
|
||||
state_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
|
||||
historical_roots*: HashList[Eth2Digest, Limit HISTORICAL_ROOTS_LIMIT]
|
||||
|
||||
# Eth1
|
||||
eth1_data*: Eth1Data
|
||||
eth1_data_votes*:
|
||||
HashList[Eth1Data, Limit(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)]
|
||||
eth1_deposit_index*: uint64
|
||||
|
||||
# Registry
|
||||
validators*: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
|
||||
# Randomness
|
||||
randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]
|
||||
|
||||
# Slashings
|
||||
slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] ##\
|
||||
## Per-epoch sums of slashed effective balances
|
||||
|
||||
# Attestations
|
||||
previous_epoch_attestations*:
|
||||
HashList[PendingAttestation, Limit(MAX_ATTESTATIONS * SLOTS_PER_EPOCH)]
|
||||
current_epoch_attestations*:
|
||||
HashList[PendingAttestation, Limit(MAX_ATTESTATIONS * SLOTS_PER_EPOCH)]
|
||||
|
||||
# Finality
|
||||
justification_bits*: uint8 ##\
|
||||
## Bit set for every recent justified epoch
|
||||
## Model a Bitvector[4] as a one-byte uint, which should remain consistent
|
||||
## with ssz/hashing.
|
||||
|
||||
previous_justified_checkpoint*: Checkpoint ##\
|
||||
## Previous epoch snapshot
|
||||
|
||||
current_justified_checkpoint*: Checkpoint
|
||||
finalized_checkpoint*: Checkpoint
|
||||
|
||||
# TODO Careful, not nil analysis is broken / incomplete and the semantics will
|
||||
# likely change in future versions of the language:
|
||||
# https://github.com/nim-lang/RFCs/issues/250
|
||||
BeaconStateRef* = ref BeaconState not nil
|
||||
NilableBeaconStateRef* = ref BeaconState
|
||||
|
||||
# Please note that this type is not part of the spec
|
||||
ImmutableValidatorData* = object
|
||||
pubkey*: ValidatorPubKey
|
||||
|
@ -517,37 +335,20 @@ type
|
|||
message*: VoluntaryExit
|
||||
signature*: TrustedSig
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#signedbeaconblock
|
||||
SignedBeaconBlock* = object
|
||||
message*: BeaconBlock
|
||||
signature*: ValidatorSig
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblockheader
|
||||
BeaconBlockHeader* = object
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
parent_root*: Eth2Digest
|
||||
state_root*: Eth2Digest
|
||||
body_root*: Eth2Digest
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#signingdata
|
||||
SigningData* = object
|
||||
object_root*: Eth2Digest
|
||||
domain*: Eth2Domain
|
||||
|
||||
SigVerifiedSignedBeaconBlock* = object
|
||||
## A SignedBeaconBlock with signatures verified
|
||||
## including:
|
||||
## - Block signature
|
||||
## - BeaconBlockBody
|
||||
## - Randao reveal
|
||||
## - Attestations
|
||||
## - ProposerSlashing (SignedBeaconBlockHeader)
|
||||
## - AttesterSlashing (IndexedAttestation)
|
||||
## - SignedVoluntaryExits
|
||||
##
|
||||
## - ETH1Data (Deposits) can contain invalid BLS signatures
|
||||
##
|
||||
## The block state transition has NOT been verified
|
||||
message*: SigVerifiedBeaconBlock
|
||||
signature*: TrustedSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
TrustedSignedBeaconBlock* = object
|
||||
message*: TrustedBeaconBlock
|
||||
signature*: TrustedSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
GraffitiBytes* = distinct array[MAX_GRAFFITI_SIZE, byte]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#signedbeaconblockheader
|
||||
SignedBeaconBlockHeader* = object
|
||||
|
@ -569,10 +370,6 @@ type
|
|||
message*: AggregateAndProof
|
||||
signature*: ValidatorSig
|
||||
|
||||
HashedBeaconState* = object
|
||||
data*: BeaconState
|
||||
root*: Eth2Digest # hash_tree_root(data)
|
||||
|
||||
# This doesn't know about forks or branches in the DAG. It's for straight,
|
||||
# linear chunks of the chain.
|
||||
StateCache* = object
|
||||
|
@ -753,25 +550,6 @@ type
|
|||
statuses*: seq[RewardStatus]
|
||||
total_balances*: TotalBalances
|
||||
|
||||
BlockRef* = ref object
|
||||
## Node in object graph guaranteed to lead back to tail block, and to have
|
||||
## a corresponding entry in database.
|
||||
## Block graph should form a tree - in particular, there are no cycles.
|
||||
|
||||
root*: Eth2Digest ##\
|
||||
## Root that can be used to retrieve block data from database
|
||||
|
||||
parent*: BlockRef ##\
|
||||
## Not nil, except for the tail
|
||||
|
||||
slot*: Slot # could calculate this by walking to root, but..
|
||||
|
||||
StateData* = object
|
||||
data*: HashedBeaconState
|
||||
|
||||
blck*: BlockRef ##\
|
||||
## The block associated with the state found in data
|
||||
|
||||
func getImmutableValidatorData*(validator: Validator): ImmutableValidatorData =
|
||||
ImmutableValidatorData(
|
||||
pubkey: validator.pubkey,
|
||||
|
@ -894,6 +672,9 @@ static: doAssert high(int) >= high(int32)
|
|||
func `[]`*[T](a: var seq[T], b: ValidatorIndex): var T =
|
||||
a[b.int]
|
||||
|
||||
func `[]=`*[T](a: var seq[T], b: ValidatorIndex, c: T) =
|
||||
a[b.int] = c
|
||||
|
||||
func `[]`*[T](a: seq[T], b: ValidatorIndex): auto =
|
||||
a[b.int]
|
||||
|
||||
|
@ -928,21 +709,6 @@ func `as`*(d: DepositData, T: type DepositMessage): T =
|
|||
ethTimeUnit Slot
|
||||
ethTimeUnit Epoch
|
||||
|
||||
Json.useCustomSerialization(BeaconState.justification_bits):
|
||||
read:
|
||||
let s = reader.readValue(string)
|
||||
|
||||
if s.len != 4:
|
||||
raiseUnexpectedValue(reader, "A string with 4 characters expected")
|
||||
|
||||
try:
|
||||
s.parseHexInt.uint8
|
||||
except ValueError:
|
||||
raiseUnexpectedValue(reader, "The `justification_bits` value must be a hex string")
|
||||
|
||||
write:
|
||||
writer.writeValue "0x" & value.toHex
|
||||
|
||||
Json.useCustomSerialization(BitSeq):
|
||||
read:
|
||||
try:
|
||||
|
@ -1013,27 +779,6 @@ func shortLog*(s: Slot): uint64 =
|
|||
func shortLog*(e: Epoch): uint64 =
|
||||
e - GENESIS_EPOCH
|
||||
|
||||
func shortLog*(v: SomeBeaconBlock): auto =
|
||||
(
|
||||
slot: shortLog(v.slot),
|
||||
proposer_index: v.proposer_index,
|
||||
parent_root: shortLog(v.parent_root),
|
||||
state_root: shortLog(v.state_root),
|
||||
eth1data: v.body.eth1_data,
|
||||
graffiti: $v.body.graffiti,
|
||||
proposer_slashings_len: v.body.proposer_slashings.len(),
|
||||
attester_slashings_len: v.body.attester_slashings.len(),
|
||||
attestations_len: v.body.attestations.len(),
|
||||
deposits_len: v.body.deposits.len(),
|
||||
voluntary_exits_len: v.body.voluntary_exits.len(),
|
||||
)
|
||||
|
||||
func shortLog*(v: SomeSignedBeaconBlock): auto =
|
||||
(
|
||||
blck: shortLog(v.message),
|
||||
signature: shortLog(v.signature)
|
||||
)
|
||||
|
||||
func shortLog*(v: BeaconBlockHeader): auto =
|
||||
(
|
||||
slot: shortLog(v.slot),
|
||||
|
@ -1119,7 +864,6 @@ func shortLog*(v: SomeSignedVoluntaryExit): auto =
|
|||
|
||||
chronicles.formatIt Slot: it.shortLog
|
||||
chronicles.formatIt Epoch: it.shortLog
|
||||
chronicles.formatIt BeaconBlock: it.shortLog
|
||||
chronicles.formatIt AttestationData: it.shortLog
|
||||
chronicles.formatIt Attestation: it.shortLog
|
||||
chronicles.formatIt Checkpoint: it.shortLog
|
||||
|
|
|
@ -1,2 +1,296 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2021 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
# This file contains data types that are part of the spec and thus subject to
|
||||
# serialization and spec updates.
|
||||
#
|
||||
# The spec folder in general contains code that has been hoisted from the
|
||||
# specification and that follows the spec as closely as possible, so as to make
|
||||
# it easy to keep up-to-date.
|
||||
#
|
||||
# These datatypes are used as specifications for serialization - thus should not
|
||||
# be altered outside of what the spec says. Likewise, they should not be made
|
||||
# `ref` - this can be achieved by wrapping them in higher-level
|
||||
# types / composition
|
||||
|
||||
# TODO Careful, not nil analysis is broken / incomplete and the semantics will
|
||||
# likely change in future versions of the language:
|
||||
# https://github.com/nim-lang/RFCs/issues/250
|
||||
{.experimental: "notnil".}
|
||||
|
||||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
std/[macros, intsets, json, strutils, tables],
|
||||
stew/[assign2, byteutils], chronicles,
|
||||
json_serialization/types as jsonTypes,
|
||||
../../ssz/types as sszTypes, ../crypto, ../digest, ../presets
|
||||
|
||||
import ./base
|
||||
export base
|
||||
|
||||
type
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconstate
|
||||
BeaconState* = object
|
||||
# Versioning
|
||||
genesis_time*: uint64
|
||||
genesis_validators_root*: Eth2Digest
|
||||
slot*: Slot
|
||||
fork*: Fork
|
||||
|
||||
# History
|
||||
latest_block_header*: BeaconBlockHeader ##\
|
||||
## `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||
|
||||
block_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] ##\
|
||||
## Needed to process attestations, older to newer
|
||||
|
||||
state_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
|
||||
historical_roots*: HashList[Eth2Digest, Limit HISTORICAL_ROOTS_LIMIT]
|
||||
|
||||
# Eth1
|
||||
eth1_data*: Eth1Data
|
||||
eth1_data_votes*:
|
||||
HashList[Eth1Data, Limit(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)]
|
||||
eth1_deposit_index*: uint64
|
||||
|
||||
# Registry
|
||||
validators*: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
|
||||
# Randomness
|
||||
randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]
|
||||
|
||||
# Slashings
|
||||
slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] ##\
|
||||
## Per-epoch sums of slashed effective balances
|
||||
|
||||
# Attestations
|
||||
previous_epoch_attestations*:
|
||||
HashList[PendingAttestation, Limit(MAX_ATTESTATIONS * SLOTS_PER_EPOCH)]
|
||||
current_epoch_attestations*:
|
||||
HashList[PendingAttestation, Limit(MAX_ATTESTATIONS * SLOTS_PER_EPOCH)]
|
||||
|
||||
# Finality
|
||||
justification_bits*: uint8 ##\
|
||||
## Bit set for every recent justified epoch
|
||||
## Model a Bitvector[4] as a one-byte uint, which should remain consistent
|
||||
## with ssz/hashing.
|
||||
|
||||
previous_justified_checkpoint*: Checkpoint ##\
|
||||
## Previous epoch snapshot
|
||||
|
||||
current_justified_checkpoint*: Checkpoint
|
||||
finalized_checkpoint*: Checkpoint
|
||||
|
||||
# TODO Careful, not nil analysis is broken / incomplete and the semantics will
|
||||
# likely change in future versions of the language:
|
||||
# https://github.com/nim-lang/RFCs/issues/250
|
||||
BeaconStateRef* = ref BeaconState not nil
|
||||
NilableBeaconStateRef* = ref BeaconState
|
||||
|
||||
HashedBeaconState* = object
|
||||
data*: BeaconState
|
||||
root*: Eth2Digest # hash_tree_root(data)
|
||||
|
||||
BlockRef* = ref object
|
||||
## Node in object graph guaranteed to lead back to tail block, and to have
|
||||
## a corresponding entry in database.
|
||||
## Block graph should form a tree - in particular, there are no cycles.
|
||||
|
||||
root*: Eth2Digest ##\
|
||||
## Root that can be used to retrieve block data from database
|
||||
|
||||
parent*: BlockRef ##\
|
||||
## Not nil, except for the tail
|
||||
|
||||
slot*: Slot # could calculate this by walking to root, but..
|
||||
|
||||
StateData* = object
|
||||
data*: HashedBeaconState
|
||||
|
||||
blck*: BlockRef ##\
|
||||
## The block associated with the state found in data
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/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
|
||||
## validators that will have a chance to vote on it through attestations.
|
||||
## Each block collects attestations, or votes, on past blocks, thus a chain
|
||||
## is formed.
|
||||
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
|
||||
parent_root*: Eth2Digest ##\
|
||||
## Root hash of the previous block
|
||||
|
||||
state_root*: Eth2Digest ##\
|
||||
## The state root, _after_ this block has been processed
|
||||
|
||||
body*: BeaconBlockBody
|
||||
|
||||
SigVerifiedBeaconBlock* = object
|
||||
## A BeaconBlock that contains verified signatures
|
||||
## but that has not been verified for state transition
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
|
||||
parent_root*: Eth2Digest ##\
|
||||
## Root hash of the previous block
|
||||
|
||||
state_root*: Eth2Digest ##\
|
||||
## The state root, _after_ this block has been processed
|
||||
|
||||
body*: SigVerifiedBeaconBlockBody
|
||||
|
||||
TrustedBeaconBlock* = object
|
||||
## When we receive blocks from outside sources, they are untrusted and go
|
||||
## through several layers of validation. Blocks that have gone through
|
||||
## validations can be trusted to be well-formed, with a correct signature,
|
||||
## having a parent and applying cleanly to the state that their parent
|
||||
## left them with.
|
||||
##
|
||||
## When loading such blocks from the database, to rewind states for example,
|
||||
## it is expensive to redo the validations (in particular, the signature
|
||||
## checks), thus `TrustedBlock` uses a `TrustedSig` type to mark that these
|
||||
## checks can be skipped.
|
||||
##
|
||||
## TODO this could probably be solved with some type trickery, but there
|
||||
## too many bugs in nim around generics handling, and we've used up
|
||||
## the trickery budget in the serialization library already. Until
|
||||
## then, the type must be manually kept compatible with its untrusted
|
||||
## cousin.
|
||||
slot*: Slot
|
||||
proposer_index*: uint64
|
||||
parent_root*: Eth2Digest ##\
|
||||
state_root*: Eth2Digest ##\
|
||||
body*: TrustedBeaconBlockBody
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblockbody
|
||||
BeaconBlockBody* = object
|
||||
randao_reveal*: ValidatorSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[Attestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
SigVerifiedBeaconBlockBody* = object
|
||||
## A BeaconBlock body with signatures verified
|
||||
## including:
|
||||
## - Randao reveal
|
||||
## - Attestations
|
||||
## - ProposerSlashing (SignedBeaconBlockHeader)
|
||||
## - AttesterSlashing (IndexedAttestation)
|
||||
## - SignedVoluntaryExits
|
||||
##
|
||||
## - ETH1Data (Deposits) can contain invalid BLS signatures
|
||||
##
|
||||
## The block state transition has NOT been verified
|
||||
randao_reveal*: TrustedSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
TrustedBeaconBlockBody* = object
|
||||
## A full verified block
|
||||
randao_reveal*: TrustedSig
|
||||
eth1_data*: Eth1Data
|
||||
graffiti*: GraffitiBytes
|
||||
|
||||
# Operations
|
||||
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
|
||||
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
|
||||
deposits*: List[Deposit, Limit MAX_DEPOSITS]
|
||||
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#signedbeaconblock
|
||||
SignedBeaconBlock* = object
|
||||
message*: BeaconBlock
|
||||
signature*: ValidatorSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
SigVerifiedSignedBeaconBlock* = object
|
||||
## A SignedBeaconBlock with signatures verified
|
||||
## including:
|
||||
## - Block signature
|
||||
## - BeaconBlockBody
|
||||
## - Randao reveal
|
||||
## - Attestations
|
||||
## - ProposerSlashing (SignedBeaconBlockHeader)
|
||||
## - AttesterSlashing (IndexedAttestation)
|
||||
## - SignedVoluntaryExits
|
||||
##
|
||||
## - ETH1Data (Deposits) can contain invalid BLS signatures
|
||||
##
|
||||
## The block state transition has NOT been verified
|
||||
message*: SigVerifiedBeaconBlock
|
||||
signature*: TrustedSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
TrustedSignedBeaconBlock* = object
|
||||
message*: TrustedBeaconBlock
|
||||
signature*: TrustedSig
|
||||
|
||||
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
|
||||
|
||||
SomeSignedBeaconBlock* = SignedBeaconBlock | SigVerifiedSignedBeaconBlock | TrustedSignedBeaconBlock
|
||||
SomeBeaconBlock* = BeaconBlock | SigVerifiedBeaconBlock | TrustedBeaconBlock
|
||||
SomeBeaconBlockBody* = BeaconBlockBody | SigVerifiedBeaconBlockBody | TrustedBeaconBlockBody
|
||||
|
||||
chronicles.formatIt BeaconBlock: it.shortLog
|
||||
|
||||
Json.useCustomSerialization(BeaconState.justification_bits):
|
||||
read:
|
||||
let s = reader.readValue(string)
|
||||
|
||||
if s.len != 4:
|
||||
raiseUnexpectedValue(reader, "A string with 4 characters expected")
|
||||
|
||||
try:
|
||||
s.parseHexInt.uint8
|
||||
except ValueError:
|
||||
raiseUnexpectedValue(reader, "The `justification_bits` value must be a hex string")
|
||||
|
||||
write:
|
||||
writer.writeValue "0x" & value.toHex
|
||||
|
||||
func shortLog*(v: SomeBeaconBlock): auto =
|
||||
(
|
||||
slot: shortLog(v.slot),
|
||||
proposer_index: v.proposer_index,
|
||||
parent_root: shortLog(v.parent_root),
|
||||
state_root: shortLog(v.state_root),
|
||||
eth1data: v.body.eth1_data,
|
||||
graffiti: $v.body.graffiti,
|
||||
proposer_slashings_len: v.body.proposer_slashings.len(),
|
||||
attester_slashings_len: v.body.attester_slashings.len(),
|
||||
attestations_len: v.body.attestations.len(),
|
||||
deposits_len: v.body.deposits.len(),
|
||||
voluntary_exits_len: v.body.voluntary_exits.len(),
|
||||
)
|
||||
|
||||
func shortLog*(v: SomeSignedBeaconBlock): auto =
|
||||
(
|
||||
blck: shortLog(v.message),
|
||||
signature: shortLog(v.signature)
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ import
|
|||
# Standard lib
|
||||
std/[math, tables],
|
||||
# Third-party
|
||||
stew/endians2,
|
||||
stew/[byteutils, endians2],
|
||||
# Internal
|
||||
./datatypes/[phase0, altair], ./digest, ./crypto, ../ssz/merkleization
|
||||
|
||||
|
@ -52,7 +52,7 @@ func is_active_validator*(validator: Validator, epoch: Epoch): bool =
|
|||
validator.activation_epoch <= epoch and epoch < validator.exit_epoch
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_active_validator_indices
|
||||
func get_active_validator_indices*(state: BeaconState, epoch: Epoch):
|
||||
func get_active_validator_indices*(state: SomeBeaconState, epoch: Epoch):
|
||||
seq[ValidatorIndex] =
|
||||
## Return the sequence of active validator indices at ``epoch``.
|
||||
result = newSeqOfCap[ValidatorIndex](state.validators.len)
|
||||
|
@ -60,20 +60,20 @@ func get_active_validator_indices*(state: BeaconState, epoch: Epoch):
|
|||
if is_active_validator(state.validators[idx], epoch):
|
||||
result.add idx.ValidatorIndex
|
||||
|
||||
func get_active_validator_indices_len*(state: BeaconState, epoch: Epoch): uint64 =
|
||||
func get_active_validator_indices_len*(state: SomeBeaconState, epoch: Epoch):
|
||||
uint64 =
|
||||
for idx in 0..<state.validators.len:
|
||||
if is_active_validator(state.validators[idx], epoch):
|
||||
inc result
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_current_epoch
|
||||
func get_current_epoch*(state: BeaconState): Epoch =
|
||||
func get_current_epoch*(state: SomeBeaconState): Epoch =
|
||||
## Return the current epoch.
|
||||
doAssert state.slot >= GENESIS_SLOT, $state.slot
|
||||
compute_epoch_at_slot(state.slot)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_randao_mix
|
||||
func get_randao_mix*(state: BeaconState,
|
||||
epoch: Epoch): Eth2Digest =
|
||||
func get_randao_mix*(state: SomeBeaconState, epoch: Epoch): Eth2Digest =
|
||||
## Returns the randao mix at a recent ``epoch``.
|
||||
state.randao_mixes[epoch mod EPOCHS_PER_HISTORICAL_VECTOR]
|
||||
|
||||
|
@ -147,7 +147,7 @@ func get_domain*(
|
|||
compute_domain(domain_type, fork_version, genesis_validators_root)
|
||||
|
||||
func get_domain*(
|
||||
state: BeaconState, domain_type: DomainType, epoch: Epoch): Eth2Domain =
|
||||
state: SomeBeaconState, domain_type: DomainType, epoch: Epoch): Eth2Domain =
|
||||
## Return the signature domain (fork version concatenated with domain type)
|
||||
## of a message.
|
||||
get_domain(state.fork, domain_type, epoch, state.genesis_validators_root)
|
||||
|
@ -163,7 +163,8 @@ func compute_signing_root*(ssz_object: auto, domain: Eth2Domain): Eth2Digest =
|
|||
hash_tree_root(domain_wrapped_object)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_seed
|
||||
func get_seed*(state: BeaconState, epoch: Epoch, domain_type: DomainType): Eth2Digest =
|
||||
func get_seed*(state: SomeBeaconState, epoch: Epoch, domain_type: DomainType):
|
||||
Eth2Digest =
|
||||
## Return the seed at ``epoch``.
|
||||
|
||||
var seed_input : array[4+8+32, byte]
|
||||
|
@ -179,14 +180,6 @@ func get_seed*(state: BeaconState, epoch: Epoch, domain_type: DomainType): Eth2D
|
|||
epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1).data
|
||||
eth2digest(seed_input)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#get_flag_indices_and_weights
|
||||
iterator get_flag_indices_and_weights*(): (ParticipationFlag, int) =
|
||||
for item in [
|
||||
(TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_WEIGHT),
|
||||
(TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_WEIGHT),
|
||||
(TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_WEIGHT)]:
|
||||
yield item
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/altair/beacon-chain.md#add_flag
|
||||
func add_flag*(flags: ParticipationFlags, flag_index: int): ParticipationFlags =
|
||||
let flag = ParticipationFlags(1'u8 shl flag_index)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
const
|
||||
# Updated penalty values
|
||||
# ---------------------------------------------------------------
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/configs/mainnet/altair.yaml#L5
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/configs/mainnet/altair.yaml#L3
|
||||
CONFIG_NAME* = "mainnet"
|
||||
|
||||
INACTIVITY_PENALTY_QUOTIENT_ALTAIR* = 50331648 ##\
|
||||
|
@ -23,28 +23,26 @@ const
|
|||
# Misc
|
||||
# ---------------------------------------------------------------
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/configs/mainnet/altair.yaml#L15
|
||||
SYNC_COMMITTEE_SIZE* = 1024
|
||||
SYNC_PUBKEYS_PER_AGGREGATE* = 64
|
||||
INACTIVITY_SCORE_BIAS* = 4
|
||||
|
||||
# Time parameters
|
||||
# Sync Committee
|
||||
# ---------------------------------------------------------------
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/configs/mainnet/altair.yaml#L25
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD* = 256
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/configs/mainnet/altair.yaml#L13
|
||||
SYNC_COMMITTEE_SIZE* = 512
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD* = 512
|
||||
|
||||
# Signature domains (DOMAIN_SYNC_COMMITTEE) in spec/datatypes/base
|
||||
|
||||
# Fork
|
||||
# ---------------------------------------------------------------
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/configs/mainnet/altair.yaml#L36
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/configs/mainnet/altair.yaml#L36
|
||||
|
||||
# ALTAIR_FORK_VERSION is a runtime preset
|
||||
|
||||
ALTAIR_FORK_SLOT* = 0 # TBD
|
||||
ALTAIR_FORK_EPOCH* = 18446744073709551615'u64
|
||||
|
||||
# Sync protocol
|
||||
# ---------------------------------------------------------------
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/configs/mainnet/altair.yaml#L43
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/configs/mainnet/altair.yaml#L44
|
||||
MIN_SYNC_COMMITTEE_PARTICIPANTS* = 1
|
||||
MAX_VALID_LIGHT_CLIENT_UPDATES* = 8192
|
||||
LIGHT_CLIENT_UPDATE_TIMEOUT* = 8192
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import
|
||||
../ssz/merkleization,
|
||||
./crypto, ./digest, ./datatypes, ./helpers, ./presets
|
||||
./crypto, ./digest, ./datatypes/[phase0, altair], ./helpers, ./presets
|
||||
|
||||
template withTrust(sig: SomeSig, body: untyped): bool =
|
||||
when sig is TrustedSig:
|
||||
|
@ -90,7 +90,7 @@ func get_block_signature*(
|
|||
|
||||
proc verify_block_signature*(
|
||||
fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
|
||||
blck: Eth2Digest | SomeBeaconBlock | BeaconBlockHeader,
|
||||
blck: Eth2Digest | SomeSomeBeaconBlock | BeaconBlockHeader,
|
||||
pubkey: ValidatorPubKey,
|
||||
signature: SomeSig): bool =
|
||||
withTrust(signature):
|
||||
|
|
|
@ -16,6 +16,9 @@ import
|
|||
./crypto, ./datatypes, ./helpers, ./presets,
|
||||
./beaconstate, ./digest
|
||||
|
||||
# Otherwise, error.
|
||||
import chronicles
|
||||
|
||||
export SignatureSet, BatchedBLSVerifierCache, batchVerify, batchVerifySerial, batchVerifyParallel
|
||||
|
||||
func `$`*(s: SignatureSet): string =
|
||||
|
|
|
@ -45,13 +45,18 @@ import
|
|||
chronicles,
|
||||
stew/results,
|
||||
../extras, ../ssz/merkleization, metrics,
|
||||
./datatypes, ./crypto, ./digest, ./helpers, ./signatures, ./validator,
|
||||
./datatypes/[phase0, altair], ./crypto, ./digest, ./helpers, ./signatures, ./validator,
|
||||
./state_transition_block, ./state_transition_epoch,
|
||||
../../nbench/bench_lab
|
||||
|
||||
# TODO why need anything except the first two?
|
||||
type Foo = phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock | phase0.SignedBeaconBlock | altair.SignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.TrustedSignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | altair.SigVerifiedSignedBeaconBlock
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc verify_block_signature*(
|
||||
state: BeaconState, signed_block: SomeSignedBeaconBlock): bool {.nbench.} =
|
||||
#state: SomeBeaconState, signed_block: SomeSomeSignedBeaconBlock): bool {.nbench.} =
|
||||
state: SomeBeaconState, signed_block: Foo): bool {.nbench.} =
|
||||
#state: SomeBeaconState, signed_block: phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock): bool {.nbench.} =
|
||||
let
|
||||
proposer_index = signed_block.message.proposer_index
|
||||
if proposer_index >= state.validators.lenu64:
|
||||
|
@ -70,7 +75,7 @@ proc verify_block_signature*(
|
|||
true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc verifyStateRoot(state: BeaconState, blck: BeaconBlock or SigVerifiedBeaconBlock): bool =
|
||||
proc verifyStateRoot(state: SomeBeaconState, blck: phase0.BeaconBlock or phase0.SigVerifiedBeaconBlock or altair.BeaconBlock or altair.SigVerifiedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
let state_root = hash_tree_root(state)
|
||||
if state_root != blck.state_root:
|
||||
|
@ -80,25 +85,25 @@ proc verifyStateRoot(state: BeaconState, blck: BeaconBlock or SigVerifiedBeaconB
|
|||
else:
|
||||
true
|
||||
|
||||
proc verifyStateRoot(state: BeaconState, blck: TrustedBeaconBlock): bool =
|
||||
proc verifyStateRoot(state: phase0.BeaconState, blck: phase0.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
type
|
||||
RollbackProc* = proc(v: var BeaconState) {.gcsafe, raises: [Defect].}
|
||||
RollbackProc* = proc(v: var phase0.BeaconState) {.gcsafe, raises: [Defect].}
|
||||
|
||||
proc noRollback*(state: var BeaconState) =
|
||||
proc noRollback*(state: var phase0.BeaconState) =
|
||||
trace "Skipping rollback of broken state"
|
||||
|
||||
type
|
||||
RollbackHashedProc* = proc(state: var HashedBeaconState) {.gcsafe, raises: [Defect].}
|
||||
RollbackHashedProc* = proc(state: var phase0.HashedBeaconState) {.gcsafe, raises: [Defect].}
|
||||
|
||||
# Hashed-state transition functions
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
func process_slot*(
|
||||
state: var BeaconState, pre_state_root: Eth2Digest) {.nbench.} =
|
||||
state: var SomeBeaconState, pre_state_root: Eth2Digest) {.nbench.} =
|
||||
# `process_slot` is the first stage of per-slot processing - it is run for
|
||||
# every slot, including epoch slots - it does not however update the slot
|
||||
# number! `pre_state_root` refers to the state root of the incoming
|
||||
|
@ -126,7 +131,7 @@ func clear_epoch_from_cache(cache: var StateCache, epoch: Epoch) =
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc advance_slot(
|
||||
state: var BeaconState, previous_slot_state_root: Eth2Digest,
|
||||
state: var SomeBeaconState, previous_slot_state_root: Eth2Digest,
|
||||
flags: UpdateFlags, cache: var StateCache, rewards: var RewardInfo) {.nbench.} =
|
||||
# Do the per-slot and potentially the per-epoch processing, then bump the
|
||||
# slot number - we've now arrived at the slot state on top of which a block
|
||||
|
@ -145,7 +150,7 @@ proc advance_slot(
|
|||
state.slot += 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc process_slots*(state: var HashedBeaconState, slot: Slot,
|
||||
proc process_slots*(state: var SomeHashedBeaconState, slot: Slot,
|
||||
cache: var StateCache, rewards: var RewardInfo,
|
||||
flags: UpdateFlags = {}): bool {.nbench.} =
|
||||
## Process one or more slot transitions without blocks - if the slot transtion
|
||||
|
@ -171,12 +176,14 @@ proc process_slots*(state: var HashedBeaconState, slot: Slot,
|
|||
|
||||
true
|
||||
|
||||
proc noRollback*(state: var HashedBeaconState) =
|
||||
proc noRollback*(state: var phase0.HashedBeaconState) =
|
||||
trace "Skipping rollback of broken state"
|
||||
|
||||
proc state_transition*(
|
||||
preset: RuntimePreset,
|
||||
state: var HashedBeaconState, signedBlock: SomeSignedBeaconBlock,
|
||||
# TODO this will be StateData
|
||||
#state: var phase0.HashedBeaconState, signedBlock: phase0.SomeSignedBeaconBlock,
|
||||
state: var (phase0.HashedBeaconState | altair.HashedBeaconState), signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
|
||||
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
|
||||
rollback: RollbackHashedProc): bool {.nbench.} =
|
||||
## Apply a block to the state, advancing the slot counter as necessary. The
|
||||
|
@ -219,7 +226,9 @@ proc state_transition*(
|
|||
# that the block is sane.
|
||||
if not (skipBLSValidation in flags or
|
||||
verify_block_signature(state.data, signedBlock)):
|
||||
rollback(state)
|
||||
when false:
|
||||
# TODO fixme
|
||||
rollback(state)
|
||||
return false
|
||||
|
||||
trace "state_transition: processing block, signature passed",
|
||||
|
@ -235,12 +244,16 @@ proc state_transition*(
|
|||
eth1_deposit_index = state.data.eth1_deposit_index,
|
||||
deposit_root = shortLog(state.data.eth1_data.deposit_root),
|
||||
error = res.error
|
||||
rollback(state)
|
||||
when false:
|
||||
# TODO re-enable
|
||||
rollback(state)
|
||||
return false
|
||||
|
||||
if not (skipStateRootValidation in flags or
|
||||
verifyStateRoot(state.data, signedBlock.message)):
|
||||
rollback(state)
|
||||
when false:
|
||||
# TODO re-enable
|
||||
rollback(state)
|
||||
return false
|
||||
|
||||
# only blocks currently being produced have an empty state root - we use a
|
||||
|
@ -254,7 +267,7 @@ proc state_transition*(
|
|||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#preparing-for-a-beaconblock
|
||||
proc makeBeaconBlock*(
|
||||
preset: RuntimePreset,
|
||||
state: var HashedBeaconState,
|
||||
state: var phase0.HashedBeaconState,
|
||||
proposer_index: ValidatorIndex,
|
||||
parent_root: Eth2Digest,
|
||||
randao_reveal: ValidatorSig,
|
||||
|
@ -267,7 +280,7 @@ proc makeBeaconBlock*(
|
|||
voluntaryExits: seq[SignedVoluntaryExit],
|
||||
executionPayload: ExecutionPayload,
|
||||
rollback: RollbackHashedProc,
|
||||
cache: var StateCache): Option[BeaconBlock] =
|
||||
cache: var StateCache): Option[phase0.BeaconBlock] =
|
||||
## Create a block for the given state. The last block applied to it must be
|
||||
## the one identified by parent_root and process_slots must be called up to
|
||||
## the slot for which a block is to be created.
|
||||
|
@ -275,11 +288,11 @@ proc makeBeaconBlock*(
|
|||
# To create a block, we'll first apply a partial block to the state, skipping
|
||||
# some validations.
|
||||
|
||||
var blck = BeaconBlock(
|
||||
var blck = phase0.BeaconBlock(
|
||||
slot: state.data.slot,
|
||||
proposer_index: proposer_index.uint64,
|
||||
parent_root: parent_root,
|
||||
body: BeaconBlockBody(
|
||||
body: phase0.BeaconBlockBody(
|
||||
randao_reveal: randao_reveal,
|
||||
eth1_data: eth1data,
|
||||
graffiti: graffiti,
|
||||
|
|
|
@ -20,16 +20,16 @@
|
|||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
std/[algorithm, intsets, options, sequtils],
|
||||
std/[algorithm, intsets, options, sequtils, sets, tables],
|
||||
chronicles,
|
||||
../extras, ../ssz/merkleization, metrics,
|
||||
./beaconstate, ./crypto, ./datatypes, ./digest, ./helpers, ./validator,
|
||||
./signatures, ./presets,
|
||||
./beaconstate, ./crypto, ./datatypes/[phase0, altair], ./digest, ./helpers,
|
||||
./validator, ./signatures, ./presets,
|
||||
../../nbench/bench_lab
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#block-header
|
||||
func process_block_header*(
|
||||
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags,
|
||||
state: var SomeBeaconState, blck: SomeSomeBeaconBlock, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
||||
# Verify that the slots match
|
||||
if not (blck.slot == state.slot):
|
||||
|
@ -72,7 +72,7 @@ func `xor`[T: array](a, b: T): T =
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#randao
|
||||
proc process_randao(
|
||||
state: var BeaconState, body: SomeBeaconBlockBody, flags: UpdateFlags,
|
||||
state: var SomeBeaconState, body: SomeSomeBeaconBlockBody, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
||||
let
|
||||
proposer_index = get_beacon_proposer_index(state, cache)
|
||||
|
@ -104,7 +104,7 @@ proc process_randao(
|
|||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#eth1-data
|
||||
func process_eth1_data(state: var BeaconState, body: SomeBeaconBlockBody): Result[void, cstring] {.nbench.}=
|
||||
func process_eth1_data(state: var SomeBeaconState, body: SomeSomeBeaconBlockBody): Result[void, cstring] {.nbench.}=
|
||||
if not state.eth1_data_votes.add body.eth1_data:
|
||||
# Count is reset in process_final_updates, so this should never happen
|
||||
return err("process_eth1_data: no more room for eth1 data")
|
||||
|
@ -123,7 +123,7 @@ func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#proposer-slashings
|
||||
proc check_proposer_slashing*(
|
||||
state: var BeaconState, proposer_slashing: SomeProposerSlashing,
|
||||
state: var SomeBeaconState, proposer_slashing: SomeProposerSlashing,
|
||||
flags: UpdateFlags):
|
||||
Result[void, cstring] {.nbench.} =
|
||||
|
||||
|
@ -165,7 +165,7 @@ proc check_proposer_slashing*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#proposer-slashings
|
||||
proc process_proposer_slashing*(
|
||||
state: var BeaconState, proposer_slashing: SomeProposerSlashing,
|
||||
state: var SomeBeaconState, proposer_slashing: SomeProposerSlashing,
|
||||
flags: UpdateFlags, cache: var StateCache):
|
||||
Result[void, cstring] {.nbench.} =
|
||||
? check_proposer_slashing(state, proposer_slashing, flags)
|
||||
|
@ -189,7 +189,7 @@ func is_slashable_attestation_data*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#attester-slashings
|
||||
proc check_attester_slashing*(
|
||||
state: var BeaconState,
|
||||
state: var SomeBeaconState,
|
||||
attester_slashing: SomeAttesterSlashing,
|
||||
flags: UpdateFlags
|
||||
): Result[seq[ValidatorIndex], cstring] {.nbench.} =
|
||||
|
@ -222,7 +222,7 @@ proc check_attester_slashing*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#attester-slashings
|
||||
proc process_attester_slashing*(
|
||||
state: var BeaconState,
|
||||
state: var SomeBeaconState,
|
||||
attester_slashing: SomeAttesterSlashing,
|
||||
flags: UpdateFlags,
|
||||
cache: var StateCache
|
||||
|
@ -240,7 +240,7 @@ proc process_attester_slashing*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#voluntary-exits
|
||||
proc check_voluntary_exit*(
|
||||
state: BeaconState,
|
||||
state: SomeBeaconState,
|
||||
signed_voluntary_exit: SomeSignedVoluntaryExit,
|
||||
flags: UpdateFlags): Result[void, cstring] {.nbench.} =
|
||||
|
||||
|
@ -292,7 +292,7 @@ proc check_voluntary_exit*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#voluntary-exits
|
||||
proc process_voluntary_exit*(
|
||||
state: var BeaconState,
|
||||
state: var SomeBeaconState,
|
||||
signed_voluntary_exit: SomeSignedVoluntaryExit,
|
||||
flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
||||
|
@ -303,8 +303,8 @@ proc process_voluntary_exit*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#operations
|
||||
proc process_operations(preset: RuntimePreset,
|
||||
state: var BeaconState,
|
||||
body: SomeBeaconBlockBody,
|
||||
state: var SomeBeaconState,
|
||||
body: SomeSomeBeaconBlockBody,
|
||||
flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
||||
# Verify that outstanding deposits are processed up to the maximum number of
|
||||
|
@ -335,10 +335,70 @@ proc process_operations(preset: RuntimePreset,
|
|||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#sync-committee-processing
|
||||
proc process_sync_committee*(
|
||||
state: var altair.BeaconState, aggregate: SyncAggregate, cache: var StateCache):
|
||||
Result[void, cstring] {.nbench.} =
|
||||
# Verify sync committee aggregate signature signing over the previous slot
|
||||
# block root
|
||||
let
|
||||
committee_pubkeys = state.current_sync_committee.pubkeys
|
||||
previous_slot = max(state.slot, Slot(1)) - 1
|
||||
domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot))
|
||||
signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain)
|
||||
|
||||
var participant_pubkeys: seq[ValidatorPubKey]
|
||||
for i in 0 ..< committee_pubkeys.len:
|
||||
if aggregate.sync_committee_bits[i]:
|
||||
participant_pubkeys.add committee_pubkeys[i]
|
||||
|
||||
# Empty participants allowed
|
||||
if participant_pubkeys.len > 0 and not blsFastAggregateVerify(
|
||||
participant_pubkeys, signing_root.data, aggregate.sync_committee_signature):
|
||||
return err("process_sync_committee: invalid signature")
|
||||
|
||||
# Compute participant and proposer rewards
|
||||
let
|
||||
total_active_increments = get_total_active_balance(state, cache) div EFFECTIVE_BALANCE_INCREMENT
|
||||
total_base_rewards = get_base_reward_per_increment(state, cache) * total_active_increments
|
||||
max_participant_rewards = total_base_rewards * SYNC_REWARD_WEIGHT div WEIGHT_DENOMINATOR div SLOTS_PER_EPOCH
|
||||
participant_reward = max_participant_rewards div SYNC_COMMITTEE_SIZE
|
||||
proposer_reward = participant_reward * PROPOSER_WEIGHT div (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)
|
||||
|
||||
# Apply participant and proposer rewards
|
||||
|
||||
# stand-in to be replaced
|
||||
# TODO obviously not viable as written
|
||||
# TODO also, this could use the pubkey -> index map that's been approached a couple places
|
||||
let s = toHashSet(state.current_sync_committee.pubkeys.data) # TODO leaking abstraction
|
||||
var pubkeyIndices: Table[ValidatorPubKey, ValidatorIndex]
|
||||
for i, v in state.validators:
|
||||
if v.pubkey in s:
|
||||
pubkeyIndices[v.pubkey] = i.ValidatorIndex
|
||||
|
||||
let committee_indices = mapIt(state.current_sync_committee.pubkeys, pubkeyIndices.getOrDefault(it))
|
||||
var participant_indices: seq[ValidatorIndex]
|
||||
for i, committee_index in committee_indices:
|
||||
if aggregate.sync_committee_bits[i]:
|
||||
participant_indices.add committee_index
|
||||
for participant_index in participant_indices:
|
||||
let proposer_index = get_beacon_proposer_index(state, cache)
|
||||
if proposer_index.isSome:
|
||||
increase_balance(state, participant_index, participant_reward)
|
||||
increase_balance(state, proposer_index.get, proposer_reward)
|
||||
else:
|
||||
warn "process_sync_committee: get_beacon_proposer_index failed"
|
||||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#block-processing
|
||||
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
|
||||
# copy of datatypes/phase0.nim
|
||||
type SomePhase0Block =
|
||||
phase0.BeaconBlock | phase0.SigVerifiedBeaconBlock | phase0.TrustedBeaconBlock
|
||||
proc process_block*(
|
||||
preset: RuntimePreset,
|
||||
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags,
|
||||
state: var phase0.BeaconState, blck: SomePhase0Block, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.}=
|
||||
## When there's a new block, we need to verify that the block is sane and
|
||||
## update the state accordingly - the state is left in an unknown state when
|
||||
|
@ -350,3 +410,24 @@ proc process_block*(
|
|||
? process_operations(preset, state, blck.body, flags, cache)
|
||||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#block-processing
|
||||
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
|
||||
# copy of datatypes/altair.nim
|
||||
type SomeAltairBlock =
|
||||
altair.BeaconBlock | altair.SigVerifiedBeaconBlock | altair.TrustedBeaconBlock
|
||||
proc process_block*(
|
||||
preset: RuntimePreset,
|
||||
state: var altair.BeaconState, blck: SomeAltairBlock, flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.}=
|
||||
## When there's a new block, we need to verify that the block is sane and
|
||||
## update the state accordingly - the state is left in an unknown state when
|
||||
## block application fails (!)
|
||||
|
||||
? process_block_header(state, blck, flags, cache)
|
||||
? process_randao(state, blck.body, flags, cache)
|
||||
? process_eth1_data(state, blck.body)
|
||||
? process_operations(preset, state, blck.body, flags, cache)
|
||||
? process_sync_committee(state, blck.body.sync_aggregate, cache) # [New in Altair]
|
||||
|
||||
ok()
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
std/[math, sequtils, tables, algorithm],
|
||||
std/[math, sequtils, sets, tables, algorithm],
|
||||
stew/[bitops2], chronicles,
|
||||
../extras,
|
||||
../ssz/merkleization,
|
||||
./beaconstate, ./crypto, ./datatypes, ./digest, ./helpers, ./validator,
|
||||
./beaconstate, ./crypto, ./datatypes/[phase0, altair], ./digest, ./helpers, ./validator,
|
||||
../../nbench/bench_lab
|
||||
|
||||
# Logging utilities
|
||||
|
@ -49,7 +49,7 @@ template previous_epoch_target_attesters*(v: TotalBalances): Gwei =
|
|||
template previous_epoch_head_attesters*(v: TotalBalances): Gwei =
|
||||
max(EFFECTIVE_BALANCE_INCREMENT, v.previous_epoch_head_attesters_raw)
|
||||
|
||||
func init*(rewards: var RewardInfo, state: BeaconState) =
|
||||
func init*(rewards: var RewardInfo, state: SomeBeaconState) =
|
||||
rewards.total_balances = TotalBalances()
|
||||
rewards.statuses.setLen(state.validators.len)
|
||||
|
||||
|
@ -58,15 +58,15 @@ func init*(rewards: var RewardInfo, state: BeaconState) =
|
|||
var flags: set[RewardFlags]
|
||||
|
||||
if v[].slashed:
|
||||
flags.incl(isSlashed)
|
||||
flags.incl(RewardFlags.isSlashed)
|
||||
if state.get_current_epoch() >= v[].withdrawable_epoch:
|
||||
flags.incl canWithdrawInCurrentEpoch
|
||||
flags.incl RewardFlags.canWithdrawInCurrentEpoch
|
||||
|
||||
if v[].is_active_validator(state.get_current_epoch()):
|
||||
rewards.total_balances.current_epoch_raw += v[].effective_balance
|
||||
|
||||
if v[].is_active_validator(state.get_previous_epoch()):
|
||||
flags.incl isActiveInPreviousEpoch
|
||||
flags.incl RewardFlags.isActiveInPreviousEpoch
|
||||
rewards.total_balances.previous_epoch_raw += v[].effective_balance
|
||||
|
||||
rewards.statuses[i] = RewardStatus(
|
||||
|
@ -79,7 +79,7 @@ func add(a: var RewardDelta, b: RewardDelta) =
|
|||
a.penalties += b.penalties
|
||||
|
||||
func process_attestation(
|
||||
self: var RewardInfo, state: BeaconState, a: PendingAttestation,
|
||||
self: var RewardInfo, state: phase0.BeaconState, a: PendingAttestation,
|
||||
cache: var StateCache) =
|
||||
# Collect information about the attestation
|
||||
var
|
||||
|
@ -87,10 +87,10 @@ func process_attestation(
|
|||
is_previous_epoch_attester: Option[InclusionInfo]
|
||||
|
||||
if a.data.target.epoch == state.get_current_epoch():
|
||||
flags.incl isCurrentEpochAttester
|
||||
flags.incl RewardFlags.isCurrentEpochAttester
|
||||
|
||||
if a.data.target.root == get_block_root(state, state.get_current_epoch()):
|
||||
flags.incl isCurrentEpochTargetAttester
|
||||
flags.incl RewardFlags.isCurrentEpochTargetAttester
|
||||
|
||||
elif a.data.target.epoch == state.get_previous_epoch():
|
||||
is_previous_epoch_attester = some(InclusionInfo(
|
||||
|
@ -99,10 +99,10 @@ func process_attestation(
|
|||
))
|
||||
|
||||
if a.data.target.root == get_block_root(state, state.get_previous_epoch()):
|
||||
flags.incl isPreviousEpochTargetAttester
|
||||
flags.incl RewardFlags.isPreviousEpochTargetAttester
|
||||
|
||||
if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot):
|
||||
flags.incl isPreviousEpochHeadAttester
|
||||
flags.incl RewardFlags.isPreviousEpochHeadAttester
|
||||
|
||||
# Update the cache for all participants
|
||||
for validator_index in get_attesting_indices(
|
||||
|
@ -120,7 +120,7 @@ func process_attestation(
|
|||
v.is_previous_epoch_attester = is_previous_epoch_attester
|
||||
|
||||
func process_attestations*(
|
||||
self: var RewardInfo, state: BeaconState, cache: var StateCache) =
|
||||
self: var RewardInfo, state: phase0.BeaconState, cache: var StateCache) =
|
||||
# Walk state attestations and update the status information
|
||||
for a in state.previous_epoch_attestations:
|
||||
process_attestation(self, state, a, cache)
|
||||
|
@ -128,47 +128,54 @@ func process_attestations*(
|
|||
process_attestation(self, state, a, cache)
|
||||
|
||||
for idx, v in self.statuses:
|
||||
if isSlashed in v.flags:
|
||||
if v.flags.contains RewardFlags.isSlashed:
|
||||
continue
|
||||
|
||||
let validator_balance = state.validators[idx].effective_balance
|
||||
|
||||
if isCurrentEpochAttester in v.flags:
|
||||
if v.flags.contains RewardFlags.isCurrentEpochAttester:
|
||||
self.total_balances.current_epoch_attesters_raw += validator_balance
|
||||
|
||||
if isCurrentEpochTargetAttester in v.flags:
|
||||
if v.flags.contains RewardFlags.isCurrentEpochTargetAttester:
|
||||
self.total_balances.current_epoch_target_attesters_raw += validator_balance
|
||||
|
||||
if v.is_previous_epoch_attester.isSome():
|
||||
self.total_balances.previous_epoch_attesters_raw += validator_balance
|
||||
|
||||
if isPreviousEpochTargetAttester in v.flags:
|
||||
if v.flags.contains RewardFlags.isPreviousEpochTargetAttester:
|
||||
self.total_balances.previous_epoch_target_attesters_raw += validator_balance
|
||||
|
||||
if isPreviousEpochHeadAttester in v.flags:
|
||||
if v.flags.contains RewardFlags.isPreviousEpochHeadAttester:
|
||||
self.total_balances.previous_epoch_head_attesters_raw += validator_balance
|
||||
|
||||
func is_eligible_validator*(validator: RewardStatus): bool =
|
||||
isActiveInPreviousEpoch in validator.flags or
|
||||
(isSlashed in validator.flags and
|
||||
(canWithdrawInCurrentEpoch notin validator.flags))
|
||||
validator.flags.contains(RewardFlags.isActiveInPreviousEpoch) or
|
||||
(validator.flags.contains(RewardFlags.isSlashed) and not
|
||||
(validator.flags.contains RewardFlags.canWithdrawInCurrentEpoch))
|
||||
|
||||
# Spec
|
||||
# --------------------------------------------------------
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_total_active_balance
|
||||
func get_total_active_balance*(state: BeaconState, cache: var StateCache): Gwei =
|
||||
## Return the combined effective balance of the active validators.
|
||||
# Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei
|
||||
# minimum to avoid divisions by zero.
|
||||
|
||||
let epoch = state.get_current_epoch()
|
||||
|
||||
get_total_balance(
|
||||
state, cache.get_shuffled_active_validator_indices(state, epoch))
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_unslashed_participating_indices
|
||||
func get_unslashed_participating_indices(
|
||||
state: altair.BeaconState, flag_index: int, epoch: Epoch):
|
||||
HashSet[ValidatorIndex] =
|
||||
## Return the set of validator indices that are both active and unslashed for
|
||||
## the given ``flag_index`` and ``epoch``.
|
||||
doAssert epoch in [get_previous_epoch(state), get_current_epoch(state)]
|
||||
let
|
||||
epoch_participation =
|
||||
if epoch == get_current_epoch(state):
|
||||
state.current_epoch_participation
|
||||
else:
|
||||
state.previous_epoch_participation
|
||||
active_validator_indices = get_active_validator_indices(state, epoch)
|
||||
participating_indices = filterIt(
|
||||
active_validator_indices, has_flag(epoch_participation[it], flag_index))
|
||||
toHashSet(filterIt(participating_indices, not state.validators[it].slashed))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#justification-and-finalization
|
||||
proc process_justification_and_finalization*(state: var BeaconState,
|
||||
proc process_justification_and_finalization*(state: var phase0.BeaconState,
|
||||
total_balances: TotalBalances, flags: UpdateFlags = {}) {.nbench.} =
|
||||
# Initial FFG checkpoint values have a `0x00` stub for `root`.
|
||||
# Skip FFG updates in the first two epochs to avoid corner cases that might
|
||||
|
@ -264,8 +271,120 @@ proc process_justification_and_finalization*(state: var BeaconState,
|
|||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.finalized_checkpoint)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#justification-and-finalization
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/phase0/beacon-chain.md#justification-and-finalization
|
||||
# TODO merge these things -- effectively, the phase0 process_justification_and_finalization is mostly a stub in this world
|
||||
proc weigh_justification_and_finalization(state: var altair.BeaconState,
|
||||
total_balances: TotalBalances,
|
||||
previous_epoch_target_balance: Gwei,
|
||||
current_epoch_target_balance: Gwei,
|
||||
flags: UpdateFlags = {}) =
|
||||
let
|
||||
previous_epoch = get_previous_epoch(state)
|
||||
current_epoch = get_current_epoch(state)
|
||||
old_previous_justified_checkpoint = state.previous_justified_checkpoint
|
||||
old_current_justified_checkpoint = state.current_justified_checkpoint
|
||||
|
||||
# Process justifications
|
||||
state.previous_justified_checkpoint = state.current_justified_checkpoint
|
||||
|
||||
## Spec:
|
||||
## state.justification_bits[1:] = state.justification_bits[:-1]
|
||||
## state.justification_bits[0] = 0b0
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#constants
|
||||
const JUSTIFICATION_BITS_LENGTH = 4
|
||||
|
||||
state.justification_bits = (state.justification_bits shl 1) and
|
||||
cast[uint8]((2^JUSTIFICATION_BITS_LENGTH) - 1)
|
||||
|
||||
let total_active_balance = total_balances.current_epoch
|
||||
if total_balances.previous_epoch_target_attesters * 3 >=
|
||||
total_active_balance * 2:
|
||||
state.current_justified_checkpoint =
|
||||
Checkpoint(epoch: previous_epoch,
|
||||
root: get_block_root(state, previous_epoch))
|
||||
state.justification_bits.setBit 1
|
||||
|
||||
trace "Justified with previous epoch",
|
||||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.current_justified_checkpoint)
|
||||
elif verifyFinalization in flags:
|
||||
warn "Low attestation participation in previous epoch",
|
||||
total_balances, epoch = get_current_epoch(state)
|
||||
|
||||
if total_balances.current_epoch_target_attesters * 3 >=
|
||||
total_active_balance * 2:
|
||||
state.current_justified_checkpoint =
|
||||
Checkpoint(epoch: current_epoch,
|
||||
root: get_block_root(state, current_epoch))
|
||||
state.justification_bits.setBit 0
|
||||
|
||||
trace "Justified with current epoch",
|
||||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.current_justified_checkpoint)
|
||||
|
||||
# Process finalizations
|
||||
let bitfield = state.justification_bits
|
||||
|
||||
## The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th
|
||||
## as source
|
||||
if (bitfield and 0b1110) == 0b1110 and
|
||||
old_previous_justified_checkpoint.epoch + 3 == current_epoch:
|
||||
state.finalized_checkpoint = old_previous_justified_checkpoint
|
||||
|
||||
trace "Finalized with rule 234",
|
||||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.finalized_checkpoint)
|
||||
|
||||
## The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as
|
||||
## source
|
||||
if (bitfield and 0b110) == 0b110 and
|
||||
old_previous_justified_checkpoint.epoch + 2 == current_epoch:
|
||||
state.finalized_checkpoint = old_previous_justified_checkpoint
|
||||
|
||||
trace "Finalized with rule 23",
|
||||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.finalized_checkpoint)
|
||||
|
||||
## The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as
|
||||
## source
|
||||
if (bitfield and 0b111) == 0b111 and
|
||||
old_current_justified_checkpoint.epoch + 2 == current_epoch:
|
||||
state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
|
||||
trace "Finalized with rule 123",
|
||||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.finalized_checkpoint)
|
||||
|
||||
## The 1st/2nd most recent epochs are justified, the 1st using the 2nd as
|
||||
## source
|
||||
if (bitfield and 0b11) == 0b11 and
|
||||
old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
||||
state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
|
||||
trace "Finalized with rule 12",
|
||||
current_epoch = current_epoch,
|
||||
checkpoint = shortLog(state.finalized_checkpoint)
|
||||
|
||||
proc process_justification_and_finalization*(state: var altair.BeaconState,
|
||||
total_balances: TotalBalances, flags: UpdateFlags = {}) {.nbench.} =
|
||||
# Initial FFG checkpoint values have a `0x00` stub for `root`.
|
||||
# Skip FFG updates in the first two epochs to avoid corner cases that might
|
||||
# result in modifying this stub.
|
||||
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
||||
return
|
||||
let
|
||||
# these ultimately differ from phase0 only in these lines
|
||||
# ref: https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/phase0/beacon-chain.md#justification-and-finalization
|
||||
previous_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state))
|
||||
current_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, get_current_epoch(state))
|
||||
previous_target_balance = get_total_balance(state, previous_indices)
|
||||
current_target_balance = get_total_balance(state, current_indices)
|
||||
weigh_justification_and_finalization(state, total_balances, previous_target_balance, current_target_balance, flags)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#helpers
|
||||
func get_base_reward_sqrt*(state: BeaconState, index: ValidatorIndex,
|
||||
func get_base_reward_sqrt*(state: phase0.BeaconState, index: ValidatorIndex,
|
||||
total_balance_sqrt: auto): Gwei =
|
||||
# Spec function recalculates total_balance every time, which creates an
|
||||
# O(n^2) situation.
|
||||
|
@ -280,9 +399,14 @@ func get_proposer_reward(base_reward: Gwei): Gwei =
|
|||
func is_in_inactivity_leak(finality_delay: uint64): bool =
|
||||
finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
||||
|
||||
func get_finality_delay(state: BeaconState): uint64 =
|
||||
func get_finality_delay(state: SomeBeaconState): uint64 =
|
||||
get_previous_epoch(state) - state.finalized_checkpoint.epoch
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/phase0/beacon-chain.md#rewards-and-penalties-1
|
||||
func is_in_inactivity_leak(state: altair.BeaconState): bool =
|
||||
# TODO remove this, see above
|
||||
get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
||||
|
||||
func get_attestation_component_delta(is_unslashed_attester: bool,
|
||||
attesting_balance: Gwei,
|
||||
total_balance: Gwei,
|
||||
|
@ -311,7 +435,7 @@ func get_source_delta*(validator: RewardStatus,
|
|||
## Return attester micro-rewards/penalties for source-vote for each validator.
|
||||
get_attestation_component_delta(
|
||||
validator.is_previous_epoch_attester.isSome() and
|
||||
(isSlashed notin validator.flags),
|
||||
not (validator.flags.contains RewardFlags.isSlashed),
|
||||
total_balances.previous_epoch_attesters,
|
||||
total_balances.current_epoch,
|
||||
base_reward,
|
||||
|
@ -323,8 +447,8 @@ func get_target_delta*(validator: RewardStatus,
|
|||
finality_delay: uint64): RewardDelta =
|
||||
## Return attester micro-rewards/penalties for target-vote for each validator.
|
||||
get_attestation_component_delta(
|
||||
isPreviousEpochTargetAttester in validator.flags and
|
||||
(isSlashed notin validator.flags),
|
||||
validator.flags.contains(RewardFlags.isPreviousEpochTargetAttester) and
|
||||
not (validator.flags.contains(RewardFlags.isSlashed)),
|
||||
total_balances.previous_epoch_target_attesters,
|
||||
total_balances.current_epoch,
|
||||
base_reward,
|
||||
|
@ -336,8 +460,8 @@ func get_head_delta*(validator: RewardStatus,
|
|||
finality_delay: uint64): RewardDelta =
|
||||
## Return attester micro-rewards/penalties for head-vote for each validator.
|
||||
get_attestation_component_delta(
|
||||
isPreviousEpochHeadAttester in validator.flags and
|
||||
(isSlashed notin validator.flags),
|
||||
validator.flags.contains(RewardFlags.isPreviousEpochHeadAttester) and
|
||||
((not validator.flags.contains(RewardFlags.isSlashed))),
|
||||
total_balances.previous_epoch_head_attesters,
|
||||
total_balances.current_epoch,
|
||||
base_reward,
|
||||
|
@ -347,7 +471,7 @@ func get_inclusion_delay_delta*(validator: RewardStatus,
|
|||
base_reward: uint64):
|
||||
(RewardDelta, Option[(uint64, RewardDelta)]) =
|
||||
## Return proposer and inclusion delay micro-rewards/penalties for each validator.
|
||||
if validator.is_previous_epoch_attester.isSome() and (isSlashed notin validator.flags):
|
||||
if validator.is_previous_epoch_attester.isSome() and ((not validator.flags.contains(RewardFlags.isSlashed))):
|
||||
let
|
||||
inclusion_info = validator.is_previous_epoch_attester.get()
|
||||
proposer_reward = get_proposer_reward(base_reward)
|
||||
|
@ -373,8 +497,8 @@ func get_inactivity_penalty_delta*(validator: RewardStatus,
|
|||
# Additionally, all validators whose FFG target didn't match are penalized extra
|
||||
# This condition is equivalent to this condition from the spec:
|
||||
# `index not in get_unslashed_attesting_indices(state, matching_target_attestations)`
|
||||
if (isSlashed in validator.flags) or
|
||||
(isPreviousEpochTargetAttester notin validator.flags):
|
||||
if (validator.flags.contains(RewardFlags.isSlashed)) or
|
||||
((not validator.flags.contains(RewardFlags.isPreviousEpochTargetAttester))):
|
||||
delta.penalties +=
|
||||
validator.current_epoch_effective_balance * finality_delay div
|
||||
INACTIVITY_PENALTY_QUOTIENT
|
||||
|
@ -382,7 +506,7 @@ func get_inactivity_penalty_delta*(validator: RewardStatus,
|
|||
delta
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_attestation_deltas
|
||||
func get_attestation_deltas(state: BeaconState, rewards: var RewardInfo) =
|
||||
func get_attestation_deltas(state: phase0.BeaconState, rewards: var RewardInfo) =
|
||||
## Update rewards with attestation reward/penalty deltas for each validator.
|
||||
|
||||
let
|
||||
|
@ -425,9 +549,81 @@ func get_attestation_deltas(state: BeaconState, rewards: var RewardInfo) =
|
|||
rewards.statuses[proposer_index].delta.add(
|
||||
proposer_delta.get()[1])
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_base_reward_per_increment
|
||||
func get_base_reward_per_increment(state: altair.BeaconState, total_balances: TotalBalances): Gwei =
|
||||
EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR div
|
||||
integer_squareroot(total_balances.current_epoch())
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_base_reward
|
||||
func get_base_reward(state: altair.BeaconState, index: ValidatorIndex, total_balances: TotalBalances): Gwei =
|
||||
## Return the base reward for the validator defined by ``index`` with respect
|
||||
## to the current ``state``.
|
||||
##
|
||||
## Note: An optimally performing validator can earn one base reward per epoch
|
||||
## over a long time horizon. This takes into account both per-epoch (e.g.
|
||||
## attestation) and intermittent duties (e.g. block proposal and sync
|
||||
## committees).
|
||||
let increments =
|
||||
state.validators[index].effective_balance div EFFECTIVE_BALANCE_INCREMENT
|
||||
increments * get_base_reward_per_increment(state, total_balances)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_flag_index_deltas
|
||||
proc get_flag_index_deltas(state: altair.BeaconState, flag_index: int, total_balances: TotalBalances):
|
||||
(seq[Gwei], seq[Gwei]) =
|
||||
## Return the deltas for a given ``flag_index`` by scanning through the
|
||||
## participation flags.
|
||||
var
|
||||
rewards = repeat(Gwei(0), len(state.validators))
|
||||
penalties = repeat(Gwei(0), len(state.validators))
|
||||
let
|
||||
previous_epoch = get_previous_epoch(state)
|
||||
unslashed_participating_indices = get_unslashed_participating_indices(state, flag_index, previous_epoch)
|
||||
weight = PARTICIPATION_FLAG_WEIGHTS[flag_index].uint64 # safe
|
||||
unslashed_participating_balance = get_total_balance(state, unslashed_participating_indices)
|
||||
unslashed_participating_increments = unslashed_participating_balance div EFFECTIVE_BALANCE_INCREMENT
|
||||
active_increments = total_balances.current_epoch() div EFFECTIVE_BALANCE_INCREMENT
|
||||
|
||||
for index in 0 ..< state.validators.len:
|
||||
# TODO Obviously not great
|
||||
let v = state.validators[index]
|
||||
if not (is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)):
|
||||
continue
|
||||
|
||||
let base_reward = get_base_reward(state, index.ValidatorIndex, total_balances)
|
||||
if index.ValidatorIndex in unslashed_participating_indices:
|
||||
if not is_in_inactivity_leak(state):
|
||||
let reward_numerator = base_reward * weight * unslashed_participating_increments
|
||||
rewards[index] += Gwei(reward_numerator div (active_increments * WEIGHT_DENOMINATOR))
|
||||
elif flag_index != TIMELY_HEAD_FLAG_INDEX:
|
||||
penalties[index] += Gwei(base_reward * weight div WEIGHT_DENOMINATOR)
|
||||
(rewards, penalties)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas
|
||||
func get_inactivity_penalty_deltas(state: altair.BeaconState): (seq[Gwei], seq[Gwei]) =
|
||||
## Return the inactivity penalty deltas by considering timely target
|
||||
## participation flags and inactivity scores.
|
||||
var
|
||||
rewards = repeat(Gwei(0), len(state.validators))
|
||||
penalties = repeat(Gwei(0), len(state.validators))
|
||||
let
|
||||
previous_epoch = get_previous_epoch(state)
|
||||
matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, previous_epoch)
|
||||
for index in 0 ..< state.validators.len:
|
||||
# get_eligible_validator_indices()
|
||||
let v = state.validators[index]
|
||||
if not (is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)):
|
||||
continue
|
||||
|
||||
if not (index.ValidatorIndex in matching_target_indices):
|
||||
let
|
||||
penalty_numerator = state.validators[index].effective_balance * state.inactivity_scores[index]
|
||||
penalty_denominator = uint64(INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR)
|
||||
penalties[index] += Gwei(penalty_numerator div penalty_denominator)
|
||||
(rewards, penalties)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#process_rewards_and_penalties
|
||||
func process_rewards_and_penalties(
|
||||
state: var BeaconState, rewards: var RewardInfo) {.nbench.} =
|
||||
state: var phase0.BeaconState, rewards: var RewardInfo) {.nbench.} =
|
||||
# No rewards are applied at the end of `GENESIS_EPOCH` because rewards are
|
||||
# for work done in the previous epoch
|
||||
doAssert rewards.statuses.len == state.validators.len
|
||||
|
@ -446,12 +642,42 @@ func process_rewards_and_penalties(
|
|||
increase_balance(state.balances.asSeq()[idx], v.delta.rewards)
|
||||
decrease_balance(state.balances.asSeq()[idx], v.delta.penalties)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#rewards-and-penalties
|
||||
proc process_rewards_and_penalties(
|
||||
state: var altair.BeaconState, rewards: var RewardInfo) {.nbench.} =
|
||||
# No rewards are applied at the end of `GENESIS_EPOCH` because rewards are
|
||||
# for work done in the previous epoch
|
||||
doAssert rewards.statuses.len == state.validators.len
|
||||
|
||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||
return
|
||||
|
||||
# TODO look at phase0 optimizations, however relevant they still are. Altair
|
||||
# is supposed to incorporate some of this into the protocol, so re-assess
|
||||
# TODO efficiency-wise, presumably a better way. look at again, once tests pass
|
||||
var deltas = mapIt(0 ..< PARTICIPATION_FLAG_WEIGHTS.len, get_flag_index_deltas(state, it, rewards.total_balances))
|
||||
deltas.add get_inactivity_penalty_deltas(state)
|
||||
for (rewards, penalties) in deltas:
|
||||
for index in 0 ..< len(state.validators):
|
||||
increase_balance(state, ValidatorIndex(index), rewards[index])
|
||||
decrease_balance(state, ValidatorIndex(index), penalties[index])
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings
|
||||
func process_slashings*(state: var BeaconState, total_balance: Gwei) {.nbench.}=
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#slashings
|
||||
func process_slashings*(state: var SomeBeaconState, total_balance: Gwei) {.nbench.}=
|
||||
let
|
||||
epoch = get_current_epoch(state)
|
||||
multiplier =
|
||||
# tradeoff here about interleaving phase0/altair, but for these
|
||||
# single-constant changes...
|
||||
uint64(when state is phase0.BeaconState:
|
||||
PROPORTIONAL_SLASHING_MULTIPLIER
|
||||
elif state is altair.BeaconState:
|
||||
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
|
||||
else:
|
||||
raiseAssert "process_slashings: incorrect BeaconState type")
|
||||
adjusted_total_slashing_balance =
|
||||
min(sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER, total_balance)
|
||||
min(sum(state.slashings) * multiplier, total_balance)
|
||||
|
||||
for index in 0..<state.validators.len:
|
||||
let validator = unsafeAddr state.validators.asSeq()[index]
|
||||
|
@ -465,16 +691,16 @@ func process_slashings*(state: var BeaconState, total_balance: Gwei) {.nbench.}=
|
|||
let penalty = penalty_numerator div total_balance * increment
|
||||
decrease_balance(state, index.ValidatorIndex, penalty)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#eth1-data-votes-updates
|
||||
func process_eth1_data_reset*(state: var BeaconState) {.nbench.} =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#eth1-data-votes-updates
|
||||
func process_eth1_data_reset*(state: var SomeBeaconState) {.nbench.} =
|
||||
let next_epoch = get_current_epoch(state) + 1
|
||||
|
||||
# Reset eth1 data votes
|
||||
if next_epoch mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0:
|
||||
state.eth1_data_votes = default(type state.eth1_data_votes)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#effective-balances-updates
|
||||
func process_effective_balance_updates*(state: var BeaconState) {.nbench.} =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#effective-balances-updates
|
||||
func process_effective_balance_updates*(state: var SomeBeaconState) {.nbench.} =
|
||||
# Update effective balances with hysteresis
|
||||
for index in 0..<state.validators.len:
|
||||
let balance = state.balances.asSeq()[index]
|
||||
|
@ -492,15 +718,15 @@ func process_effective_balance_updates*(state: var BeaconState) {.nbench.} =
|
|||
balance - balance mod EFFECTIVE_BALANCE_INCREMENT,
|
||||
MAX_EFFECTIVE_BALANCE)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#slashings-balances-updates
|
||||
func process_slashings_reset*(state: var BeaconState) {.nbench.} =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#slashings-balances-updates
|
||||
func process_slashings_reset*(state: var SomeBeaconState) {.nbench.} =
|
||||
let next_epoch = get_current_epoch(state) + 1
|
||||
|
||||
# Reset slashings
|
||||
state.slashings[int(next_epoch mod EPOCHS_PER_SLASHINGS_VECTOR)] = 0.Gwei
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#randao-mixes-updates
|
||||
func process_randao_mixes_reset*(state: var BeaconState) {.nbench.} =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#randao-mixes-updates
|
||||
func process_randao_mixes_reset*(state: var SomeBeaconState) {.nbench.} =
|
||||
let
|
||||
current_epoch = get_current_epoch(state)
|
||||
next_epoch = current_epoch + 1
|
||||
|
@ -509,8 +735,8 @@ func process_randao_mixes_reset*(state: var BeaconState) {.nbench.} =
|
|||
state.randao_mixes[next_epoch mod EPOCHS_PER_HISTORICAL_VECTOR] =
|
||||
get_randao_mix(state, current_epoch)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#historical-roots-updates
|
||||
func process_historical_roots_update*(state: var BeaconState) {.nbench.} =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#historical-roots-updates
|
||||
func process_historical_roots_update*(state: var SomeBeaconState) {.nbench.} =
|
||||
# Set historical root accumulator
|
||||
let next_epoch = get_current_epoch(state) + 1
|
||||
|
||||
|
@ -523,15 +749,54 @@ func process_historical_roots_update*(state: var BeaconState) {.nbench.} =
|
|||
[hash_tree_root(state.block_roots), hash_tree_root(state.state_roots)]):
|
||||
raiseAssert "no more room for historical roots, so long and thanks for the fish!"
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#participation-records-rotation
|
||||
func process_participation_record_updates*(state: var BeaconState) {.nbench.} =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#participation-records-rotation
|
||||
func process_participation_record_updates*(state: var phase0.BeaconState) {.nbench.} =
|
||||
# Rotate current/previous epoch attestations - using swap avoids copying all
|
||||
# elements using a slow genericSeqAssign
|
||||
state.previous_epoch_attestations.clear()
|
||||
swap(state.previous_epoch_attestations, state.current_epoch_attestations)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#participation-flags-updates
|
||||
func process_participation_flag_updates(state: var altair.BeaconState) =
|
||||
state.previous_epoch_participation = state.current_epoch_participation
|
||||
|
||||
# TODO more subtle clearing
|
||||
state.current_epoch_participation.clear()
|
||||
for _ in 0 ..< state.validators.len:
|
||||
doAssert state.current_epoch_participation.add 0.ParticipationFlags
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#sync-committee-updates
|
||||
proc process_sync_committee_updates(state: var altair.BeaconState) =
|
||||
let next_epoch = get_current_epoch(state) + 1
|
||||
if next_epoch mod EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
|
||||
state.current_sync_committee = state.next_sync_committee
|
||||
state.next_sync_committee = get_next_sync_committee(state)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#inactivity-scores
|
||||
func process_inactivity_updates(state: var altair.BeaconState) =
|
||||
# Score updates based on previous epoch participation, skip genesis epoch
|
||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||
return
|
||||
|
||||
# TODO actually implement get_eligible_validator_indices() as an iterator
|
||||
let previous_epoch = get_previous_epoch(state) # get_eligible_validator_indices()
|
||||
for index in 0'u64 ..< state.validators.lenu64:
|
||||
# get_eligible_validator_indices()
|
||||
let v = state.validators[index]
|
||||
if not (is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)):
|
||||
continue
|
||||
|
||||
# Increase inactivity score of inactive validators
|
||||
if index.ValidatorIndex in get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state)):
|
||||
state.inactivity_scores[index] -= min(1'u64, state.inactivity_scores[index])
|
||||
else:
|
||||
state.inactivity_scores[index] += INACTIVITY_SCORE_BIAS
|
||||
# Decrease the score of all validators for forgiveness when not during a leak
|
||||
if not is_in_inactivity_leak(state):
|
||||
state.inactivity_scores[index] -= min(INACTIVITY_SCORE_RECOVERY_RATE.uint64, state.inactivity_scores[index])
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#final-updates
|
||||
func process_final_updates*(state: var BeaconState) {.nbench.} =
|
||||
func process_final_updates*(state: var phase0.BeaconState) {.nbench.} =
|
||||
# This function's a wrapper over the HF1 split/refactored HF1 version. TODO
|
||||
# remove once test vectors become available for each HF1 function.
|
||||
process_eth1_data_reset(state)
|
||||
|
@ -543,7 +808,7 @@ func process_final_updates*(state: var BeaconState) {.nbench.} =
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#epoch-processing
|
||||
proc process_epoch*(
|
||||
state: var BeaconState, flags: UpdateFlags, cache: var StateCache,
|
||||
state: var phase0.BeaconState, flags: UpdateFlags, cache: var StateCache,
|
||||
rewards: var RewardInfo) {.nbench.} =
|
||||
let currentEpoch = get_current_epoch(state)
|
||||
trace "process_epoch",
|
||||
|
@ -576,3 +841,53 @@ proc process_epoch*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#final-updates
|
||||
process_final_updates(state)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#epoch-processing
|
||||
proc process_epoch*(
|
||||
state: var altair.BeaconState, flags: UpdateFlags, cache: var StateCache,
|
||||
rewards: var RewardInfo) {.nbench.} =
|
||||
let currentEpoch = get_current_epoch(state)
|
||||
trace "process_epoch",
|
||||
current_epoch = currentEpoch
|
||||
init(rewards, state)
|
||||
when false:
|
||||
# TODO this is the key thing which needs porting over
|
||||
rewards.process_attestations(state, cache)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#justification-and-finalization
|
||||
process_justification_and_finalization(state, rewards.total_balances, flags)
|
||||
|
||||
# state.slot hasn't been incremented yet.
|
||||
if verifyFinalization in flags and currentEpoch >= 2:
|
||||
doAssert state.current_justified_checkpoint.epoch + 2 >= currentEpoch
|
||||
|
||||
if verifyFinalization in flags and currentEpoch >= 3:
|
||||
# Rule 2/3/4 finalization results in the most pessimal case. The other
|
||||
# three finalization rules finalize more quickly as long as the any of
|
||||
# the finalization rules triggered.
|
||||
doAssert state.finalized_checkpoint.epoch + 3 >= currentEpoch
|
||||
|
||||
process_inactivity_updates(state) # [New in Altair]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1
|
||||
process_rewards_and_penalties(state, rewards)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#registry-updates
|
||||
process_registry_updates(state, cache)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings
|
||||
process_slashings(state, rewards.total_balances.current_epoch)
|
||||
|
||||
process_eth1_data_reset(state)
|
||||
|
||||
process_effective_balance_updates(state)
|
||||
|
||||
process_slashings_reset(state)
|
||||
|
||||
process_randao_mixes_reset(state)
|
||||
|
||||
process_historical_roots_update(state)
|
||||
|
||||
process_participation_flag_updates(state) # [New in Altair]
|
||||
|
||||
process_sync_committee_updates(state) # [New in Altair]
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import
|
||||
std/[options, math, tables],
|
||||
./datatypes, ./digest, ./helpers
|
||||
./datatypes/[phase0, altair], ./digest, ./helpers
|
||||
|
||||
const
|
||||
SEED_SIZE = sizeof(Eth2Digest)
|
||||
|
@ -122,8 +122,8 @@ func shuffle_list*(input: var seq[ValidatorIndex], seed: Eth2Digest) =
|
|||
|
||||
shuffle
|
||||
|
||||
func get_shuffled_active_validator_indices*(state: BeaconState, epoch: Epoch):
|
||||
seq[ValidatorIndex] =
|
||||
func get_shuffled_active_validator_indices*(
|
||||
state: SomeBeaconState, epoch: Epoch): seq[ValidatorIndex] =
|
||||
# Non-spec function, to cache a data structure from which one can cheaply
|
||||
# compute both get_active_validator_indexes() and get_beacon_committee().
|
||||
var active_validator_indices = get_active_validator_indices(state, epoch)
|
||||
|
@ -134,7 +134,7 @@ func get_shuffled_active_validator_indices*(state: BeaconState, epoch: Epoch):
|
|||
active_validator_indices
|
||||
|
||||
func get_shuffled_active_validator_indices*(
|
||||
cache: var StateCache, state: BeaconState, epoch: Epoch):
|
||||
cache: var StateCache, state: SomeBeaconState, epoch: Epoch):
|
||||
var seq[ValidatorIndex] =
|
||||
# `cache` comes first because of nim's borrowing rules for the `var` return -
|
||||
# the `var` returns avoids copying the validator set.
|
||||
|
@ -145,7 +145,7 @@ func get_shuffled_active_validator_indices*(
|
|||
return cache.shuffled_active_validator_indices.mgetOrPut(epoch, indices)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_active_validator_indices
|
||||
func count_active_validators*(state: BeaconState,
|
||||
func count_active_validators*(state: SomeBeaconState,
|
||||
epoch: Epoch,
|
||||
cache: var StateCache): uint64 =
|
||||
cache.get_shuffled_active_validator_indices(state, epoch).lenu64
|
||||
|
@ -156,7 +156,7 @@ func get_committee_count_per_slot*(num_active_validators: uint64): uint64 =
|
|||
num_active_validators div SLOTS_PER_EPOCH div TARGET_COMMITTEE_SIZE,
|
||||
1'u64, MAX_COMMITTEES_PER_SLOT)
|
||||
|
||||
func get_committee_count_per_slot*(state: BeaconState,
|
||||
func get_committee_count_per_slot*(state: SomeBeaconState,
|
||||
epoch: Epoch,
|
||||
cache: var StateCache): uint64 =
|
||||
# Return the number of committees at ``slot``.
|
||||
|
@ -168,7 +168,7 @@ func get_committee_count_per_slot*(state: BeaconState,
|
|||
# Otherwise, get_beacon_committee(...) cannot access some committees.
|
||||
doAssert (SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT) >= uint64(result)
|
||||
|
||||
func get_committee_count_per_slot*(state: BeaconState,
|
||||
func get_committee_count_per_slot*(state: SomeBeaconState,
|
||||
slot: Slot,
|
||||
cache: var StateCache): uint64 =
|
||||
get_committee_count_per_slot(state, slot.compute_epoch_at_slot, cache)
|
||||
|
@ -181,8 +181,9 @@ func get_previous_epoch*(current_epoch: Epoch): Epoch =
|
|||
else:
|
||||
current_epoch - 1
|
||||
|
||||
func get_previous_epoch*(state: BeaconState): Epoch =
|
||||
func get_previous_epoch*(state: SomeBeaconState): Epoch =
|
||||
## Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
|
||||
# Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
|
||||
get_previous_epoch(get_current_epoch(state))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#compute_committee
|
||||
|
@ -228,7 +229,7 @@ func compute_committee_len*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_beacon_committee
|
||||
iterator get_beacon_committee*(
|
||||
state: BeaconState, slot: Slot, index: CommitteeIndex,
|
||||
state: SomeBeaconState, slot: Slot, index: CommitteeIndex,
|
||||
cache: var StateCache): ValidatorIndex =
|
||||
## Return the beacon committee at ``slot`` for ``index``.
|
||||
let
|
||||
|
@ -242,7 +243,7 @@ iterator get_beacon_committee*(
|
|||
): yield idx
|
||||
|
||||
func get_beacon_committee*(
|
||||
state: BeaconState, slot: Slot, index: CommitteeIndex,
|
||||
state: SomeBeaconState, slot: Slot, index: CommitteeIndex,
|
||||
cache: var StateCache): seq[ValidatorIndex] =
|
||||
## Return the beacon committee at ``slot`` for ``index``.
|
||||
let
|
||||
|
@ -257,7 +258,7 @@ func get_beacon_committee*(
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_beacon_committee
|
||||
func get_beacon_committee_len*(
|
||||
state: BeaconState, slot: Slot, index: CommitteeIndex,
|
||||
state: SomeBeaconState, slot: Slot, index: CommitteeIndex,
|
||||
cache: var StateCache): uint64 =
|
||||
# Return the number of members in the beacon committee at ``slot`` for ``index``.
|
||||
let
|
||||
|
@ -272,7 +273,7 @@ func get_beacon_committee_len*(
|
|||
)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#compute_shuffled_index
|
||||
func compute_shuffled_index(
|
||||
func compute_shuffled_index*(
|
||||
index: uint64, index_count: uint64, seed: Eth2Digest): uint64 =
|
||||
## Return the shuffled index corresponding to ``seed`` (and ``index_count``).
|
||||
doAssert index < index_count
|
||||
|
@ -307,8 +308,8 @@ func compute_shuffled_index(
|
|||
cur_idx_permuted
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#compute_proposer_index
|
||||
func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex],
|
||||
seed: Eth2Digest): Option[ValidatorIndex] =
|
||||
func compute_proposer_index(state: SomeBeaconState,
|
||||
indices: seq[ValidatorIndex], seed: Eth2Digest): Option[ValidatorIndex] =
|
||||
## Return from ``indices`` a random index sampled by effective balance.
|
||||
const MAX_RANDOM_BYTE = 255
|
||||
|
||||
|
@ -334,7 +335,8 @@ func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex],
|
|||
i += 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_beacon_proposer_index
|
||||
func get_beacon_proposer_index*(state: BeaconState, cache: var StateCache, slot: Slot):
|
||||
func get_beacon_proposer_index*(
|
||||
state: SomeBeaconState, cache: var StateCache, slot: Slot):
|
||||
Option[ValidatorIndex] =
|
||||
cache.beacon_proposer_indices.withValue(slot, proposer) do:
|
||||
return proposer[]
|
||||
|
@ -366,6 +368,6 @@ func get_beacon_proposer_index*(state: BeaconState, cache: var StateCache, slot:
|
|||
return res
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_beacon_proposer_index
|
||||
func get_beacon_proposer_index*(state: BeaconState, cache: var StateCache):
|
||||
func get_beacon_proposer_index*(state: SomeBeaconState, cache: var StateCache):
|
||||
Option[ValidatorIndex] =
|
||||
get_beacon_proposer_index(state, cache, state.slot)
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
import
|
||||
std/[typetraits, options],
|
||||
stew/[endians2, objects],
|
||||
../spec/[digest, datatypes], ./types, ./spec_types, ./merkleization
|
||||
../spec/digest, ./types, ./spec_types, ./merkleization,
|
||||
../spec/datatypes/[phase0, altair]
|
||||
|
||||
template raiseIncorrectSize(T: type) =
|
||||
const typeName = name(T)
|
||||
|
@ -59,6 +60,9 @@ template fromSszBytes*(T: type Slot, bytes: openArray[byte]): T =
|
|||
template fromSszBytes*(T: type Epoch, bytes: openArray[byte]): T =
|
||||
T fromSszBytes(uint64, bytes)
|
||||
|
||||
template fromSszBytes*(T: type ParticipationFlags, bytes: openArray[byte]): T =
|
||||
T fromSszBytes(uint8, bytes)
|
||||
|
||||
func fromSszBytes*(T: type ForkDigest, bytes: openArray[byte]): T {.raisesssz.} =
|
||||
if bytes.len != sizeof(result):
|
||||
raiseIncorrectSize T
|
||||
|
@ -252,7 +256,8 @@ func readSszValue*[T](input: openArray[byte],
|
|||
type(field),
|
||||
input.toOpenArray(int(startOffset), int(endOffset - 1)))
|
||||
|
||||
when val is SignedBeaconBlock | TrustedSignedBeaconBlock:
|
||||
when val is phase0.SignedBeaconBlock | phase0.TrustedSignedBeaconBlock |
|
||||
altair.SignedBeaconBlock | altair.TrustedSignedBeaconBlock:
|
||||
if updateRoot:
|
||||
val.root = hash_tree_root(val.message)
|
||||
else:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Copyright (c) 2021 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
@ -20,6 +20,7 @@ import
|
|||
./test_fixture_operations_attester_slashings,
|
||||
./test_fixture_operations_block_header,
|
||||
./test_fixture_operations_proposer_slashings,
|
||||
./test_fixture_operations_sync_committee,
|
||||
./test_fixture_operations_voluntary_exit
|
||||
|
||||
summarizeLongTests("FixtureAll")
|
||||
|
|
|
@ -18,6 +18,7 @@ import
|
|||
../testutil, ./fixtures_utils
|
||||
|
||||
const
|
||||
# TODO NimYAML issue
|
||||
SpecDir = currentSourcePath.rsplit(DirSep, 1)[0] /
|
||||
".."/".."/"beacon_chain"/"spec"
|
||||
Config = SszTestsDir/const_preset/"config"/"phase0.yaml"
|
||||
|
|
|
@ -14,14 +14,15 @@ import
|
|||
unittest2,
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, beaconstate],
|
||||
../../beacon_chain/spec/beaconstate,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const OperationsAttestationsDir = SszTestsDir/const_preset/"phase0"/"operations"/"attestation"/"pyspec_tests"
|
||||
const OperationsAttestationsDir = SszTestsDir/const_preset/"altair"/"operations"/"attestation"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
|
|
@ -13,14 +13,15 @@ import
|
|||
# Utilities
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, state_transition_block],
|
||||
../../beacon_chain/spec/state_transition_block,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const OpAttSlashingDir = SszTestsDir/const_preset/"phase0"/"operations"/"attester_slashing"/"pyspec_tests"
|
||||
const OpAttSlashingDir = SszTestsDir/const_preset/"altair"/"operations"/"attester_slashing"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
|
|
@ -13,14 +13,15 @@ import
|
|||
# Utilities
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, state_transition_block, crypto],
|
||||
../../beacon_chain/spec/[state_transition_block, crypto],
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const OpBlockHeaderDir = SszTestsDir/const_preset/"phase0"/"operations"/"block_header"/"pyspec_tests"
|
||||
const OpBlockHeaderDir = SszTestsDir/const_preset/"altair"/"operations"/"block_header"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
|
|
@ -13,14 +13,15 @@ import
|
|||
# Utilities
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, beaconstate, presets],
|
||||
../../beacon_chain/spec/[beaconstate, presets],
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const OperationsDepositsDir = SszTestsDir/const_preset/"phase0"/"operations"/"deposit"/"pyspec_tests"
|
||||
const OperationsDepositsDir = SszTestsDir/const_preset/"altair"/"operations"/"deposit"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
|
|
@ -13,14 +13,18 @@ import
|
|||
# Utilities
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, state_transition_block],
|
||||
../../beacon_chain/spec/state_transition_block,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const OpProposerSlashingDir = SszTestsDir/const_preset/"phase0"/"operations"/"proposer_slashing"/"pyspec_tests"
|
||||
when isMainModule:
|
||||
import chronicles # or some random compile error happens...
|
||||
|
||||
const OpProposerSlashingDir = SszTestsDir/const_preset/"altair"/"operations"/"proposer_slashing"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
import
|
||||
# Standard library
|
||||
os,
|
||||
# Utilities
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/state_transition_block,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
when isMainModule:
|
||||
import chronicles # or some random compile error happens...
|
||||
|
||||
const OpSyncCommitteeDir = SszTestsDir/const_preset/"altair"/"operations"/"sync_committee"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
# in the future: Nim supports up to 3500 globals
|
||||
# but unittest with the macro/templates put everything as globals
|
||||
# https://github.com/nim-lang/Nim/issues/12084#issue-486866402
|
||||
|
||||
let testDir = OpSyncCommitteeDir / identifier
|
||||
|
||||
proc `testImpl_sync_committee _ identifier`() =
|
||||
|
||||
var prefix: string
|
||||
if existsFile(testDir/"post.ssz_snappy"):
|
||||
prefix = "[Valid] "
|
||||
else:
|
||||
prefix = "[Invalid] "
|
||||
|
||||
test prefix & identifier:
|
||||
let syncAggregate = parseTest(
|
||||
testDir/"sync_aggregate.ssz_snappy", SSZ, SyncAggregate)
|
||||
var
|
||||
preState =
|
||||
newClone(parseTest(testDir/"pre.ssz_snappy", SSZ, BeaconState))
|
||||
cache = StateCache()
|
||||
|
||||
if existsFile(testDir/"post.ssz_snappy"):
|
||||
let
|
||||
postState =
|
||||
newClone(parseTest(testDir/"post.ssz_snappy", SSZ, BeaconState))
|
||||
done = process_sync_committee(
|
||||
preState[], syncAggregate, cache).isOk
|
||||
doAssert done, "Valid sync aggregate not processed"
|
||||
check: preState[].hash_tree_root() == postState[].hash_tree_root()
|
||||
reportDiff(preState, postState)
|
||||
else:
|
||||
let done = process_sync_committee(preState[], syncAggregate, cache).isOk
|
||||
doAssert done == false, "We didn't expect this invalid proposer slashing to be processed."
|
||||
|
||||
`testImpl_sync_committee _ identifier`()
|
||||
|
||||
suite "Official - Operations - Sync Committee " & preset():
|
||||
for kind, path in walkDir(OpSyncCommitteeDir, true):
|
||||
runTest(path)
|
|
@ -13,14 +13,15 @@ import
|
|||
# Utilities
|
||||
stew/results,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, state_transition_block],
|
||||
../../beacon_chain/spec/state_transition_block,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const OpVoluntaryExitDir = SszTestsDir/const_preset/"phase0"/"operations"/"voluntary_exit"/"pyspec_tests"
|
||||
const OpVoluntaryExitDir = SszTestsDir/const_preset/"altair"/"operations"/"voluntary_exit"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
|
|
@ -11,15 +11,16 @@ import
|
|||
# Standard library
|
||||
os, sequtils, chronicles,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[crypto, datatypes, state_transition, presets],
|
||||
../../beacon_chain/spec/[crypto, state_transition, presets],
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils
|
||||
|
||||
const
|
||||
FinalityDir = SszTestsDir/const_preset/"phase0"/"finality"/"finality"/"pyspec_tests"
|
||||
SanityBlocksDir = SszTestsDir/const_preset/"phase0"/"sanity"/"blocks"/"pyspec_tests"
|
||||
FinalityDir = SszTestsDir/const_preset/"altair"/"finality"/"finality"/"pyspec_tests"
|
||||
SanityBlocksDir = SszTestsDir/const_preset/"altair"/"sanity"/"blocks"/"pyspec_tests"
|
||||
|
||||
proc runTest(testName, testDir, unitTestName: string) =
|
||||
# We wrap the tests in a proc to avoid running out of globals
|
||||
|
@ -73,5 +74,6 @@ suite "Official - Sanity - Blocks " & preset():
|
|||
runTest("Official - Sanity - Blocks", SanityBlocksDir, path)
|
||||
|
||||
suite "Official - Finality " & preset():
|
||||
# these seem to only exist in minimal presets, both for phase0 and altair
|
||||
for kind, path in walkDir(FinalityDir, true):
|
||||
runTest("Official - Finality", FinalityDir, path)
|
||||
|
|
|
@ -8,16 +8,18 @@
|
|||
{.used.}
|
||||
|
||||
import
|
||||
chronicles,
|
||||
# Standard library
|
||||
os, strutils,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, state_transition],
|
||||
../../beacon_chain/spec/state_transition,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
../helpers/debug_state
|
||||
|
||||
const SanitySlotsDir = SszTestsDir/const_preset/"phase0"/"sanity"/"slots"/"pyspec_tests"
|
||||
const SanitySlotsDir = SszTestsDir/const_preset/"altair"/"sanity"/"slots"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
let
|
||||
|
|
|
@ -12,7 +12,8 @@ import
|
|||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[crypto, datatypes, digest],
|
||||
../../beacon_chain/spec/[crypto, digest],
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
../../beacon_chain/ssz,
|
||||
# Status libraries
|
||||
snappy,
|
||||
|
@ -25,7 +26,7 @@ import
|
|||
# ----------------------------------------------------------------
|
||||
|
||||
const
|
||||
SSZDir = SszTestsDir/const_preset/"phase0"/"ssz_static"
|
||||
SSZDir = SszTestsDir/const_preset/"altair"/"ssz_static"
|
||||
|
||||
type
|
||||
SSZHashTreeRoot = object
|
||||
|
@ -35,7 +36,7 @@ type
|
|||
# Some have a signing_root field
|
||||
signing_root {.defaultVal: "".}: string
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#eth1block
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/altair/validator.md#eth1block
|
||||
Eth1Block* = object
|
||||
timestamp*: uint64
|
||||
deposit_root*: Eth2Digest
|
||||
|
@ -108,6 +109,7 @@ suite "Official - SSZ consensus objects " & preset():
|
|||
of "BeaconBlockHeader": checkSSZ(BeaconBlockHeader, path, hash)
|
||||
of "BeaconState": checkSSZ(BeaconState, path, hash)
|
||||
of "Checkpoint": checkSSZ(Checkpoint, path, hash)
|
||||
of "ContributionAndProof": checkSSZ(ContributionAndProof, path, hash)
|
||||
of "Deposit": checkSSZ(Deposit, path, hash)
|
||||
of "DepositData": checkSSZ(DepositData, path, hash)
|
||||
of "DepositMessage": checkSSZ(DepositMessage, path, hash)
|
||||
|
@ -117,6 +119,8 @@ suite "Official - SSZ consensus objects " & preset():
|
|||
of "ForkData": checkSSZ(ForkData, path, hash)
|
||||
of "HistoricalBatch": checkSSZ(HistoricalBatch, path, hash)
|
||||
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
|
||||
of "LightClientSnapshot": checkSSZ(LightClientSnapshot, path, hash)
|
||||
of "LightClientUpdate": checkSSZ(LightClientUpdate, path, hash)
|
||||
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
|
||||
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)
|
||||
of "SignedAggregateAndProof":
|
||||
|
@ -124,9 +128,18 @@ suite "Official - SSZ consensus objects " & preset():
|
|||
of "SignedBeaconBlock": checkSSZ(SignedBeaconBlock, path, hash)
|
||||
of "SignedBeaconBlockHeader":
|
||||
checkSSZ(SignedBeaconBlockHeader, path, hash)
|
||||
of "SignedContributionAndProof":
|
||||
checkSSZ(SignedContributionAndProof, path, hash)
|
||||
of "SignedVoluntaryExit": checkSSZ(SignedVoluntaryExit, path, hash)
|
||||
of "SigningData":
|
||||
checkSSZ(SigningData, path, hash)
|
||||
of "SigningData": checkSSZ(SigningData, path, hash)
|
||||
of "SyncAggregate": checkSSZ(SyncAggregate, path, hash)
|
||||
of "SyncAggregatorSelectionData":
|
||||
checkSSZ(SyncAggregatorSelectionData, path, hash)
|
||||
of "SyncCommittee": checkSSZ(SyncCommittee, path, hash)
|
||||
of "SyncCommitteeContribution":
|
||||
checkSSZ(SyncCommitteeContribution, path, hash)
|
||||
of "SyncCommitteeSignature":
|
||||
checkSSZ(SyncCommitteeSignature, path, hash)
|
||||
of "Validator": checkSSZ(Validator, path, hash)
|
||||
of "VoluntaryExit": checkSSZ(VoluntaryExit, path, hash)
|
||||
else:
|
||||
|
|
|
@ -11,7 +11,8 @@ import
|
|||
# Standard library
|
||||
os, strutils,
|
||||
# Beacon chain internals
|
||||
../../beacon_chain/spec/[datatypes, state_transition_epoch],
|
||||
../../beacon_chain/spec/state_transition_epoch,
|
||||
../../beacon_chain/spec/datatypes/altair,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils,
|
||||
|
@ -43,8 +44,10 @@ template runSuite(suiteDir, testName: string, transitionProc: untyped{ident}, us
|
|||
# Justification & Finalization
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
const JustificationFinalizationDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"justification_and_finalization"/"pyspec_tests"
|
||||
runSuite(JustificationFinalizationDir, "Justification & Finalization", process_justification_and_finalization, useCache = false)
|
||||
const JustificationFinalizationDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"justification_and_finalization"/"pyspec_tests"
|
||||
when false:
|
||||
# TODO
|
||||
runSuite(JustificationFinalizationDir, "Justification & Finalization", process_justification_and_finalization, useCache = false)
|
||||
|
||||
# Rewards & Penalties
|
||||
# ---------------------------------------------------------------
|
||||
|
@ -54,32 +57,36 @@ runSuite(JustificationFinalizationDir, "Justification & Finalization", process_
|
|||
# Registry updates
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
const RegistryUpdatesDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"registry_updates"/"pyspec_tests"
|
||||
const RegistryUpdatesDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"registry_updates"/"pyspec_tests"
|
||||
runSuite(RegistryUpdatesDir, "Registry updates", process_registry_updates, useCache = true)
|
||||
|
||||
# Slashings
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
const SlashingsDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"slashings"/"pyspec_tests"
|
||||
runSuite(SlashingsDir, "Slashings", process_slashings, useCache = false)
|
||||
const SlashingsDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"slashings"/"pyspec_tests"
|
||||
when false:
|
||||
# TODO needs totalbalance info
|
||||
runSuite(SlashingsDir, "Slashings", process_slashings, useCache = false)
|
||||
|
||||
# Final updates
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
const Eth1DataResetDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"eth1_data_reset/"/"pyspec_tests"
|
||||
const Eth1DataResetDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"eth1_data_reset/"/"pyspec_tests"
|
||||
runSuite(Eth1DataResetDir, "Eth1 data reset", process_eth1_data_reset, useCache = false)
|
||||
|
||||
const EffectiveBalanceUpdatesDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"effective_balance_updates"/"pyspec_tests"
|
||||
const EffectiveBalanceUpdatesDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"effective_balance_updates"/"pyspec_tests"
|
||||
runSuite(EffectiveBalanceUpdatesDir, "Effective balance updates", process_effective_balance_updates, useCache = false)
|
||||
|
||||
const SlashingsResetDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"slashings_reset"/"pyspec_tests"
|
||||
const SlashingsResetDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"slashings_reset"/"pyspec_tests"
|
||||
runSuite(SlashingsResetDir, "Slashings reset", process_slashings_reset, useCache = false)
|
||||
|
||||
const RandaoMixesResetDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"randao_mixes_reset"/"pyspec_tests"
|
||||
const RandaoMixesResetDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"randao_mixes_reset"/"pyspec_tests"
|
||||
runSuite(RandaoMixesResetDir, "RANDAO mixes reset", process_randao_mixes_reset, useCache = false)
|
||||
|
||||
const HistoricalRootsUpdateDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"historical_roots_update"/"pyspec_tests"
|
||||
const HistoricalRootsUpdateDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"historical_roots_update"/"pyspec_tests"
|
||||
runSuite(HistoricalRootsUpdateDir, "Historical roots update", process_historical_roots_update, useCache = false)
|
||||
|
||||
const ParticipationRecordsDir = SszTestsDir/const_preset/"phase0"/"epoch_processing"/"participation_record_updates"/"pyspec_tests"
|
||||
runSuite(ParticipationRecordsDir, "Participation record updates", process_participation_record_updates, useCache = false)
|
||||
const ParticipationRecordsDir = SszTestsDir/const_preset/"altair"/"epoch_processing"/"participation_record_updates"/"pyspec_tests"
|
||||
when false:
|
||||
# TODO needs totalbalance info
|
||||
runSuite(ParticipationRecordsDir, "Participation record updates", process_participation_record_updates, useCache = false)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Copyright (c) 2018-2021 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
@ -9,7 +9,7 @@ import
|
|||
# Standard library
|
||||
strformat, tables,
|
||||
# Specs
|
||||
../../beacon_chain/spec/[datatypes, state_transition_epoch, validator, helpers],
|
||||
../../beacon_chain/spec/[beaconstate, datatypes, validator, helpers],
|
||||
# Test helpers
|
||||
../helpers/digest_helpers
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
chronicles,
|
||||
options, stew/endians2,
|
||||
../beacon_chain/extras,
|
||||
../beacon_chain/validators/validator_pool,
|
||||
|
|
Loading…
Reference in New Issue