2019-06-28 13:44:44 +00:00
|
|
|
# beacon_chain
|
2020-01-27 12:21:50 +00:00
|
|
|
# Copyright (c) 2018-2020 Status Research & Development GmbH
|
2019-06-28 13:44:44 +00:00
|
|
|
# Licensed and distributed under either of
|
2019-11-25 15:30:02 +00:00
|
|
|
# * 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).
|
2019-06-28 13:44:44 +00:00
|
|
|
# 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):
|
|
|
|
# * 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.
|
|
|
|
# * For indices, we get a mix of uint64, ValidatorIndex and int - this is currently
|
|
|
|
# swept under the rug with casts
|
|
|
|
# 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.
|
|
|
|
|
2020-04-22 05:53:02 +00:00
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
2019-12-04 10:49:59 +00:00
|
|
|
import
|
2020-04-10 14:06:24 +00:00
|
|
|
algorithm, collections/sets, chronicles, options, sequtils, sets,
|
2020-06-03 13:52:02 +00:00
|
|
|
../extras, ../ssz/merkleization, metrics,
|
2020-06-16 05:45:04 +00:00
|
|
|
./beaconstate, ./crypto, ./datatypes, ./digest, ./helpers, ./validator,
|
2020-07-07 23:02:14 +00:00
|
|
|
./signatures, ./presets,
|
2019-12-20 16:14:43 +00:00
|
|
|
../../nbench/bench_lab
|
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
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#block-header
|
2020-07-03 17:03:14 +00:00
|
|
|
func process_block_header*(
|
2020-06-25 10:23:10 +00:00
|
|
|
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags,
|
2020-07-03 17:03:14 +00:00
|
|
|
stateCache: var StateCache): Result[void, cstring] {.nbench.} =
|
2019-06-28 13:44:44 +00:00
|
|
|
# Verify that the slots match
|
|
|
|
if not (blck.slot == state.slot):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("process_block_header: slot mismatch")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-05-19 14:37:29 +00:00
|
|
|
# Verify that the block is newer than latest block header
|
|
|
|
if not (blck.slot > state.latest_block_header.slot):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("process_block_header: block not newer than latest block header")
|
2020-05-19 14:37:29 +00:00
|
|
|
|
2020-03-14 21:54:45 +00:00
|
|
|
# Verify that proposer index is the correct index
|
|
|
|
let proposer_index = get_beacon_proposer_index(state, stateCache)
|
|
|
|
if proposer_index.isNone:
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("process_block_header: proposer missing")
|
2020-03-14 21:54:45 +00:00
|
|
|
|
|
|
|
if not (blck.proposer_index.ValidatorIndex == proposer_index.get):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("process_block_header: proposer index incorrect")
|
2020-03-14 21:54:45 +00:00
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
# Verify that the parent matches
|
2020-06-18 05:56:47 +00:00
|
|
|
if not (blck.parent_root == hash_tree_root(state.latest_block_header)):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("process_block_header: previous block root mismatch")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-09-01 07:49:55 +00:00
|
|
|
# Verify proposer is not slashed
|
|
|
|
if state.validators[proposer_index.get].slashed:
|
|
|
|
return err("process_block_header: proposer slashed")
|
|
|
|
|
2020-03-14 21:54:45 +00:00
|
|
|
# Cache current block as the new latest block
|
2019-06-28 13:44:44 +00:00
|
|
|
state.latest_block_header = BeaconBlockHeader(
|
|
|
|
slot: blck.slot,
|
2020-03-14 21:54:45 +00:00
|
|
|
proposer_index: blck.proposer_index,
|
2019-06-28 13:44:44 +00:00
|
|
|
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),
|
|
|
|
)
|
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
ok()
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
func `xor`[T: array](a, b: T): T =
|
2020-05-28 16:34:59 +00:00
|
|
|
for i in 0..<result.len:
|
|
|
|
result[i] = a[i] xor b[i]
|
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#randao
|
2019-09-04 13:57:18 +00:00
|
|
|
proc process_randao(
|
2020-06-25 10:23:10 +00:00
|
|
|
state: var BeaconState, body: SomeBeaconBlockBody, flags: UpdateFlags,
|
|
|
|
stateCache: var StateCache): bool {.nbench.} =
|
2019-06-28 13:44:44 +00:00
|
|
|
let
|
|
|
|
proposer_index = get_beacon_proposer_index(state, stateCache)
|
2019-12-04 10:49:59 +00:00
|
|
|
|
|
|
|
if proposer_index.isNone:
|
|
|
|
debug "Proposer index missing, probably along with any active validators"
|
|
|
|
return false
|
|
|
|
|
2020-05-26 05:04:24 +00:00
|
|
|
# Verify RANDAO reveal
|
2020-06-16 05:45:04 +00:00
|
|
|
let
|
|
|
|
epoch = state.get_current_epoch()
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-03-04 21:27:11 +00:00
|
|
|
if skipBLSValidation notin flags:
|
2020-06-16 05:45:04 +00:00
|
|
|
let proposer_pubkey = state.validators[proposer_index.get].pubkey
|
|
|
|
|
|
|
|
if not verify_epoch_signature(
|
|
|
|
state.fork, state.genesis_validators_root, epoch, proposer_pubkey,
|
|
|
|
body.randao_reveal):
|
|
|
|
notice "Randao mismatch", proposer_pubkey = shortLog(proposer_pubkey),
|
|
|
|
epoch,
|
2020-03-19 16:18:48 +00:00
|
|
|
signature = shortLog(body.randao_reveal),
|
2019-06-28 13:44:44 +00:00
|
|
|
slot = state.slot
|
|
|
|
return false
|
|
|
|
|
|
|
|
# Mix it in
|
|
|
|
let
|
2019-09-04 13:57:18 +00:00
|
|
|
mix = get_randao_mix(state, epoch)
|
2020-06-16 12:16:43 +00:00
|
|
|
rr = eth2digest(body.randao_reveal.toRaw()).data
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-05-28 16:34:59 +00:00
|
|
|
state.randao_mixes[epoch mod EPOCHS_PER_HISTORICAL_VECTOR].data =
|
|
|
|
mix.data xor rr
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
true
|
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#eth1-data
|
2020-06-25 10:23:10 +00:00
|
|
|
func process_eth1_data(state: var BeaconState, body: SomeBeaconBlockBody) {.nbench.}=
|
2019-06-28 13:44:44 +00:00
|
|
|
state.eth1_data_votes.add body.eth1_data
|
2020-05-28 16:34:59 +00:00
|
|
|
|
2020-07-26 18:55:48 +00:00
|
|
|
if state.eth1_data_votes.asSeq.count(body.eth1_data).uint64 * 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
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/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)
|
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#proposer-slashings
|
2020-09-24 17:05:49 +00:00
|
|
|
proc check_proposer_slashing*(
|
2019-09-10 15:29:46 +00:00
|
|
|
state: var BeaconState, proposer_slashing: ProposerSlashing,
|
2020-09-24 17:05:49 +00:00
|
|
|
flags: UpdateFlags, cache: var StateCache):
|
2020-07-03 17:03:14 +00:00
|
|
|
Result[void, cstring] {.nbench.} =
|
2020-03-14 21:54:45 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
header_1 = proposer_slashing.signed_header_1.message
|
|
|
|
header_2 = proposer_slashing.signed_header_2.message
|
|
|
|
|
|
|
|
# Not from spec
|
2020-07-26 18:55:48 +00:00
|
|
|
if header_1.proposer_index >= state.validators.lenu64:
|
2020-09-24 17:05:49 +00:00
|
|
|
return err("check_proposer_slashing: invalid proposer index")
|
2019-09-11 07:50:07 +00:00
|
|
|
|
2020-03-14 21:54:45 +00:00
|
|
|
# Verify header slots match
|
|
|
|
if not (header_1.slot == header_2.slot):
|
2020-09-24 17:05:49 +00:00
|
|
|
return err("check_proposer_slashing: slot mismatch")
|
2019-09-10 15:29:46 +00:00
|
|
|
|
2020-03-14 21:54:45 +00:00
|
|
|
# Verify header proposer indices match
|
|
|
|
if not (header_1.proposer_index == header_2.proposer_index):
|
2020-09-24 17:05:49 +00:00
|
|
|
return err("check_proposer_slashing: proposer indices mismatch")
|
2020-03-14 21:54:45 +00:00
|
|
|
|
|
|
|
# Verify the headers are different
|
|
|
|
if not (header_1 != header_2):
|
2020-09-24 17:05:49 +00:00
|
|
|
return err("check_proposer_slashing: headers not different")
|
2019-09-10 15:29:46 +00:00
|
|
|
|
2020-03-14 21:54:45 +00:00
|
|
|
# Verify the proposer is slashable
|
|
|
|
let proposer = state.validators[header_1.proposer_index]
|
2019-09-10 15:29:46 +00:00
|
|
|
if not is_slashable_validator(proposer, get_current_epoch(state)):
|
2020-09-24 17:05:49 +00:00
|
|
|
return err("check_proposer_slashing: slashed proposer")
|
2019-09-10 15:29:46 +00:00
|
|
|
|
2020-03-14 21:54:45 +00:00
|
|
|
# Verify signatures
|
2020-03-05 12:52:10 +00:00
|
|
|
if skipBlsValidation notin flags:
|
2020-09-24 17:05:49 +00:00
|
|
|
for signed_header in [proposer_slashing.signed_header_1,
|
2019-12-16 18:08:50 +00:00
|
|
|
proposer_slashing.signed_header_2]:
|
2020-06-16 05:45:04 +00:00
|
|
|
if not verify_block_signature(
|
|
|
|
state.fork, state.genesis_validators_root, signed_header.message.slot,
|
|
|
|
signed_header.message, proposer.pubkey, signed_header.signature):
|
2020-09-24 17:05:49 +00:00
|
|
|
return err("check_proposer_slashing: invalid signature")
|
2019-09-10 15:29:46 +00:00
|
|
|
|
2020-09-24 17:05:49 +00:00
|
|
|
ok()
|
2019-09-10 15:29:46 +00:00
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#proposer-slashings
|
2020-09-24 17:05:49 +00:00
|
|
|
proc process_proposer_slashing*(
|
|
|
|
state: var BeaconState, proposer_slashing: ProposerSlashing,
|
|
|
|
flags: UpdateFlags, cache: var StateCache):
|
|
|
|
Result[void, cstring] {.nbench.} =
|
|
|
|
? check_proposer_slashing(state, proposer_slashing, flags, cache)
|
|
|
|
slash_validator(
|
|
|
|
state,
|
|
|
|
proposer_slashing.signed_header_1.message.proposer_index.ValidatorIndex,
|
|
|
|
cache)
|
2020-07-03 17:03:14 +00:00
|
|
|
ok()
|
2019-09-10 15:29:46 +00:00
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#is_slashable_attestation_data
|
2020-09-14 14:26:31 +00:00
|
|
|
func is_slashable_attestation_data*(
|
2019-06-28 13:44:44 +00:00
|
|
|
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
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#attester-slashings
|
2020-09-24 17:05:49 +00:00
|
|
|
proc check_attester_slashing*(
|
2019-09-10 22:03:06 +00:00
|
|
|
state: var BeaconState,
|
|
|
|
attester_slashing: AttesterSlashing,
|
2020-01-30 21:03:47 +00:00
|
|
|
flags: UpdateFlags,
|
2020-09-24 17:05:49 +00:00
|
|
|
cache: var StateCache
|
|
|
|
): Result[seq[ValidatorIndex], cstring] {.nbench.} =
|
2020-07-03 17:03:14 +00:00
|
|
|
let
|
|
|
|
attestation_1 = attester_slashing.attestation_1
|
|
|
|
attestation_2 = attester_slashing.attestation_2
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
if not is_slashable_attestation_data(
|
|
|
|
attestation_1.data, attestation_2.data):
|
|
|
|
return err("Attester slashing: surround or double vote check failed")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-08-13 13:47:06 +00:00
|
|
|
if not is_valid_indexed_attestation(state, attestation_1, flags).isOk():
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Attester slashing: invalid attestation 1")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-08-13 13:47:06 +00:00
|
|
|
if not is_valid_indexed_attestation(state, attestation_2, flags).isOk():
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Attester slashing: invalid attestation 2")
|
|
|
|
|
2020-09-24 17:05:49 +00:00
|
|
|
var slashed_indices: seq[ValidatorIndex]
|
2020-07-03 17:03:14 +00:00
|
|
|
|
|
|
|
for index in sorted(toSeq(intersection(
|
|
|
|
toHashSet(attestation_1.attesting_indices.asSeq),
|
|
|
|
toHashSet(attestation_2.attesting_indices.asSeq)).items), system.cmp):
|
|
|
|
if is_slashable_validator(
|
2020-07-26 18:55:48 +00:00
|
|
|
state.validators[index], get_current_epoch(state)):
|
2020-09-24 17:05:49 +00:00
|
|
|
slashed_indices.add index.ValidatorIndex
|
|
|
|
if slashed_indices.len == 0:
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Attester slashing: Trying to slash participant(s) twice")
|
2020-09-24 17:05:49 +00:00
|
|
|
|
|
|
|
ok slashed_indices
|
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#attester-slashings
|
2020-09-24 17:05:49 +00:00
|
|
|
proc process_attester_slashing*(
|
|
|
|
state: var BeaconState,
|
|
|
|
attester_slashing: AttesterSlashing,
|
|
|
|
flags: UpdateFlags,
|
|
|
|
cache: var StateCache
|
|
|
|
): Result[void, cstring] {.nbench.} =
|
|
|
|
let attester_slashing_validity =
|
|
|
|
check_attester_slashing(state, attester_slashing, flags, cache)
|
|
|
|
|
|
|
|
if attester_slashing_validity.isErr:
|
|
|
|
return err(attester_slashing_validity.error)
|
|
|
|
|
|
|
|
for index in attester_slashing_validity.value:
|
|
|
|
slash_validator(state, index, cache)
|
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
ok()
|
2019-09-10 22:03:06 +00:00
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#voluntary-exits
|
2020-09-24 17:05:49 +00:00
|
|
|
proc check_voluntary_exit*(
|
2019-09-10 00:14:03 +00:00
|
|
|
state: var BeaconState,
|
2019-12-16 18:08:50 +00:00
|
|
|
signed_voluntary_exit: SignedVoluntaryExit,
|
2020-08-14 12:42:59 +00:00
|
|
|
flags: UpdateFlags,
|
|
|
|
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
2019-09-10 00:14:03 +00:00
|
|
|
|
2019-12-16 18:08:50 +00:00
|
|
|
let voluntary_exit = signed_voluntary_exit.message
|
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Not in spec. Check that validator_index is in range
|
2020-07-26 18:55:48 +00:00
|
|
|
if voluntary_exit.validator_index >= state.validators.lenu64:
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Exit: invalid validator index")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-07-26 18:55:48 +00:00
|
|
|
let validator = state.validators[voluntary_exit.validator_index]
|
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)):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Exit: validator not active")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-07-08 20:36:26 +00:00
|
|
|
# Verify exit has not been initiated
|
2019-09-10 00:14:03 +00:00
|
|
|
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Exit: validator has exited")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
# Exits must specify an epoch when they become valid; they are not valid
|
|
|
|
# before then
|
2019-12-16 18:08:50 +00:00
|
|
|
if not (get_current_epoch(state) >= voluntary_exit.epoch):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Exit: exit epoch not passed")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Verify the validator has been active long enough
|
2020-06-29 18:08:58 +00:00
|
|
|
if not (get_current_epoch(state) >= validator.activation_epoch +
|
|
|
|
SHARD_COMMITTEE_PERIOD):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Exit: not in validator set long enough")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Verify signature
|
2020-03-05 12:52:10 +00:00
|
|
|
if skipBlsValidation notin flags:
|
2020-06-16 05:45:04 +00:00
|
|
|
if not verify_voluntary_exit_signature(
|
|
|
|
state.fork, state.genesis_validators_root, voluntary_exit,
|
|
|
|
validator.pubkey, signed_voluntary_exit.signature):
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("Exit: invalid signature")
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2019-09-10 00:14:03 +00:00
|
|
|
# Initiate exit
|
2020-09-24 17:05:49 +00:00
|
|
|
debug "Exit: checking voluntary exit (validator_leaving)",
|
2019-12-16 18:08:50 +00:00
|
|
|
index = voluntary_exit.validator_index,
|
2019-11-25 08:22:16 +00:00
|
|
|
num_validators = state.validators.len,
|
2019-12-16 18:08:50 +00:00
|
|
|
epoch = voluntary_exit.epoch,
|
2019-11-25 08:22:16 +00:00
|
|
|
current_epoch = get_current_epoch(state),
|
|
|
|
validator_slashed = validator.slashed,
|
|
|
|
validator_withdrawable_epoch = validator.withdrawable_epoch,
|
|
|
|
validator_exit_epoch = validator.exit_epoch,
|
|
|
|
validator_effective_balance = validator.effective_balance
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
ok()
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2020-09-24 17:05:49 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#voluntary-exits
|
|
|
|
proc process_voluntary_exit*(
|
|
|
|
state: var BeaconState,
|
|
|
|
signed_voluntary_exit: SignedVoluntaryExit,
|
|
|
|
flags: UpdateFlags,
|
|
|
|
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
|
|
|
? check_voluntary_exit(state, signed_voluntary_exit, flags, cache)
|
|
|
|
initiate_validator_exit(
|
|
|
|
state, signed_voluntary_exit.message.validator_index.ValidatorIndex, cache)
|
|
|
|
ok()
|
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#operations
|
2020-07-07 23:02:14 +00:00
|
|
|
proc process_operations(preset: RuntimePreset,
|
|
|
|
state: var BeaconState,
|
|
|
|
body: SomeBeaconBlockBody,
|
|
|
|
flags: UpdateFlags,
|
2020-08-14 12:42:59 +00:00
|
|
|
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
2020-05-22 15:52:07 +00:00
|
|
|
# Verify that outstanding deposits are processed up to the maximum number of
|
|
|
|
# deposits
|
|
|
|
let
|
|
|
|
req_deposits = min(MAX_DEPOSITS,
|
2020-07-13 14:44:58 +00:00
|
|
|
state.eth1_data.deposit_count - state.eth1_deposit_index)
|
2020-08-21 13:34:14 +00:00
|
|
|
if state.eth1_data.deposit_count < state.eth1_deposit_index or
|
|
|
|
body.deposits.lenu64 != req_deposits:
|
2020-07-03 17:03:14 +00:00
|
|
|
return err("incorrect number of deposits")
|
2020-05-22 15:52:07 +00:00
|
|
|
|
2020-05-22 17:00:58 +00:00
|
|
|
template for_ops(operations: auto, fn: auto) =
|
2020-05-22 15:52:07 +00:00
|
|
|
for operation in operations:
|
2020-08-14 12:42:59 +00:00
|
|
|
let res = fn(state, operation, flags, cache)
|
2020-07-03 17:03:14 +00:00
|
|
|
if res.isErr:
|
|
|
|
return res
|
2020-05-22 15:52:07 +00:00
|
|
|
|
2020-08-14 12:42:59 +00:00
|
|
|
for_ops(body.proposer_slashings, process_proposer_slashing)
|
|
|
|
for_ops(body.attester_slashings, process_attester_slashing)
|
|
|
|
for_ops(body.attestations, process_attestation)
|
2020-07-07 23:02:14 +00:00
|
|
|
|
|
|
|
for deposit in body.deposits:
|
2020-07-08 12:36:03 +00:00
|
|
|
let res = process_deposit(preset, state, deposit, flags)
|
|
|
|
if res.isErr:
|
|
|
|
return res
|
2020-07-07 23:02:14 +00:00
|
|
|
|
2020-05-22 17:00:58 +00:00
|
|
|
for_ops(body.voluntary_exits, process_voluntary_exit)
|
2020-05-22 15:52:07 +00:00
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
ok()
|
2019-09-10 00:14:03 +00:00
|
|
|
|
2020-09-25 11:52:50 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#block-processing
|
2020-03-15 13:01:37 +00:00
|
|
|
proc process_block*(
|
2020-07-07 23:02:14 +00:00
|
|
|
preset: RuntimePreset,
|
2020-06-25 10:23:10 +00:00
|
|
|
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags,
|
2019-12-20 16:14:43 +00:00
|
|
|
stateCache: var StateCache): bool {.nbench.}=
|
2019-06-28 13:44:44 +00:00
|
|
|
## 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
|
|
|
|
|
2020-05-08 23:13:57 +00:00
|
|
|
# Adds nontrivial additional computation, but only does so when metrics
|
|
|
|
# enabled.
|
|
|
|
beacon_current_live_validators.set(toHashSet(
|
|
|
|
mapIt(state.current_epoch_attestations, it.proposerIndex)).len.int64)
|
|
|
|
beacon_previous_live_validators.set(toHashSet(
|
|
|
|
mapIt(state.previous_epoch_attestations, it.proposerIndex)).len.int64)
|
2019-10-21 08:11:54 +00:00
|
|
|
|
2020-07-03 17:03:14 +00:00
|
|
|
logScope:
|
|
|
|
blck = shortLog(blck)
|
|
|
|
let res_block = process_block_header(state, blck, flags, stateCache)
|
|
|
|
if res_block.isErr:
|
|
|
|
debug "Block header not valid",
|
|
|
|
block_header_error = $(res_block.error),
|
|
|
|
slot = state.slot
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
2020-06-25 10:23:10 +00:00
|
|
|
if not process_randao(state, blck.body, flags, stateCache):
|
|
|
|
debug "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)
|
2020-07-03 17:03:14 +00:00
|
|
|
|
2020-07-08 12:36:03 +00:00
|
|
|
let res_ops = process_operations(preset, state, blck.body, flags, stateCache)
|
2020-07-03 17:03:14 +00:00
|
|
|
if res_ops.isErr:
|
|
|
|
debug "process_operations encountered error",
|
|
|
|
operation_error = $(res_ops.error),
|
|
|
|
slot = state.slot,
|
|
|
|
eth1_deposit_index = state.eth1_deposit_index,
|
|
|
|
deposit_root = shortLog(state.eth1_data.deposit_root)
|
2019-06-28 13:44:44 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
true
|