2019-06-28 13:44:44 +00:00
|
|
|
# beacon_chain
|
|
|
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
# State transition - block processing, as described in
|
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
|
|
|
#
|
|
|
|
# The purpose of this code right is primarily educational, to help piece
|
|
|
|
# together the mechanics of the beacon state and to discover potential problem
|
|
|
|
# areas.
|
|
|
|
#
|
|
|
|
# The entry point is `process_block` which is at the bottom of this file.
|
|
|
|
#
|
|
|
|
# General notes about the code (TODO):
|
|
|
|
# * It's inefficient - we quadratically copy, allocate and iterate when there
|
|
|
|
# are faster options
|
|
|
|
# * Weird styling - the sections taken from the spec use python styling while
|
|
|
|
# the others use NEP-1 - helps grepping identifiers in spec
|
|
|
|
# * We mix procedural and functional styles for no good reason, except that the
|
|
|
|
# spec does so also.
|
|
|
|
# * There are likely lots of bugs.
|
|
|
|
# * For indices, we get a mix of uint64, ValidatorIndex and int - this is currently
|
|
|
|
# swept under the rug with casts
|
|
|
|
# * The spec uses uint64 for data types, but functions in the spec often assume
|
|
|
|
# signed bigint semantics - under- and overflows ensue
|
|
|
|
# * Sane error handling is missing in most cases (yay, we'll get the chance to
|
|
|
|
# debate exceptions again!)
|
|
|
|
# When updating the code, add TODO sections to mark where there are clear
|
|
|
|
# improvements to be made - other than that, keep things similar to spec for
|
|
|
|
# now.
|
|
|
|
|
|
|
|
import # TODO - cleanup imports
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
algorithm, collections/sets, chronicles, sequtils, sets, tables,
|
2019-10-25 10:59:56 +00:00
|
|
|
../extras, ../ssz, metrics,
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
beaconstate, crypto, datatypes, digest, helpers, validator
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-10-06 04:31:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#additional-metrics
|
2019-10-21 08:11:54 +00:00
|
|
|
declareGauge beacon_current_live_validators, "Number of active validators that successfully included attestation on chain for current epoch" # On block
|
|
|
|
declareGauge beacon_previous_live_validators, "Number of active validators that successfully included attestation on chain for previous epoch" # On block
|
2019-10-06 04:31:50 +00:00
|
|
|
declareGauge beacon_pending_deposits, "Number of pending deposits (state.eth1_data.deposit_count - state.eth1_deposit_index)" # On block
|
|
|
|
declareGauge beacon_processed_deposits_total, "Number of total deposits included on chain" # On block
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#block-header
|
2019-09-09 18:40:59 +00:00
|
|
|
proc process_block_header*(
|
2019-06-28 13:44:44 +00:00
|
|
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
|
|
|
stateCache: var StateCache): bool =
|
|
|
|
# Verify that the slots match
|
|
|
|
if not (blck.slot == state.slot):
|
|
|
|
notice "Block header: slot mismatch",
|
2019-08-15 16:01:55 +00:00
|
|
|
block_slot = shortLog(blck.slot),
|
|
|
|
state_slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
# Verify that the parent matches
|
|
|
|
if skipValidation notin flags and not (blck.parent_root ==
|
|
|
|
signing_root(state.latest_block_header)):
|
2019-09-09 18:40:59 +00:00
|
|
|
# TODO: skip validation is too strong
|
|
|
|
# can't do "invalid_parent_root" test
|
2019-06-28 13:44:44 +00:00
|
|
|
notice "Block header: previous block root mismatch",
|
|
|
|
latest_block_header = state.latest_block_header,
|
|
|
|
blck = shortLog(blck),
|
|
|
|
latest_block_header_root = shortLog(signing_root(state.latest_block_header))
|
|
|
|
return false
|
|
|
|
|
|
|
|
# Save current block as the new latest block
|
|
|
|
state.latest_block_header = BeaconBlockHeader(
|
|
|
|
slot: blck.slot,
|
|
|
|
parent_root: blck.parent_root,
|
2019-07-15 12:57:18 +00:00
|
|
|
# state_root: zeroed, overwritten in the next `process_slot` call
|
2019-06-28 13:44:44 +00:00
|
|
|
body_root: hash_tree_root(blck.body),
|
2019-07-15 12:57:18 +00:00
|
|
|
# signature is always zeroed
|
2019-09-03 18:02:21 +00:00
|
|
|
# TODO - Pure BLSSig cannot be zero: https://github.com/status-im/nim-beacon-chain/issues/374
|
|
|
|
signature: BlsValue[Signature](kind: OpaqueBlob)
|
2019-06-28 13:44:44 +00:00
|
|
|
)
|
|
|
|
|
2019-09-03 18:02:21 +00:00
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
# Verify proposer is not slashed
|
|
|
|
let proposer =
|
2019-07-01 09:13:14 +00:00
|
|
|
state.validators[get_beacon_proposer_index(state, stateCache)]
|
2019-06-28 13:44:44 +00:00
|
|
|
if proposer.slashed:
|
|
|
|
notice "Block header: proposer slashed"
|
|
|
|
return false
|
|
|
|
|
|
|
|
# Verify proposer signature
|
|
|
|
if skipValidation notin flags and not bls_verify(
|
|
|
|
proposer.pubkey,
|
|
|
|
signing_root(blck).data,
|
|
|
|
blck.signature,
|
|
|
|
get_domain(state, DOMAIN_BEACON_PROPOSER)):
|
|
|
|
notice "Block header: invalid block header",
|
|
|
|
proposer_pubkey = proposer.pubkey,
|
|
|
|
block_root = shortLog(signing_root(blck)),
|
|
|
|
block_signature = blck.signature
|
|
|
|
return false
|
|
|
|
|
|
|
|
true
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#randao
|
2019-09-04 13:57:18 +00:00
|
|
|
proc process_randao(
|
2019-06-28 13:44:44 +00:00
|
|
|
state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags,
|
|
|
|
stateCache: var StateCache): bool =
|
|
|
|
let
|
2019-09-04 13:57:18 +00:00
|
|
|
epoch = state.get_current_epoch()
|
2019-06-28 13:44:44 +00:00
|
|
|
proposer_index = get_beacon_proposer_index(state, stateCache)
|
2019-07-01 09:13:14 +00:00
|
|
|
proposer = addr state.validators[proposer_index]
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
# Verify that the provided randao value is valid
|
|
|
|
if skipValidation notin flags:
|
|
|
|
if not bls_verify(
|
|
|
|
proposer.pubkey,
|
2019-09-04 13:57:18 +00:00
|
|
|
hash_tree_root(epoch.uint64).data,
|
2019-06-28 13:44:44 +00:00
|
|
|
body.randao_reveal,
|
|
|
|
get_domain(state, DOMAIN_RANDAO)):
|
|
|
|
|
|
|
|
notice "Randao mismatch", proposer_pubkey = proposer.pubkey,
|
2019-09-04 13:57:18 +00:00
|
|
|
message = epoch,
|
2019-06-28 13:44:44 +00:00
|
|
|
signature = body.randao_reveal,
|
|
|
|
slot = state.slot
|
|
|
|
return false
|
|
|
|
|
|
|
|
# Mix it in
|
|
|
|
let
|
2019-09-04 13:57:18 +00:00
|
|
|
mix = get_randao_mix(state, epoch)
|
2019-06-28 13:44:44 +00:00
|
|
|
rr = eth2hash(body.randao_reveal.getBytes()).data
|
|
|
|
|
2019-09-04 13:57:18 +00:00
|
|
|
for i in 0 ..< mix.data.len:
|
|
|
|
state.randao_mixes[epoch mod EPOCHS_PER_HISTORICAL_VECTOR].data[i] = mix.data[i] xor rr[i]
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
true
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#eth1-data
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) =
|
2019-06-28 13:44:44 +00:00
|
|
|
state.eth1_data_votes.add body.eth1_data
|
|
|
|
if state.eth1_data_votes.count(body.eth1_data) * 2 >
|
|
|
|
SLOTS_PER_ETH1_VOTING_PERIOD:
|
2019-07-01 09:42:37 +00:00
|
|
|
state.eth1_data = body.eth1_data
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#is_slashable_validator
|
2019-06-28 13:44:44 +00:00
|
|
|
func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
|
|
|
|
# Check if ``validator`` is slashable.
|
|
|
|
(not validator.slashed) and
|
|
|
|
(validator.activation_epoch <= epoch) and
|
|
|
|
(epoch < validator.withdrawable_epoch)
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#proposer-slashings
|
2019-09-11 07:50:07 +00:00
|
|
|
proc process_proposer_slashing*(
|
2019-09-10 15:29:46 +00:00
|
|
|
state: var BeaconState, proposer_slashing: ProposerSlashing,
|
|
|
|
flags: UpdateFlags, stateCache: var StateCache): bool =
|
2019-09-11 07:50:07 +00:00
|
|
|
if proposer_slashing.proposer_index.int >= state.validators.len:
|
|
|
|
notice "Proposer slashing: invalid proposer index"
|
|
|
|
return false
|
|
|
|
|
2019-09-10 15:29:46 +00:00
|
|
|
let proposer = state.validators[proposer_slashing.proposer_index.int]
|
|
|
|
|
2019-11-08 10:30:22 +00:00
|
|
|
# Verify slots match
|
|
|
|
if not (proposer_slashing.header_1.slot ==
|
|
|
|
proposer_slashing.header_2.slot):
|
|
|
|
notice "Proposer slashing: slot mismatch"
|
2019-09-10 15:29:46 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
# But the headers are different
|
|
|
|
if not (proposer_slashing.header_1 != proposer_slashing.header_2):
|
2019-09-11 07:50:07 +00:00
|
|
|
notice "Proposer slashing: headers not different"
|
2019-09-10 15:29:46 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
# Check proposer is slashable
|
|
|
|
if not is_slashable_validator(proposer, get_current_epoch(state)):
|
2019-09-11 07:50:07 +00:00
|
|
|
notice "Proposer slashing: slashed proposer"
|
2019-09-10 15:29:46 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
# Signatures are valid
|
|
|
|
if skipValidation notin flags:
|
2019-09-11 07:50:07 +00:00
|
|
|
for i, header in [proposer_slashing.header_1, proposer_slashing.header_2]:
|
2019-09-10 15:29:46 +00:00
|
|
|
if not bls_verify(
|
|
|
|
proposer.pubkey,
|
|
|
|
signing_root(header).data,
|
|
|
|
header.signature,
|
|
|
|
get_domain(
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot))):
|
2019-09-11 07:50:07 +00:00
|
|
|
notice "Proposer slashing: invalid signature",
|
2019-09-10 15:29:46 +00:00
|
|
|
signature_index = i
|
|
|
|
return false
|
|
|
|
|
|
|
|
slashValidator(
|
|
|
|
state, proposer_slashing.proposer_index.ValidatorIndex, stateCache)
|
|
|
|
|
|
|
|
true
|
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
proc processProposerSlashings(
|
|
|
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
|
|
|
stateCache: var StateCache): bool =
|
|
|
|
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
|
|
|
|
notice "PropSlash: too many!",
|
|
|
|
proposer_slashings = len(blck.body.proposer_slashings)
|
|
|
|
return false
|
|
|
|
|
|
|
|
for proposer_slashing in blck.body.proposer_slashings:
|
2019-09-10 15:29:46 +00:00
|
|
|
if not process_proposer_slashing(
|
|
|
|
state, proposer_slashing, flags, stateCache):
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
true
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#is_slashable_attestation_data
|
2019-06-28 13:44:44 +00:00
|
|
|
func is_slashable_attestation_data(
|
|
|
|
data_1: AttestationData, data_2: AttestationData): bool =
|
|
|
|
## Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG
|
|
|
|
## rules.
|
|
|
|
|
|
|
|
# Double vote
|
2019-07-02 21:14:55 +00:00
|
|
|
(data_1 != data_2 and data_1.target.epoch == data_2.target.epoch) or
|
2019-06-28 13:44:44 +00:00
|
|
|
# Surround vote
|
2019-07-02 21:14:55 +00:00
|
|
|
(data_1.source.epoch < data_2.source.epoch and
|
|
|
|
data_2.target.epoch < data_1.target.epoch)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.0/specs/core/0_beacon-chain.md#attester-slashings
|
2019-09-10 22:03:06 +00:00
|
|
|
proc process_attester_slashing*(
|
|
|
|
state: var BeaconState,
|
|
|
|
attester_slashing: AttesterSlashing,
|
|
|
|
stateCache: var StateCache
|
|
|
|
): bool =
|
2019-06-28 13:44:44 +00:00
|
|
|
let
|
|
|
|
attestation_1 = attester_slashing.attestation_1
|
|
|
|
attestation_2 = attester_slashing.attestation_2
|
|
|
|
|
|
|
|
if not is_slashable_attestation_data(
|
|
|
|
attestation_1.data, attestation_2.data):
|
2019-09-10 22:03:06 +00:00
|
|
|
notice "Attester slashing: surround or double vote check failed"
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
2019-07-02 21:14:55 +00:00
|
|
|
if not is_valid_indexed_attestation(state, attestation_1):
|
2019-09-10 22:03:06 +00:00
|
|
|
notice "Attester slashing: invalid attestation 1"
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
2019-07-02 21:14:55 +00:00
|
|
|
if not is_valid_indexed_attestation(state, attestation_2):
|
2019-09-10 22:03:06 +00:00
|
|
|
notice "Attester slashing: invalid attestation 2"
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
2019-09-10 22:03:06 +00:00
|
|
|
var slashed_any = false # Detect if trying to slash twice
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
## TODO there's a lot of sorting/set construction here and
|
|
|
|
## verify_indexed_attestation, but go by spec unless there
|
|
|
|
## is compelling perf evidence otherwise.
|
2019-09-10 22:03:06 +00:00
|
|
|
let
|
|
|
|
attesting_indices_1 = attestation_1.custody_bit_0_indices & attestation_1.custody_bit_1_indices
|
|
|
|
attesting_indices_2 = attestation_2.custody_bit_0_indices & attestation_2.custody_bit_1_indices
|
2019-06-28 13:44:44 +00:00
|
|
|
for index in sorted(toSeq(intersection(toSet(attesting_indices_1),
|
|
|
|
toSet(attesting_indices_2)).items), system.cmp):
|
2019-09-10 22:03:06 +00:00
|
|
|
if is_slashable_validator(state.validators[index.int], get_current_epoch(state)):
|
2019-06-28 13:44:44 +00:00
|
|
|
slash_validator(state, index.ValidatorIndex, stateCache)
|
|
|
|
slashed_any = true
|
2019-09-10 22:03:06 +00:00
|
|
|
if not slashed_any:
|
|
|
|
notice "Attester slashing: Trying to slash participant(s) twice"
|
|
|
|
return false
|
|
|
|
return true
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attester-slashings
|
2019-09-10 22:03:06 +00:00
|
|
|
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock,
|
|
|
|
stateCache: var StateCache): bool =
|
|
|
|
# Process ``AttesterSlashing`` operation.
|
|
|
|
if len(blck.body.attester_slashings) > MAX_ATTESTER_SLASHINGS:
|
|
|
|
notice "Attester slashing: too many!"
|
|
|
|
return false
|
|
|
|
|
|
|
|
for attester_slashing in blck.body.attester_slashings:
|
|
|
|
if not process_attester_slashing(state, attester_slashing, stateCache):
|
|
|
|
return false
|
|
|
|
return true
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#attestations
|
2019-08-14 08:56:32 +00:00
|
|
|
proc processAttestations*(
|
2019-06-28 13:44:44 +00:00
|
|
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
|
|
|
stateCache: var StateCache): bool =
|
|
|
|
## Each block includes a number of attestations that the proposer chose. Each
|
|
|
|
## attestation represents an update to a specific shard and is signed by a
|
|
|
|
## committee of validators.
|
|
|
|
## Here we make sanity checks for each attestation and it to the state - most
|
|
|
|
## updates will happen at the epoch boundary where state updates happen in
|
|
|
|
## bulk.
|
|
|
|
if blck.body.attestations.len > MAX_ATTESTATIONS:
|
|
|
|
notice "Attestation: too many!", attestations = blck.body.attestations.len
|
|
|
|
return false
|
|
|
|
|
2019-08-19 16:41:13 +00:00
|
|
|
trace "in processAttestations, not processed attestations",
|
2019-08-14 08:56:32 +00:00
|
|
|
attestations_len = blck.body.attestations.len()
|
|
|
|
|
2019-07-02 21:14:55 +00:00
|
|
|
if not blck.body.attestations.allIt(process_attestation(state, it, flags, stateCache)):
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
true
|
|
|
|
|
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#deposits
|
|
|
|
proc processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
|
|
|
|
if not (len(blck.body.deposits) <= MAX_DEPOSITS):
|
|
|
|
notice "processDeposits: too many deposits"
|
|
|
|
return false
|
|
|
|
|
|
|
|
for deposit in blck.body.deposits:
|
|
|
|
if not process_deposit(state, deposit):
|
|
|
|
notice "processDeposits: deposit invalid"
|
|
|
|
return false
|
|
|
|
|
|
|
|
true
|
|
|
|
|
2019-11-11 09:02:52 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#voluntary-exits
|
2019-09-10 00:14:03 +00:00
|
|
|
proc process_voluntary_exit*(
|
|
|
|
state: var BeaconState,
|
|
|
|
exit: VoluntaryExit,
|
|
|
|
flags: UpdateFlags): bool =
|
|
|
|
|
|
|
|
# Not in spec. Check that validator_index is in range
|
|
|
|
if exit.validator_index.int >= state.validators.len:
|
|
|
|
notice "Exit: invalid validator index",
|
|
|
|
index = exit.validator_index,
|
|
|
|
num_validators = state.validators.len
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
let validator = state.validators[exit.validator_index.int]
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Verify the validator is active
|
|
|
|
if not is_active_validator(validator, get_current_epoch(state)):
|
|
|
|
notice "Exit: validator not active"
|
|
|
|
return false
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Verify the validator has not yet exited
|
|
|
|
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
|
|
|
notice "Exit: validator has exited"
|
|
|
|
return false
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
## Exits must specify an epoch when they become valid; they are not valid
|
|
|
|
## before then
|
|
|
|
if not (get_current_epoch(state) >= exit.epoch):
|
|
|
|
notice "Exit: exit epoch not passed"
|
|
|
|
return false
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Verify the validator has been active long enough
|
|
|
|
if not (get_current_epoch(state) >= validator.activation_epoch +
|
|
|
|
PERSISTENT_COMMITTEE_PERIOD):
|
|
|
|
notice "Exit: not in validator set long enough"
|
|
|
|
return false
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Verify signature
|
|
|
|
if skipValidation notin flags:
|
|
|
|
let domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
|
|
|
|
if not bls_verify(
|
|
|
|
validator.pubkey,
|
|
|
|
signing_root(exit).data,
|
|
|
|
exit.signature,
|
|
|
|
domain):
|
|
|
|
notice "Exit: invalid signature"
|
|
|
|
return false
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Initiate exit
|
|
|
|
initiate_validator_exit(state, exit.validator_index.ValidatorIndex)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
true
|
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
proc processVoluntaryExits(state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
|
|
|
if len(blck.body.voluntary_exits) > MAX_VOLUNTARY_EXITS:
|
|
|
|
notice "[Block processing - Voluntary Exit]: too many exits!"
|
|
|
|
return false
|
|
|
|
for exit in blck.body.voluntary_exits:
|
|
|
|
if not process_voluntary_exit(state, exit, flags):
|
|
|
|
return false
|
|
|
|
return true
|
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
proc processBlock*(
|
|
|
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
|
|
|
stateCache: var StateCache): bool =
|
|
|
|
## When there's a new block, we need to verify that the block is sane and
|
|
|
|
## update the state accordingly
|
|
|
|
|
|
|
|
# TODO when there's a failure, we should reset the state!
|
|
|
|
# TODO probably better to do all verification first, then apply state changes
|
|
|
|
|
2019-10-06 04:31:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#additional-metrics
|
|
|
|
# doesn't seem to specify at what point in block processing this metric is to be read,
|
|
|
|
# and this avoids the early-return issue (could also use defer, etc).
|
|
|
|
beacon_pending_deposits.set(
|
|
|
|
state.eth1_data.deposit_count.int64 - state.eth1_deposit_index.int64)
|
|
|
|
beacon_processed_deposits_total.set(state.eth1_deposit_index.int64)
|
|
|
|
|
2019-10-21 08:11:54 +00:00
|
|
|
# Adds nontrivial additional computation, but only does so when metrics
|
|
|
|
# enabled.
|
|
|
|
beacon_current_live_validators.set(toSet(
|
|
|
|
mapIt(state.current_epoch_attestations, it.proposerIndex)).len.int64)
|
|
|
|
beacon_previous_live_validators.set(toSet(
|
|
|
|
mapIt(state.previous_epoch_attestations, it.proposerIndex)).len.int64)
|
|
|
|
|
2019-09-09 18:40:59 +00:00
|
|
|
if not process_block_header(state, blck, flags, stateCache):
|
2019-08-15 16:01:55 +00:00
|
|
|
notice "Block header not valid", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
if not processRandao(state, blck.body, flags, stateCache):
|
2019-08-15 16:01:55 +00:00
|
|
|
debug "[Block processing] Randao failure", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
process_eth1_data(state, blck.body)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# TODO, everything below is now in process_operations
|
|
|
|
# and implementation is per element instead of the whole seq
|
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
if not processProposerSlashings(state, blck, flags, stateCache):
|
2019-08-15 16:01:55 +00:00
|
|
|
debug "[Block processing] Proposer slashing failure", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
if not processAttesterSlashings(state, blck, stateCache):
|
2019-08-15 16:01:55 +00:00
|
|
|
debug "[Block processing] Attester slashing failure", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
if not processAttestations(state, blck, flags, stateCache):
|
2019-08-15 16:01:55 +00:00
|
|
|
debug "[Block processing] Attestation processing failure", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
if not processDeposits(state, blck):
|
2019-08-15 16:01:55 +00:00
|
|
|
debug "[Block processing] Deposit processing failure", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
if not processVoluntaryExits(state, blck, flags):
|
2019-09-10 00:14:03 +00:00
|
|
|
debug "[Block processing - Voluntary Exit] Exit processing failure", slot = shortLog(state.slot)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
true
|