nimbus-eth2/beacon_chain/spec/state_transition_block.nim

1416 lines
60 KiB
Nim
Raw Normal View History

2019-06-28 13:44:44 +00:00
# beacon_chain
# Copyright (c) 2018-2024 Status Research & Development GmbH
2019-06-28 13:44:44 +00:00
# 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).
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.
{.push raises: [].}
# State transition - block processing as described in
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#block-processing
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#block-processing
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#block-processing
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/capella/beacon-chain.md#block-processing
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/deneb/beacon-chain.md#block-processing
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#block-processing
2019-06-28 13:44:44 +00:00
#
# The entry point is `process_block` which is at the bottom of this file.
#
# General notes about the code:
2019-06-28 13:44:44 +00:00
# * Weird styling - the sections taken from the spec use python styling while
# the others use NEP-1 - helps grepping identifiers in spec
# * 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 unless
# motivated by security or performance considerations
2019-06-28 13:44:44 +00:00
import
disentangle eth2 types from the ssz library (#2785) * reorganize ssz dependencies This PR continues the work in https://github.com/status-im/nimbus-eth2/pull/2646, https://github.com/status-im/nimbus-eth2/pull/2779 as well as past issues with serialization and type, to disentangle SSZ from eth2 and at the same time simplify imports and exports with a structured approach. The principal idea here is that when a library wants to introduce SSZ support, they do so via 3 files: * `ssz_codecs` which imports and reexports `codecs` - this covers the basic byte conversions and ensures no overloads get lost * `xxx_merkleization` imports and exports `merkleization` to specialize and get access to `hash_tree_root` and friends * `xxx_ssz_serialization` imports and exports `ssz_serialization` to specialize ssz for a specific library Those that need to interact with SSZ always import the `xxx_` versions of the modules and never `ssz` itself so as to keep imports simple and safe. This is similar to how the REST / JSON-RPC serializers are structured in that someone wanting to serialize spec types to REST-JSON will import `eth2_rest_serialization` and nothing else. * split up ssz into a core library that is independendent of eth2 types * rename `bytes_reader` to `codec` to highlight that it contains coding and decoding of bytes and native ssz types * remove tricky List init overload that causes compile issues * get rid of top-level ssz import * reenable merkleization tests * move some "standard" json serializers to spec * remove `ValidatorIndex` serialization for now * remove test_ssz_merkleization * add tests for over/underlong byte sequences * fix broken seq[byte] test - seq[byte] is not an SSZ type There are a few things this PR doesn't solve: * like #2646 this PR is weak on how to handle root and other dontSerialize fields that "sometimes" should be computed - the same problem appears in REST / JSON-RPC etc * Fix a build problem on macOS * Another way to fix the macOS builds Co-authored-by: Zahary Karadjov <zahary@gmail.com>
2021-08-18 18:57:58 +00:00
chronicles, metrics,
../extras,
./datatypes/[phase0, altair, bellatrix, deneb],
"."/[beaconstate, eth2_merkleization, helpers, validator, signatures],
kzg4844/kzg_abi, kzg4844/kzg
2019-06-28 13:44:44 +00:00
from std/algorithm import fill, sorted
from std/sequtils import count, filterIt, mapIt
2022-10-27 06:29:24 +00:00
from ./datatypes/capella import
BeaconState, MAX_WITHDRAWALS_PER_PAYLOAD, SignedBLSToExecutionChange,
Withdrawal
from ./datatypes/electra import PendingPartialWithdrawal
2022-10-27 06:29:24 +00:00
export extras, phase0, altair
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#block-header
func process_block_header*(
state: var ForkyBeaconState, blck: SomeForkyBeaconBlock,
flags: UpdateFlags, cache: var StateCache): Result[void, cstring] =
2019-06-28 13:44:44 +00:00
# Verify that the slots match
if not (blck.slot == state.slot):
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):
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
2023-01-11 12:29:21 +00:00
let proposer_index = get_beacon_proposer_index(state, cache).valueOr:
return err("process_block_header: proposer missing")
2020-03-14 21:54:45 +00:00
2023-01-11 12:29:21 +00:00
if not (blck.proposer_index == proposer_index):
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
if not (blck.parent_root == hash_tree_root(state.latest_block_header)):
return err("process_block_header: previous block root mismatch")
2019-06-28 13:44:44 +00:00
# Verify proposer is not slashed
if state.validators.item(blck.proposer_index).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,
# 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),
)
ok()
2019-06-28 13:44:44 +00:00
func `xor`[T: array](a, b: T): T =
for i in 0..<result.len:
result[i] = a[i] xor b[i]
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#randao
proc process_randao(
state: var ForkyBeaconState, body: SomeForkyBeaconBlockBody,
flags: UpdateFlags, cache: var StateCache): Result[void, cstring] =
2019-06-28 13:44:44 +00:00
let
2023-01-11 12:29:21 +00:00
proposer_index = get_beacon_proposer_index(state, cache).valueOr:
return err("process_randao: proposer index missing, probably along with any active validators")
# Verify RANDAO reveal
let epoch = state.get_current_epoch()
2019-06-28 13:44:44 +00:00
if skipBlsValidation notin flags and body.randao_reveal isnot TrustedSig:
2023-01-11 12:29:21 +00:00
let proposer_pubkey = state.validators.item(proposer_index).pubkey
# `state_transition.makeBeaconBlock` ensures this is run with a trusted
# signature, but unless the full skipBlsValidation is specified, RANDAO
# epoch signatures still have to be verified.
if not verify_epoch_signature(
state.fork, state.genesis_validators_root, epoch, proposer_pubkey,
body.randao_reveal):
return err("process_randao: invalid epoch signature")
2019-06-28 13:44:44 +00:00
# Mix in RANDAO reveal
2019-06-28 13:44:44 +00:00
let
mix = get_randao_mix(state, epoch)
rr = eth2digest(body.randao_reveal.toRaw()).data
2019-06-28 13:44:44 +00:00
state.randao_mixes.mitem(epoch mod EPOCHS_PER_HISTORICAL_VECTOR).data =
mix.data xor rr
2019-06-28 13:44:44 +00:00
ok()
2019-06-28 13:44:44 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#eth1-data
func process_eth1_data(
state: var ForkyBeaconState,
body: SomeForkyBeaconBlockBody): Result[void, cstring] =
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")
if state.eth1_data_votes.asSeq.count(body.eth1_data).uint64 * 2 >
SLOTS_PER_ETH1_VOTING_PERIOD:
state.eth1_data = body.eth1_data
ok()
2019-06-28 13:44:44 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/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)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#proposer-slashings
proc check_proposer_slashing*(
state: ForkyBeaconState, proposer_slashing: SomeProposerSlashing,
flags: UpdateFlags):
Result[ValidatorIndex, cstring] =
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
# Verify header slots match
if not (header_1.slot == header_2.slot):
return err("check_proposer_slashing: slot mismatch")
2020-03-14 21:54:45 +00:00
# Verify header proposer indices match
if not (header_1.proposer_index == header_2.proposer_index):
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):
return err("check_proposer_slashing: headers not different")
2020-03-14 21:54:45 +00:00
# Verify the proposer is slashable
if header_1.proposer_index >= state.validators.lenu64:
return err("check_proposer_slashing: invalid proposer index")
let proposer = unsafeAddr state.validators[header_1.proposer_index]
performance fixes (#2259) * performance fixes * don't mark tree cache as dirty on read-only List accesses * store only blob in memory for keys and signatures, parse blob lazily * compare public keys by blob instead of parsing / converting to raw * compare Eth2Digest using non-constant-time comparison * avoid some unnecessary validator copying This branch will in particular speed up deposit processing which has been slowing down block replay. Pre (mainnet, 1600 blocks): ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3450.269, 0.000, 3450.269, 3450.269, 1, Initialize DB 0.417, 0.822, 0.036, 21.098, 1400, Load block from database 16.521, 0.000, 16.521, 16.521, 1, Load state from database 27.906, 50.846, 8.104, 1507.633, 1350, Apply block 52.617, 37.029, 20.640, 135.938, 50, Apply epoch block ``` Post: ``` 3502.715, 0.000, 3502.715, 3502.715, 1, Initialize DB 0.080, 0.560, 0.035, 21.015, 1400, Load block from database 17.595, 0.000, 17.595, 17.595, 1, Load state from database 15.706, 11.028, 8.300, 107.537, 1350, Apply block 33.217, 12.622, 17.331, 60.580, 50, Apply epoch block ``` * more perf fixes * load EpochRef cache into StateCache more aggressively * point out security concern with public key cache * reuse proposer index from state when processing block * avoid genericAssign in a few more places * don't parse key when signature is unparseable * fix `==` overload for Eth2Digest * preallocate validator list when getting active validators * speed up proposer index calculation a little bit * reuse cache when replaying blocks in ncli_db * avoid a few more copying loops ``` Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3279.158, 0.000, 3279.158, 3279.158, 1, Initialize DB 0.072, 0.357, 0.035, 13.400, 1400, Load block from database 17.295, 0.000, 17.295, 17.295, 1, Load state from database 5.918, 9.896, 0.198, 98.028, 1350, Apply block 15.888, 10.951, 7.902, 39.535, 50, Apply epoch block 0.000, 0.000, 0.000, 0.000, 0, Database block store ``` * clear full balance cache before processing rewards and penalties ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3947.901, 0.000, 3947.901, 3947.901, 1, Initialize DB 0.124, 0.506, 0.026, 202.370, 363345, Load block from database 97.614, 0.000, 97.614, 97.614, 1, Load state from database 0.186, 0.188, 0.012, 99.561, 357262, Advance slot, non-epoch 14.161, 5.966, 1.099, 395.511, 11524, Advance slot, epoch 1.372, 4.170, 0.017, 276.401, 363345, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database block store ```
2021-01-25 12:04:18 +00:00
if not is_slashable_validator(proposer[], get_current_epoch(state)):
return err("check_proposer_slashing: slashed proposer")
2020-03-14 21:54:45 +00:00
# Verify signatures
if skipBlsValidation notin flags:
for signed_header in [proposer_slashing.signed_header_1,
2019-12-16 18:08:50 +00:00
proposer_slashing.signed_header_2]:
if not verify_block_signature(
state.fork, state.genesis_validators_root, signed_header.message.slot,
signed_header.message, proposer[].pubkey,
signed_header.signature):
return err("check_proposer_slashing: invalid signature")
# Verified above against state.validators
ValidatorIndex.init(header_1.proposer_index)
proc check_proposer_slashing*(
state: var ForkedHashedBeaconState, proposer_slashing: SomeProposerSlashing,
flags: UpdateFlags): Result[ValidatorIndex, cstring] =
withState(state):
check_proposer_slashing(forkyState.data, proposer_slashing, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#proposer-slashings
proc process_proposer_slashing*(
cfg: RuntimeConfig, state: var ForkyBeaconState,
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
proposer_slashing: SomeProposerSlashing, flags: UpdateFlags,
exit_queue_info: ExitQueueInfo, cache: var StateCache):
Result[(Gwei, ExitQueueInfo), cstring] =
let proposer_index = ? check_proposer_slashing(state, proposer_slashing, flags)
slash_validator(cfg, state, proposer_index, exit_queue_info, cache)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#is_slashable_attestation_data
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
(data_1 != data_2 and data_1.target.epoch == data_2.target.epoch) or
2019-06-28 13:44:44 +00:00
# Surround vote
(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
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#attester-slashings
proc check_attester_slashing*(
state: ForkyBeaconState,
# phase0.SomeAttesterSlashing | electra.SomeAttesterSlashing:
# https://github.com/nim-lang/Nim/issues/18095
attester_slashing:
phase0.AttesterSlashing | phase0.TrustedAttesterSlashing |
electra.AttesterSlashing | electra.TrustedAttesterSlashing,
flags: UpdateFlags): Result[seq[ValidatorIndex], cstring] =
let
attestation_1 = attester_slashing.attestation_1
attestation_2 = attester_slashing.attestation_2
2019-06-28 13:44:44 +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
if not is_valid_indexed_attestation(state, attestation_1, flags).isOk():
return err("Attester slashing: invalid attestation 1")
2019-06-28 13:44:44 +00:00
if not is_valid_indexed_attestation(state, attestation_2, flags).isOk():
return err("Attester slashing: invalid attestation 2")
var slashed_indices: seq[ValidatorIndex]
let attesting_indices_2 = toHashSet(attestation_2.attesting_indices.asSeq)
for index in sorted(filterIt(
attestation_1.attesting_indices.asSeq, it in attesting_indices_2),
system.cmp):
if is_slashable_validator(
state.validators[index], get_current_epoch(state)):
slashed_indices.add ValidatorIndex.init(index).expect(
"checked by is_valid_indexed_attestation")
if slashed_indices.len == 0:
return err("Attester slashing: Trying to slash participant(s) twice")
ok slashed_indices
proc check_attester_slashing*(
state: var ForkedHashedBeaconState,
# phase0.SomeAttesterSlashing | electra.SomeAttesterSlashing:
# https://github.com/nim-lang/Nim/issues/18095
attester_slashing:
phase0.AttesterSlashing | phase0.TrustedAttesterSlashing |
electra.AttesterSlashing | electra.TrustedAttesterSlashing,
flags: UpdateFlags): Result[seq[ValidatorIndex], cstring] =
withState(state):
check_attester_slashing(forkyState.data, attester_slashing, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#attester-slashings
proc process_attester_slashing*(
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
cfg: RuntimeConfig,
state: var ForkyBeaconState,
# phase0.SomeAttesterSlashing | electra.SomeAttesterSlashing:
# https://github.com/nim-lang/Nim/issues/18095
attester_slashing:
phase0.AttesterSlashing | phase0.TrustedAttesterSlashing |
electra.AttesterSlashing | electra.TrustedAttesterSlashing,
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
flags: UpdateFlags,
exit_queue_info: ExitQueueInfo, cache: var StateCache
): Result[(Gwei, ExitQueueInfo), cstring] =
let slashed_attesters =
? check_attester_slashing(state, attester_slashing, flags)
var
proposer_reward: Gwei
cur_exit_queue_info = exit_queue_info
for index in slashed_attesters:
doAssert strictVerification notin flags or
cur_exit_queue_info == get_state_exit_queue_info(state)
let (new_proposer_reward, new_exit_queue_info) = ? slash_validator(
cfg, state, index, cur_exit_queue_info, cache)
proposer_reward += new_proposer_reward
cur_exit_queue_info = new_exit_queue_info
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
ok((proposer_reward, cur_exit_queue_info))
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
from ".."/validator_bucket_sort import
BucketSortedValidators, add, findValidatorIndex, sortValidatorBuckets
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/phase0/beacon-chain.md#deposits
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#modified-apply_deposit
proc apply_deposit(
cfg: RuntimeConfig, state: var ForkyBeaconState,
bucketSortedValidators: var BucketSortedValidators,
deposit_data: DepositData, flags: UpdateFlags): Result[void, cstring] =
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
let
pubkey = deposit_data.pubkey
amount = deposit_data.amount
index = findValidatorIndex(
state.validators.asSeq, bucketSortedValidators, pubkey)
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
if index.isSome():
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
# Increase balance by deposit amount
when typeof(state).kind < ConsensusFork.Electra:
increase_balance(state, index.get(), amount)
else:
discard state.pending_deposits.add PendingDeposit(
pubkey: pubkey,
withdrawal_credentials: deposit_data.withdrawal_credentials,
amount: amount,
signature: deposit_data.signature,
# Use GENESIS_SLOT to distinguish from a pending deposit request
slot: GENESIS_SLOT)
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
else:
# Verify the deposit signature (proof of possession) which is not checked
# by the deposit contract
if verify_deposit_signature(cfg, deposit_data):
when typeof(state).kind >= ConsensusFork.Electra:
? add_validator_to_registry(state, deposit_data, 0.Gwei)
let new_vidx = state.validators.lenu64 - 1
# [New in Electra:EIP7251]
discard state.pending_deposits.add PendingDeposit(
pubkey: pubkey,
withdrawal_credentials: deposit_data.withdrawal_credentials,
amount: amount,
signature: deposit_data.signature,
slot: GENESIS_SLOT)
else:
? add_validator_to_registry(state, deposit_data, deposit_data.amount)
let new_vidx = state.validators.lenu64 - 1
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
doAssert state.validators.len == state.balances.len
bucketSortedValidators.add new_vidx.ValidatorIndex
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
else:
# Deposits may come with invalid signatures - in that case, they are not
# turned into a validator but still get processed to keep the deposit
# index correct
trace "Skipping deposit with invalid signature",
deposit = shortLog(deposit_data)
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#deposits
proc process_deposit*(
cfg: RuntimeConfig, state: var ForkyBeaconState,
bucketSortedValidators: var BucketSortedValidators,
deposit: Deposit, flags: UpdateFlags):
Result[void, cstring] =
## Process an Eth1 deposit, registering a validator or increasing its balance.
# Verify the Merkle branch
if not is_valid_merkle_branch(
hash_tree_root(deposit.data),
deposit.proof,
DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the `List` length mix-in
state.eth1_deposit_index,
state.eth1_data.deposit_root,
):
return err("process_deposit: deposit Merkle validation failed")
# Deposits must be processed in order
state.eth1_deposit_index += 1
apply_deposit(cfg, state, bucketSortedValidators, deposit.data, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#new-process_deposit_request
func process_deposit_request*(
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState),
deposit_request: DepositRequest,
flags: UpdateFlags): Result[void, cstring] =
# Set deposit request start index
if state.deposit_requests_start_index ==
UNSET_DEPOSIT_REQUESTS_START_INDEX:
state.deposit_requests_start_index = deposit_request.index
# Create pending deposit
if state.pending_deposits.add(PendingDeposit(
pubkey: deposit_request.pubkey,
withdrawal_credentials: deposit_request.withdrawal_credentials,
amount: deposit_request.amount,
signature: deposit_request.signature,
slot: state.slot)):
ok()
else:
err("process_deposit_request: couldn't add deposit to pending_deposits")
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#voluntary-exits
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/deneb/beacon-chain.md#modified-process_voluntary_exit
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#updated-process_voluntary_exit
proc check_voluntary_exit*(
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
cfg: RuntimeConfig,
state: ForkyBeaconState,
signed_voluntary_exit: SomeSignedVoluntaryExit,
flags: UpdateFlags): Result[ValidatorIndex, cstring] =
2019-12-16 18:08:50 +00:00
let voluntary_exit = signed_voluntary_exit.message
if voluntary_exit.validator_index >= state.validators.lenu64:
return err("Exit: invalid validator index")
2019-06-28 13:44:44 +00:00
let validator = unsafeAddr state.validators[voluntary_exit.validator_index]
2019-06-28 13:44:44 +00:00
# Verify the validator is active
performance fixes (#2259) * performance fixes * don't mark tree cache as dirty on read-only List accesses * store only blob in memory for keys and signatures, parse blob lazily * compare public keys by blob instead of parsing / converting to raw * compare Eth2Digest using non-constant-time comparison * avoid some unnecessary validator copying This branch will in particular speed up deposit processing which has been slowing down block replay. Pre (mainnet, 1600 blocks): ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3450.269, 0.000, 3450.269, 3450.269, 1, Initialize DB 0.417, 0.822, 0.036, 21.098, 1400, Load block from database 16.521, 0.000, 16.521, 16.521, 1, Load state from database 27.906, 50.846, 8.104, 1507.633, 1350, Apply block 52.617, 37.029, 20.640, 135.938, 50, Apply epoch block ``` Post: ``` 3502.715, 0.000, 3502.715, 3502.715, 1, Initialize DB 0.080, 0.560, 0.035, 21.015, 1400, Load block from database 17.595, 0.000, 17.595, 17.595, 1, Load state from database 15.706, 11.028, 8.300, 107.537, 1350, Apply block 33.217, 12.622, 17.331, 60.580, 50, Apply epoch block ``` * more perf fixes * load EpochRef cache into StateCache more aggressively * point out security concern with public key cache * reuse proposer index from state when processing block * avoid genericAssign in a few more places * don't parse key when signature is unparseable * fix `==` overload for Eth2Digest * preallocate validator list when getting active validators * speed up proposer index calculation a little bit * reuse cache when replaying blocks in ncli_db * avoid a few more copying loops ``` Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3279.158, 0.000, 3279.158, 3279.158, 1, Initialize DB 0.072, 0.357, 0.035, 13.400, 1400, Load block from database 17.295, 0.000, 17.295, 17.295, 1, Load state from database 5.918, 9.896, 0.198, 98.028, 1350, Apply block 15.888, 10.951, 7.902, 39.535, 50, Apply epoch block 0.000, 0.000, 0.000, 0.000, 0, Database block store ``` * clear full balance cache before processing rewards and penalties ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3947.901, 0.000, 3947.901, 3947.901, 1, Initialize DB 0.124, 0.506, 0.026, 202.370, 363345, Load block from database 97.614, 0.000, 97.614, 97.614, 1, Load state from database 0.186, 0.188, 0.012, 99.561, 357262, Advance slot, non-epoch 14.161, 5.966, 1.099, 395.511, 11524, Advance slot, epoch 1.372, 4.170, 0.017, 276.401, 363345, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database block store ```
2021-01-25 12:04:18 +00:00
if not is_active_validator(validator[], get_current_epoch(state)):
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
performance fixes (#2259) * performance fixes * don't mark tree cache as dirty on read-only List accesses * store only blob in memory for keys and signatures, parse blob lazily * compare public keys by blob instead of parsing / converting to raw * compare Eth2Digest using non-constant-time comparison * avoid some unnecessary validator copying This branch will in particular speed up deposit processing which has been slowing down block replay. Pre (mainnet, 1600 blocks): ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3450.269, 0.000, 3450.269, 3450.269, 1, Initialize DB 0.417, 0.822, 0.036, 21.098, 1400, Load block from database 16.521, 0.000, 16.521, 16.521, 1, Load state from database 27.906, 50.846, 8.104, 1507.633, 1350, Apply block 52.617, 37.029, 20.640, 135.938, 50, Apply epoch block ``` Post: ``` 3502.715, 0.000, 3502.715, 3502.715, 1, Initialize DB 0.080, 0.560, 0.035, 21.015, 1400, Load block from database 17.595, 0.000, 17.595, 17.595, 1, Load state from database 15.706, 11.028, 8.300, 107.537, 1350, Apply block 33.217, 12.622, 17.331, 60.580, 50, Apply epoch block ``` * more perf fixes * load EpochRef cache into StateCache more aggressively * point out security concern with public key cache * reuse proposer index from state when processing block * avoid genericAssign in a few more places * don't parse key when signature is unparseable * fix `==` overload for Eth2Digest * preallocate validator list when getting active validators * speed up proposer index calculation a little bit * reuse cache when replaying blocks in ncli_db * avoid a few more copying loops ``` Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3279.158, 0.000, 3279.158, 3279.158, 1, Initialize DB 0.072, 0.357, 0.035, 13.400, 1400, Load block from database 17.295, 0.000, 17.295, 17.295, 1, Load state from database 5.918, 9.896, 0.198, 98.028, 1350, Apply block 15.888, 10.951, 7.902, 39.535, 50, Apply epoch block 0.000, 0.000, 0.000, 0.000, 0, Database block store ``` * clear full balance cache before processing rewards and penalties ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3947.901, 0.000, 3947.901, 3947.901, 1, Initialize DB 0.124, 0.506, 0.026, 202.370, 363345, Load block from database 97.614, 0.000, 97.614, 97.614, 1, Load state from database 0.186, 0.188, 0.012, 99.561, 357262, Advance slot, non-epoch 14.161, 5.966, 1.099, 395.511, 11524, Advance slot, epoch 1.372, 4.170, 0.017, 276.401, 363345, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database block store ```
2021-01-25 12:04:18 +00:00
if validator[].exit_epoch != FAR_FUTURE_EPOCH:
return err("Exit: validator has exited")
2019-06-28 13:44:44 +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):
return err("Exit: exit epoch not passed")
2019-06-28 13:44:44 +00:00
# Verify the validator has been active long enough
performance fixes (#2259) * performance fixes * don't mark tree cache as dirty on read-only List accesses * store only blob in memory for keys and signatures, parse blob lazily * compare public keys by blob instead of parsing / converting to raw * compare Eth2Digest using non-constant-time comparison * avoid some unnecessary validator copying This branch will in particular speed up deposit processing which has been slowing down block replay. Pre (mainnet, 1600 blocks): ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3450.269, 0.000, 3450.269, 3450.269, 1, Initialize DB 0.417, 0.822, 0.036, 21.098, 1400, Load block from database 16.521, 0.000, 16.521, 16.521, 1, Load state from database 27.906, 50.846, 8.104, 1507.633, 1350, Apply block 52.617, 37.029, 20.640, 135.938, 50, Apply epoch block ``` Post: ``` 3502.715, 0.000, 3502.715, 3502.715, 1, Initialize DB 0.080, 0.560, 0.035, 21.015, 1400, Load block from database 17.595, 0.000, 17.595, 17.595, 1, Load state from database 15.706, 11.028, 8.300, 107.537, 1350, Apply block 33.217, 12.622, 17.331, 60.580, 50, Apply epoch block ``` * more perf fixes * load EpochRef cache into StateCache more aggressively * point out security concern with public key cache * reuse proposer index from state when processing block * avoid genericAssign in a few more places * don't parse key when signature is unparseable * fix `==` overload for Eth2Digest * preallocate validator list when getting active validators * speed up proposer index calculation a little bit * reuse cache when replaying blocks in ncli_db * avoid a few more copying loops ``` Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3279.158, 0.000, 3279.158, 3279.158, 1, Initialize DB 0.072, 0.357, 0.035, 13.400, 1400, Load block from database 17.295, 0.000, 17.295, 17.295, 1, Load state from database 5.918, 9.896, 0.198, 98.028, 1350, Apply block 15.888, 10.951, 7.902, 39.535, 50, Apply epoch block 0.000, 0.000, 0.000, 0.000, 0, Database block store ``` * clear full balance cache before processing rewards and penalties ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3947.901, 0.000, 3947.901, 3947.901, 1, Initialize DB 0.124, 0.506, 0.026, 202.370, 363345, Load block from database 97.614, 0.000, 97.614, 97.614, 1, Load state from database 0.186, 0.188, 0.012, 99.561, 357262, Advance slot, non-epoch 14.161, 5.966, 1.099, 395.511, 11524, Advance slot, epoch 1.372, 4.170, 0.017, 276.401, 363345, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database block store ```
2021-01-25 12:04:18 +00:00
if not (get_current_epoch(state) >= validator[].activation_epoch +
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
cfg.SHARD_COMMITTEE_PERIOD):
return err("Exit: not in validator set long enough")
2019-06-28 13:44:44 +00:00
when typeof(state).kind >= ConsensusFork.Electra:
# Only exit validator if it has no pending withdrawals in the queue
debugComment "truncating"
if not (get_pending_balance_to_withdraw(
state, voluntary_exit.validator_index.ValidatorIndex) == 0.Gwei):
return err("Exit: still has pending withdrawals")
# Verify signature
if skipBlsValidation notin flags:
fix EIP-7044 implementation when using batch verification (#5953) In #5120, EIP-7044 support got added to the state transition function to force `CAPELLA_FORK_VERSION` to be used when validiting `VoluntaryExit` messages, irrespective of their `epoch`. In #5637, similar logic was added when batch verifying BLS signatures, which is used during gossip validation (libp2p gossipsub, and req/resp). However, that logic did not match the one introduced in #5120, and only uses `CAPELLA_FORK_VERSION` when a `VoluntaryExit`'s `epoch` was set to a value `>= CAPELLA_FORK_EPOCH`. Otherwise, `BELLATRIX_FORK_VERSION` would still be used when validating `VoluntaryExit`, e.g., with `epoch` set to `0`, as is the case in this Holesky block: - https://holesky.beaconcha.in/slot/1076985#voluntary-exits Extracting the correct logic from #5120 into a function, and reusing it when verifying BLS signatures fixes this issue, and also leverages the exhaustive EF test suite that covers the (correct) #5120 logic. This fix only affects networks that have EIP-7044 applied (post-Deneb). Without the fix, Deneb blocks with a `VoluntaryExit` with `epoch` set to `< CAPELLA_FORK_EPOCH` incorrectly fail to validate despite being valid. Incorrect blocks that contain a malicious `VoluntaryExit` with `epoch` set to `< CAPELLA_FORK_EPOCH` and signed using `BELLATRIX_FORK_VERSION` _would_ pass the BLS verification stage, but subsequently fail the state transition logic. Such blocks would still correctly be labeled invalid.
2024-02-25 14:25:26 +00:00
const consensusFork = typeof(state).kind
let voluntary_exit_fork = consensusFork.voluntary_exit_signature_fork(
state.fork, cfg.CAPELLA_FORK_VERSION)
if not verify_voluntary_exit_signature(
fix EIP-7044 implementation when using batch verification (#5953) In #5120, EIP-7044 support got added to the state transition function to force `CAPELLA_FORK_VERSION` to be used when validiting `VoluntaryExit` messages, irrespective of their `epoch`. In #5637, similar logic was added when batch verifying BLS signatures, which is used during gossip validation (libp2p gossipsub, and req/resp). However, that logic did not match the one introduced in #5120, and only uses `CAPELLA_FORK_VERSION` when a `VoluntaryExit`'s `epoch` was set to a value `>= CAPELLA_FORK_EPOCH`. Otherwise, `BELLATRIX_FORK_VERSION` would still be used when validating `VoluntaryExit`, e.g., with `epoch` set to `0`, as is the case in this Holesky block: - https://holesky.beaconcha.in/slot/1076985#voluntary-exits Extracting the correct logic from #5120 into a function, and reusing it when verifying BLS signatures fixes this issue, and also leverages the exhaustive EF test suite that covers the (correct) #5120 logic. This fix only affects networks that have EIP-7044 applied (post-Deneb). Without the fix, Deneb blocks with a `VoluntaryExit` with `epoch` set to `< CAPELLA_FORK_EPOCH` incorrectly fail to validate despite being valid. Incorrect blocks that contain a malicious `VoluntaryExit` with `epoch` set to `< CAPELLA_FORK_EPOCH` and signed using `BELLATRIX_FORK_VERSION` _would_ pass the BLS verification stage, but subsequently fail the state transition logic. Such blocks would still correctly be labeled invalid.
2024-02-25 14:25:26 +00:00
voluntary_exit_fork, state.genesis_validators_root, voluntary_exit,
performance fixes (#2259) * performance fixes * don't mark tree cache as dirty on read-only List accesses * store only blob in memory for keys and signatures, parse blob lazily * compare public keys by blob instead of parsing / converting to raw * compare Eth2Digest using non-constant-time comparison * avoid some unnecessary validator copying This branch will in particular speed up deposit processing which has been slowing down block replay. Pre (mainnet, 1600 blocks): ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3450.269, 0.000, 3450.269, 3450.269, 1, Initialize DB 0.417, 0.822, 0.036, 21.098, 1400, Load block from database 16.521, 0.000, 16.521, 16.521, 1, Load state from database 27.906, 50.846, 8.104, 1507.633, 1350, Apply block 52.617, 37.029, 20.640, 135.938, 50, Apply epoch block ``` Post: ``` 3502.715, 0.000, 3502.715, 3502.715, 1, Initialize DB 0.080, 0.560, 0.035, 21.015, 1400, Load block from database 17.595, 0.000, 17.595, 17.595, 1, Load state from database 15.706, 11.028, 8.300, 107.537, 1350, Apply block 33.217, 12.622, 17.331, 60.580, 50, Apply epoch block ``` * more perf fixes * load EpochRef cache into StateCache more aggressively * point out security concern with public key cache * reuse proposer index from state when processing block * avoid genericAssign in a few more places * don't parse key when signature is unparseable * fix `==` overload for Eth2Digest * preallocate validator list when getting active validators * speed up proposer index calculation a little bit * reuse cache when replaying blocks in ncli_db * avoid a few more copying loops ``` Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3279.158, 0.000, 3279.158, 3279.158, 1, Initialize DB 0.072, 0.357, 0.035, 13.400, 1400, Load block from database 17.295, 0.000, 17.295, 17.295, 1, Load state from database 5.918, 9.896, 0.198, 98.028, 1350, Apply block 15.888, 10.951, 7.902, 39.535, 50, Apply epoch block 0.000, 0.000, 0.000, 0.000, 0, Database block store ``` * clear full balance cache before processing rewards and penalties ``` All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3947.901, 0.000, 3947.901, 3947.901, 1, Initialize DB 0.124, 0.506, 0.026, 202.370, 363345, Load block from database 97.614, 0.000, 97.614, 97.614, 1, Load state from database 0.186, 0.188, 0.012, 99.561, 357262, Advance slot, non-epoch 14.161, 5.966, 1.099, 395.511, 11524, Advance slot, epoch 1.372, 4.170, 0.017, 276.401, 363345, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database block store ```
2021-01-25 12:04:18 +00:00
validator[].pubkey, signed_voluntary_exit.signature):
return err("Exit: invalid signature")
2019-06-28 13:44:44 +00:00
# Checked above
ValidatorIndex.init(voluntary_exit.validator_index)
2019-06-28 13:44:44 +00:00
proc check_voluntary_exit*(
cfg: RuntimeConfig, state: ForkedHashedBeaconState,
signed_voluntary_exit: SomeSignedVoluntaryExit,
flags: UpdateFlags): Result[ValidatorIndex, cstring] =
withState(state):
check_voluntary_exit(cfg, forkyState.data, signed_voluntary_exit, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#voluntary-exits
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#updated-process_voluntary_exit
proc process_voluntary_exit*(
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
cfg: RuntimeConfig,
state: var ForkyBeaconState,
signed_voluntary_exit: SomeSignedVoluntaryExit,
flags: UpdateFlags, exit_queue_info: ExitQueueInfo,
cache: var StateCache): Result[ExitQueueInfo, cstring] =
let exited_validator =
? check_voluntary_exit(cfg, state, signed_voluntary_exit, flags)
ok(? initiate_validator_exit(
cfg, state, exited_validator, exit_queue_info, cache))
proc process_bls_to_execution_change*(
cfg: RuntimeConfig,
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState |
fulu.BeaconState),
signed_address_change: SignedBLSToExecutionChange): Result[void, cstring] =
? check_bls_to_execution_change(
cfg.genesisFork, state, signed_address_change, {})
let address_change = signed_address_change.message
var withdrawal_credentials =
state.validators.item(address_change.validator_index).withdrawal_credentials
withdrawal_credentials.data[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX
withdrawal_credentials.data.fill(1, 11, 0)
withdrawal_credentials.data[12..31] =
address_change.to_execution_address.data
state.validators.mitem(address_change.validator_index).withdrawal_credentials =
withdrawal_credentials
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/electra/beacon-chain.md#new-process_withdrawal_request
func process_withdrawal_request*(
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState),
bucketSortedValidators: BucketSortedValidators,
withdrawal_request: WithdrawalRequest, cache: var StateCache) =
let
amount = withdrawal_request.amount
is_full_exit_request = amount == static(FULL_EXIT_REQUEST_AMOUNT.Gwei)
# If partial withdrawal queue is full, only full exits are processed
if lenu64(state.pending_partial_withdrawals) ==
PENDING_PARTIAL_WITHDRAWALS_LIMIT and not is_full_exit_request:
return
let
request_pubkey = withdrawal_request.validator_pubkey
# Verify pubkey exists
index = findValidatorIndex(
state.validators.asSeq, bucketSortedValidators,
request_pubkey).valueOr:
return
validator = state.validators.item(index)
# Verify withdrawal credentials
let
has_correct_credential = has_execution_withdrawal_credential(validator)
is_correct_source_address =
validator.withdrawal_credentials.data.toOpenArray(12, 31) ==
withdrawal_request.source_address.data
if not (has_correct_credential and is_correct_source_address):
return
# Verify the validator is active
if not is_active_validator(validator, get_current_epoch(state)):
return
# Verify exit has not been initiated
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return
# Verify the validator has been active long enough
if get_current_epoch(state) <
validator.activation_epoch + cfg.SHARD_COMMITTEE_PERIOD:
return
let pending_balance_to_withdraw =
get_pending_balance_to_withdraw(state, index)
if is_full_exit_request:
# Only exit validator if it has no pending withdrawals in the queue
if pending_balance_to_withdraw == 0.Gwei:
if initiate_validator_exit(cfg, state, index, default(ExitQueueInfo),
cache).isErr():
return
return
let
has_sufficient_effective_balance =
validator.effective_balance >= static(MIN_ACTIVATION_BALANCE.Gwei)
has_excess_balance = state.balances.item(index) >
static(MIN_ACTIVATION_BALANCE.Gwei) + pending_balance_to_withdraw
# Only allow partial withdrawals with compounding withdrawal credentials
if has_compounding_withdrawal_credential(validator) and
has_sufficient_effective_balance and has_excess_balance:
let
to_withdraw = min(
state.balances.item(index) - static(MIN_ACTIVATION_BALANCE.Gwei) -
pending_balance_to_withdraw,
amount
)
exit_queue_epoch =
compute_exit_epoch_and_update_churn(cfg, state, to_withdraw, cache)
withdrawable_epoch =
exit_queue_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# In theory can fail, but failing/early returning here is indistinguishable
discard state.pending_partial_withdrawals.add(PendingPartialWithdrawal(
index: index.uint64,
amount: to_withdraw,
withdrawable_epoch: withdrawable_epoch,
))
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#new-is_valid_switch_to_compounding_request
func is_valid_switch_to_compounding_request(
state: electra.BeaconState | fulu.BeaconState,
consolidation_request: ConsolidationRequest,
source_validator: Validator): bool =
# Switch to compounding requires source and target be equal
if consolidation_request.source_pubkey != consolidation_request.target_pubkey:
return false
# process_consolidation_request() verifies pubkey exists
# Verify request has been authorized
if source_validator.withdrawal_credentials.data.toOpenArray(12, 31) !=
consolidation_request.source_address.data:
return false
# Verify source withdrawal credentials
if not has_eth1_withdrawal_credential(source_validator):
return false
# Verify the source is active
let current_epoch = get_current_epoch(state)
if not is_active_validator(source_validator, current_epoch):
return false
# Verify exit for source has not been initiated
if source_validator.exit_epoch != FAR_FUTURE_EPOCH:
return false
true
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#new-process_consolidation_request
func process_consolidation_request*(
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState),
bucketSortedValidators: BucketSortedValidators,
consolidation_request: ConsolidationRequest,
cache: var StateCache) =
let
request_source_pubkey = consolidation_request.source_pubkey
source_index = findValidatorIndex(
state.validators.asSeq, bucketSortedValidators,
request_source_pubkey).valueOr:
return
if is_valid_switch_to_compounding_request(
state, consolidation_request, state.validators.item(source_index)):
switch_to_compounding_validator(state, source_index)
return
# Verify that source != target, so a consolidation cannot be used as an exit.
if consolidation_request.source_pubkey ==
consolidation_request.target_pubkey:
return
# If the pending consolidations queue is full, consolidation requests are
# ignored
if len(state.pending_consolidations) ==
static(PENDING_CONSOLIDATIONS_LIMIT.int):
return
# If there is too little available consolidation churn limit, consolidation
# requests are ignored
if get_consolidation_churn_limit(cfg, state, cache) <=
static(MIN_ACTIVATION_BALANCE.Gwei):
return
# Verify pubkeys exists (source already verified)
let target_index = findValidatorIndex(
state.validators.asSeq, bucketSortedValidators,
consolidation_request.target_pubkey).valueOr:
return
let
source_validator = addr state.validators.mitem(source_index)
target_validator = state.validators.item(target_index)
# Verify source withdrawal credentials
let
has_correct_credential =
has_execution_withdrawal_credential(source_validator[])
is_correct_source_address =
source_validator.withdrawal_credentials.data.toOpenArray(12, 31) ==
consolidation_request.source_address.data
if not (has_correct_credential and is_correct_source_address):
return
# Verify that target has execution withdrawal credentials
if not has_execution_withdrawal_credential(target_validator):
return
# Verify the source and the target are active
let current_epoch = get_current_epoch(state)
if not is_active_validator(source_validator[], current_epoch):
return
if not is_active_validator(target_validator, current_epoch):
return
# Verify exits for source and target have not been initiated
if source_validator[].exit_epoch != FAR_FUTURE_EPOCH:
return
if target_validator.exit_epoch != FAR_FUTURE_EPOCH:
return
# Verify the source has been active long enough
if current_epoch <
source_validator.activation_epoch + cfg.SHARD_COMMITTEE_PERIOD:
return
# Verify the source has no pending withdrawals in the queue
if get_pending_balance_to_withdraw(state, source_index) > 0.Gwei:
return
# Initiate source validator exit and append pending consolidation
source_validator[].exit_epoch = compute_consolidation_epoch_and_update_churn(
cfg, state, source_validator[].effective_balance, cache)
source_validator[].withdrawable_epoch =
source_validator[].exit_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
discard state.pending_consolidations.add(PendingConsolidation(
source_index: source_index.uint64, target_index: target_index.uint64))
# Churn any target excess active balance of target and raise its max
if has_eth1_withdrawal_credential(target_validator):
switch_to_compounding_validator(state, target_index)
type
# https://ethereum.github.io/beacon-APIs/?urls.primaryName=v2.5.0#/Rewards/getBlockRewards
BlockRewards* = object
attestations*: Gwei
sync_aggregate*: Gwei
proposer_slashings*: Gwei
attester_slashings*: Gwei
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#operations
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#modified-process_operations
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/electra/beacon-chain.md#modified-process_operations
proc process_operations(
cfg: RuntimeConfig, state: var ForkyBeaconState,
body: SomeForkyBeaconBlockBody, base_reward_per_increment: Gwei,
flags: UpdateFlags, cache: var StateCache): Result[BlockRewards, cstring] =
# Verify that outstanding deposits are processed up to the maximum number of
# deposits
when typeof(body).kind >= ConsensusFork.Electra:
# Disable former deposit mechanism once all prior deposits are processed
let
eth1_deposit_index_limit =
min(state.eth1_data.deposit_count, state.deposit_requests_start_index)
req_deposits =
# Otherwise wraps because unsigned; Python spec semantics would result in
# negative difference, which would be impossible for len(...) to match.
if state.eth1_deposit_index < eth1_deposit_index_limit:
if eth1_deposit_index_limit < state.eth1_deposit_index:
return err("eth1_deposit_index_limit < state.eth1_deposit_index")
min(
MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index)
else:
0
else:
# Otherwise wraps because unsigned; Python spec semantics would result in
# negative difference, which would be impossible for len(...) to match.
if state.eth1_data.deposit_count < state.eth1_deposit_index:
return err("state.eth1_data.deposit_count < state.eth1_deposit_index")
let req_deposits = min(
MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
if body.deposits.lenu64 != req_deposits:
return err("incorrect number of deposits")
var operations_rewards: BlockRewards
# It costs a full validator set scan to construct these values; only do so if
# there will be some kind of exit.
# TODO Electra doesn't use exit_queue_info, don't calculate
var
exit_queue_info =
if body.proposer_slashings.len + body.attester_slashings.len +
body.voluntary_exits.len > 0:
get_state_exit_queue_info(state)
else:
default(ExitQueueInfo) # not used
bsv_use =
when typeof(body).kind >= ConsensusFork.Electra:
body.deposits.len + body.execution_requests.deposits.len +
body.execution_requests.withdrawals.len +
body.execution_requests.consolidations.len > 0
else:
body.deposits.len > 0
bsv =
if bsv_use:
sortValidatorBuckets(state.validators.asSeq)
else:
nil # this is a logic error, effectively assert
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
for op in body.proposer_slashings:
let (proposer_slashing_reward, new_exit_queue_info) =
? process_proposer_slashing(cfg, state, op, flags, exit_queue_info, cache)
operations_rewards.proposer_slashings += proposer_slashing_reward
exit_queue_info = new_exit_queue_info
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
for op in body.attester_slashings:
let (attester_slashing_reward, new_exit_queue_info) =
? process_attester_slashing(cfg, state, op, flags, exit_queue_info, cache)
operations_rewards.attester_slashings += attester_slashing_reward
exit_queue_info = new_exit_queue_info
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
for op in body.attestations:
operations_rewards.attestations +=
? process_attestation(state, op, flags, base_reward_per_increment, cache)
for op in body.deposits:
? process_deposit(cfg, state, bsv[], op, flags)
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
for op in body.voluntary_exits:
exit_queue_info = ? process_voluntary_exit(
cfg, state, op, flags, exit_queue_info, cache)
when typeof(body).kind >= ConsensusFork.Capella:
for op in body.bls_to_execution_changes:
? process_bls_to_execution_change(cfg, state, op)
when typeof(body).kind >= ConsensusFork.Electra:
for op in body.execution_requests.deposits:
? process_deposit_request(cfg, state, op, {})
for op in body.execution_requests.withdrawals:
# [New in Electra:EIP7002:7251]
process_withdrawal_request(cfg, state, bsv[], op, cache)
for op in body.execution_requests.consolidations:
# [New in Electra:EIP7251]
process_consolidation_request(cfg, state, bsv[], op, cache)
ok(operations_rewards)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#sync-aggregate-processing
func get_participant_reward*(total_active_balance: Gwei): Gwei =
let
total_active_increments =
total_active_balance div EFFECTIVE_BALANCE_INCREMENT.Gwei
total_base_rewards =
get_base_reward_per_increment(total_active_balance) *
total_active_increments
max_participant_rewards =
total_base_rewards * SYNC_REWARD_WEIGHT div
WEIGHT_DENOMINATOR div SLOTS_PER_EPOCH
max_participant_rewards div SYNC_COMMITTEE_SIZE
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#sync-aggregate-processing
func get_proposer_reward*(participant_reward: Gwei): Gwei =
participant_reward * PROPOSER_WEIGHT div (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#sync-aggregate-processing
proc process_sync_aggregate*(
2022-12-06 12:40:13 +00:00
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState | electra.BeaconState |
fulu.BeaconState),
sync_aggregate: SomeSyncAggregate, total_active_balance: Gwei,
flags: UpdateFlags, cache: var StateCache): Result[Gwei, cstring] =
if strictVerification in flags and state.slot > 1.Slot:
template sync_committee_bits(): auto = sync_aggregate.sync_committee_bits
let num_active_participants = countOnes(sync_committee_bits).uint64
if num_active_participants * 3 < static(sync_committee_bits.len * 2):
fatal "Low sync committee participation",
slot = state.slot, num_active_participants
quit 1
# Verify sync committee aggregate signature signing over the previous slot
# block root
when sync_aggregate.sync_committee_signature isnot TrustedSig:
speed up epoch processing 6x+ (#3089) * speed up epoch processing 6x+ This change above all helps contain long replay times on epoch change, reorg and deep history inspection via REST/RPC * most effective balances don't actually change due to MAX_EFFECTIVE_BALANCE * ditto for inactivity scores * avoid signature check for trusted sync aggregates pre: ``` ./ncli_db --db:mainnet_0/db bench --start-slot=-3200 All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3468.621, 0.000, 3468.621, 3468.621, 1, Initialize DB 0.357, 0.938, 0.171, 52.752, 3155, Load block from database 15691.471, 0.000, 15691.471, 15691.471, 1, Load state from database 6.100, 9.469, 0.033, 526.816, 3101, Advance slot, non-epoch 579.131, 9.523, 566.936, 610.328, 100, Advance slot, epoch 18.551, 16.317, 12.664, 136.668, 3155, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` post: ``` Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 3488.541, 0.000, 3488.541, 3488.541, 1, Initialize DB 0.369, 1.123, 0.183, 63.208, 3155, Load block from database 13430.642, 0.000, 13430.642, 13430.642, 1, Load state from database 6.522, 1.721, 0.034, 36.708, 3101, Advance slot, non-epoch 89.074, 3.162, 83.573, 101.436, 100, Advance slot, epoch 18.325, 18.346, 13.005, 145.040, 3155, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` * Update beacon_chain/spec/state_transition_block.nim Co-authored-by: zah <zahary@gmail.com> * avoid copying validator data in accessor ``` 5291.227, 0.000, 5291.227, 5291.227, 1, Initialize DB 0.436, 0.928, 0.138, 51.438, 3155, Load block from database 11962.826, 0.000, 11962.826, 11962.826, 1, Load state from database 6.477, 1.675, 0.037, 34.174, 3101, Advance slot, non-epoch 76.633, 3.705, 71.106, 98.085, 100, Advance slot, epoch 18.301, 18.593, 13.208, 149.153, 3155, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` * work around compiler bug Co-authored-by: zah <zahary@gmail.com>
2021-11-11 19:24:29 +00:00
var participant_pubkeys: seq[ValidatorPubKey]
Speed up altair block processing 2x (#3115) * Speed up altair block processing >2x Like #3089, this PR drastially speeds up historical REST queries and other long state replays. * cache sync committee validator indices * use ~80mb less memory for validator pubkey mappings * batch-verify sync aggregate signature (fixes #2985) * document sync committee hack with head block vs sync message block * add batch signature verification failure tests Before: ``` ../env.sh nim c -d:release -r ncli_db --db:mainnet_0/db bench --start-slot:-1000 All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 5830.675, 0.000, 5830.675, 5830.675, 1, Initialize DB 0.481, 1.878, 0.215, 59.167, 981, Load block from database 8422.566, 0.000, 8422.566, 8422.566, 1, Load state from database 6.996, 1.678, 0.042, 14.385, 969, Advance slot, non-epoch 93.217, 8.318, 84.192, 122.209, 32, Advance slot, epoch 20.513, 23.665, 11.510, 201.561, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` After: ``` 7081.422, 0.000, 7081.422, 7081.422, 1, Initialize DB 0.553, 2.122, 0.175, 66.692, 981, Load block from database 5439.446, 0.000, 5439.446, 5439.446, 1, Load state from database 6.829, 1.575, 0.043, 12.156, 969, Advance slot, non-epoch 94.716, 2.749, 88.395, 100.026, 32, Advance slot, epoch 11.636, 23.766, 4.889, 205.250, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` * add comment
2021-11-24 12:43:50 +00:00
for i in 0 ..< state.current_sync_committee.pubkeys.len:
if sync_aggregate.sync_committee_bits[i]:
participant_pubkeys.add state.current_sync_committee.pubkeys.data[i]
Speed up altair block processing 2x (#3115) * Speed up altair block processing >2x Like #3089, this PR drastially speeds up historical REST queries and other long state replays. * cache sync committee validator indices * use ~80mb less memory for validator pubkey mappings * batch-verify sync aggregate signature (fixes #2985) * document sync committee hack with head block vs sync message block * add batch signature verification failure tests Before: ``` ../env.sh nim c -d:release -r ncli_db --db:mainnet_0/db bench --start-slot:-1000 All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 5830.675, 0.000, 5830.675, 5830.675, 1, Initialize DB 0.481, 1.878, 0.215, 59.167, 981, Load block from database 8422.566, 0.000, 8422.566, 8422.566, 1, Load state from database 6.996, 1.678, 0.042, 14.385, 969, Advance slot, non-epoch 93.217, 8.318, 84.192, 122.209, 32, Advance slot, epoch 20.513, 23.665, 11.510, 201.561, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` After: ``` 7081.422, 0.000, 7081.422, 7081.422, 1, Initialize DB 0.553, 2.122, 0.175, 66.692, 981, Load block from database 5439.446, 0.000, 5439.446, 5439.446, 1, Load state from database 6.829, 1.575, 0.043, 12.156, 969, Advance slot, non-epoch 94.716, 2.749, 88.395, 100.026, 32, Advance slot, epoch 11.636, 23.766, 4.889, 205.250, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` * add comment
2021-11-24 12:43:50 +00:00
# p2p-interface message validators check for empty sync committees, so it
# shouldn't run except as part of test suite.
if participant_pubkeys.len == 0:
if sync_aggregate.sync_committee_signature != ValidatorSig.infinity():
return err("process_sync_aggregate: empty sync aggregates need signature of point at infinity")
else:
# Empty participants allowed
let
previous_slot = max(state.slot, Slot(1)) - 1
beacon_block_root = get_block_root_at_slot(state, previous_slot)
if not verify_sync_committee_signature(
state.fork, state.genesis_validators_root, previous_slot,
beacon_block_root, participant_pubkeys,
sync_aggregate.sync_committee_signature):
return err("process_sync_aggregate: invalid signature")
# Compute participant and proposer rewards
let
participant_reward = get_participant_reward(total_active_balance)
proposer_reward = state_transition_block.get_proposer_reward(participant_reward)
2023-01-11 12:29:21 +00:00
proposer_index = get_beacon_proposer_index(state, cache).valueOr:
# We're processing a block, so this can't happen, in theory (!)
return err("process_sync_aggregate: no proposer")
# Apply participant and proposer rewards
Speed up altair block processing 2x (#3115) * Speed up altair block processing >2x Like #3089, this PR drastially speeds up historical REST queries and other long state replays. * cache sync committee validator indices * use ~80mb less memory for validator pubkey mappings * batch-verify sync aggregate signature (fixes #2985) * document sync committee hack with head block vs sync message block * add batch signature verification failure tests Before: ``` ../env.sh nim c -d:release -r ncli_db --db:mainnet_0/db bench --start-slot:-1000 All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 5830.675, 0.000, 5830.675, 5830.675, 1, Initialize DB 0.481, 1.878, 0.215, 59.167, 981, Load block from database 8422.566, 0.000, 8422.566, 8422.566, 1, Load state from database 6.996, 1.678, 0.042, 14.385, 969, Advance slot, non-epoch 93.217, 8.318, 84.192, 122.209, 32, Advance slot, epoch 20.513, 23.665, 11.510, 201.561, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` After: ``` 7081.422, 0.000, 7081.422, 7081.422, 1, Initialize DB 0.553, 2.122, 0.175, 66.692, 981, Load block from database 5439.446, 0.000, 5439.446, 5439.446, 1, Load state from database 6.829, 1.575, 0.043, 12.156, 969, Advance slot, non-epoch 94.716, 2.749, 88.395, 100.026, 32, Advance slot, epoch 11.636, 23.766, 4.889, 205.250, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` * add comment
2021-11-24 12:43:50 +00:00
let indices = get_sync_committee_cache(state, cache).current_sync_committee
for i in 0 ..< min(
state.current_sync_committee.pubkeys.len,
sync_aggregate.sync_committee_bits.len):
Speed up altair block processing 2x (#3115) * Speed up altair block processing >2x Like #3089, this PR drastially speeds up historical REST queries and other long state replays. * cache sync committee validator indices * use ~80mb less memory for validator pubkey mappings * batch-verify sync aggregate signature (fixes #2985) * document sync committee hack with head block vs sync message block * add batch signature verification failure tests Before: ``` ../env.sh nim c -d:release -r ncli_db --db:mainnet_0/db bench --start-slot:-1000 All time are ms Average, StdDev, Min, Max, Samples, Test Validation is turned off meaning that no BLS operations are performed 5830.675, 0.000, 5830.675, 5830.675, 1, Initialize DB 0.481, 1.878, 0.215, 59.167, 981, Load block from database 8422.566, 0.000, 8422.566, 8422.566, 1, Load state from database 6.996, 1.678, 0.042, 14.385, 969, Advance slot, non-epoch 93.217, 8.318, 84.192, 122.209, 32, Advance slot, epoch 20.513, 23.665, 11.510, 201.561, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` After: ``` 7081.422, 0.000, 7081.422, 7081.422, 1, Initialize DB 0.553, 2.122, 0.175, 66.692, 981, Load block from database 5439.446, 0.000, 5439.446, 5439.446, 1, Load state from database 6.829, 1.575, 0.043, 12.156, 969, Advance slot, non-epoch 94.716, 2.749, 88.395, 100.026, 32, Advance slot, epoch 11.636, 23.766, 4.889, 205.250, 981, Apply block, no slot processing 0.000, 0.000, 0.000, 0.000, 0, Database load 0.000, 0.000, 0.000, 0.000, 0, Database store ``` * add comment
2021-11-24 12:43:50 +00:00
let participant_index = indices[i]
if sync_aggregate.sync_committee_bits[i]:
increase_balance(state, participant_index, participant_reward)
2023-01-11 12:29:21 +00:00
increase_balance(state, proposer_index, proposer_reward)
else:
decrease_balance(state, participant_index, participant_reward)
ok(proposer_reward)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/beacon-chain.md#process_execution_payload
proc process_execution_payload*(
2022-10-27 06:29:24 +00:00
state: var bellatrix.BeaconState, payload: bellatrix.ExecutionPayload,
notify_new_payload: bellatrix.ExecutePayload): Result[void, cstring] =
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if is_merge_transition_complete(state):
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
2022-10-27 06:29:24 +00:00
state.latest_execution_payload_header = bellatrix.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions))
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/capella/beacon-chain.md#modified-process_execution_payload
2022-10-27 06:29:24 +00:00
proc process_execution_payload*(
state: var capella.BeaconState, payload: capella.ExecutionPayload,
notify_new_payload: capella.ExecutePayload): Result[void, cstring] =
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
2022-10-27 06:29:24 +00:00
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = capella.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals)) # [New in Capella]
ok()
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
# copy of datatypes/deneb.nim
type SomeDenebBeaconBlockBody =
deneb.BeaconBlockBody | deneb.SigVerifiedBeaconBlockBody |
deneb.TrustedBeaconBlockBody
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/deneb/beacon-chain.md#process_execution_payload
2022-12-06 12:40:13 +00:00
proc process_execution_payload*(
state: var deneb.BeaconState, body: SomeDenebBeaconBlockBody,
notify_new_payload: deneb.ExecutePayload): Result[void, cstring] =
template payload: auto = body.execution_payload
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
2022-12-06 12:40:13 +00:00
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# [New in Deneb] Verify commitments are under limit
if not (lenu64(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK):
return err("process_execution_payload: too many KZG commitments")
2022-12-06 12:40:13 +00:00
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = deneb.ExecutionPayloadHeader(
2022-12-06 12:40:13 +00:00
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals),
blob_gas_used: payload.blob_gas_used, # [New in Deneb]
excess_blob_gas: payload.excess_blob_gas) # [New in Deneb]
2022-12-06 12:40:13 +00:00
ok()
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
# copy of datatypes/electra.nim
type SomeElectraBeaconBlockBody =
electra.BeaconBlockBody | electra.SigVerifiedBeaconBlockBody |
electra.TrustedBeaconBlockBody
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/electra/beacon-chain.md#modified-process_execution_payload
proc process_execution_payload*(
state: var electra.BeaconState, body: SomeElectraBeaconBlockBody,
notify_new_payload: electra.ExecutePayload): Result[void, cstring] =
template payload: auto = body.execution_payload
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# [New in Deneb] Verify commitments are under limit
if not (lenu64(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK):
return err("process_execution_payload: too many KZG commitments")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = electra.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals),
blob_gas_used: payload.blob_gas_used,
2024-10-16 21:29:47 +00:00
excess_blob_gas: payload.excess_blob_gas,
system_logs_root: payload.system_logs_root)
ok()
# copy of datatypes/fulu.nim
type SomeFuluBeaconBlockBody =
fulu.BeaconBlockBody | fulu.SigVerifiedBeaconBlockBody |
fulu.TrustedBeaconBlockBody
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/electra/beacon-chain.md#modified-process_execution_payload
proc process_execution_payload*(
state: var fulu.BeaconState, body: SomeFuluBeaconBlockBody,
notify_new_payload: fulu.ExecutePayload): Result[void, cstring] =
template payload: auto = body.execution_payload
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# [New in Deneb] Verify commitments are under limit
if not (lenu64(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK):
return err("process_execution_payload: too many KZG commitments")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = fulu.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals),
blob_gas_used: payload.blob_gas_used,
excess_blob_gas: payload.excess_blob_gas)
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/capella/beacon-chain.md#new-process_withdrawals
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/electra/beacon-chain.md#updated-process_withdrawals
2022-10-27 06:29:24 +00:00
func process_withdrawals*(
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState |
fulu.BeaconState),
payload: capella.ExecutionPayload | deneb.ExecutionPayload |
electra.ExecutionPayload | fulu.ExecutionPayload):
2022-10-27 06:29:24 +00:00
Result[void, cstring] =
when typeof(state).kind >= ConsensusFork.Electra:
let (expected_withdrawals, partial_withdrawals_count) =
get_expected_withdrawals_with_partial_count(state)
# Update pending partial withdrawals [New in Electra:EIP7251]
# Moved slightly earlier to be in same when block
state.pending_partial_withdrawals =
HashList[PendingPartialWithdrawal, Limit PENDING_PARTIAL_WITHDRAWALS_LIMIT].init(
state.pending_partial_withdrawals.asSeq[partial_withdrawals_count .. ^1])
else:
let expected_withdrawals = get_expected_withdrawals(state)
if not (len(payload.withdrawals) == len(expected_withdrawals)):
return err("process_withdrawals: different numbers of payload and expected withdrawals")
for i in 0 ..< len(expected_withdrawals):
if expected_withdrawals[i] != payload.withdrawals[i]:
return err("process_withdrawals: mismatched expected and payload withdrawal")
let validator_index =
ValidatorIndex.init(expected_withdrawals[i].validator_index).valueOr:
return err("process_withdrawals: invalid validator index")
decrease_balance(
state, validator_index, expected_withdrawals[i].amount)
# Update the next withdrawal index if this block contained withdrawals
if len(expected_withdrawals) != 0:
let latest_withdrawal = expected_withdrawals[^1]
state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
# Update the next validator index to start the next withdrawal sweep
if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
# Next sweep starts after the latest withdrawal's validator index
let next_validator_index =
(expected_withdrawals[^1].validator_index + 1) mod
lenu64(state.validators)
state.next_withdrawal_validator_index = next_validator_index
else:
# Advance sweep by the max length of the sweep if there was not a full set
# of withdrawals
let next_index =
state.next_withdrawal_validator_index +
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
let next_validator_index = next_index mod lenu64(state.validators)
state.next_withdrawal_validator_index = next_validator_index
2022-10-27 06:29:24 +00:00
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/deneb/beacon-chain.md#kzg_commitment_to_versioned_hash
func kzg_commitment_to_versioned_hash*(
kzg_commitment: KzgCommitment): VersionedHash =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/deneb/beacon-chain.md#blob
const VERSIONED_HASH_VERSION_KZG = 0x01'u8
var res: VersionedHash
res[0] = VERSIONED_HASH_VERSION_KZG
res[1 .. 31] = eth2digest(kzg_commitment.bytes).data.toOpenArray(1, 31)
res
proc validate_blobs*(
expected_kzg_commitments: seq[KzgCommitment], blobs: seq[KzgBlob],
proofs: seq[KzgProof]): Result[void, string] =
let res = verifyBlobKzgProofBatch(blobs, expected_kzg_commitments, proofs).valueOr:
return err("validate_blobs proof verification error: " & error())
if not res:
return err("validate_blobs proof verification failed")
ok()
# 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*(
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
cfg: RuntimeConfig,
state: var phase0.BeaconState, blck: SomePhase0Block, flags: UpdateFlags,
cache: var StateCache): Result[BlockRewards, cstring]=
## 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)
ok(? process_operations(cfg, state, blck.body, 0.Gwei, flags, cache))
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/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*(
Implement split preset/config support (#2710) * Implement split preset/config support This is the initial bulk refactor to introduce runtime config values in a number of places, somewhat replacing the existing mechanism of loading network metadata. It still needs more work, this is the initial refactor that introduces runtime configuration in some of the places that need it. The PR changes the way presets and constants work, to match the spec. In particular, a "preset" now refers to the compile-time configuration while a "cfg" or "RuntimeConfig" is the dynamic part. A single binary can support either mainnet or minimal, but not both. Support for other presets has been removed completely (can be readded, in case there's need). There's a number of outstanding tasks: * `SECONDS_PER_SLOT` still needs fixing * loading custom runtime configs needs redoing * checking constants against YAML file * yeerongpilly support `build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG` * load fork epoch from config * fix fork digest sent in status * nicer error string for request failures * fix tools * one more * fixup * fixup * fixup * use "standard" network definition folder in local testnet Files are loaded from their standard locations, including genesis etc, to conform to the format used in the `eth2-networks` repo. * fix launch scripts, allow unknown config values * fix base config of rest test * cleanups * bundle mainnet config using common loader * fix spec links and names * only include supported preset in binary * drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
cfg: RuntimeConfig,
state: var altair.BeaconState, blck: SomeAltairBlock, flags: UpdateFlags,
cache: var StateCache): Result[BlockRewards, cstring]=
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 - 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)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
var operations_rewards = ? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
operations_rewards.sync_aggregate = ? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance,
flags, cache) # [New in Altair]
2019-06-28 13:44:44 +00:00
ok(operations_rewards)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
type SomeBellatrixBlock =
bellatrix.BeaconBlock | bellatrix.SigVerifiedBeaconBlock | bellatrix.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var bellatrix.BeaconState, blck: SomeBellatrixBlock,
flags: UpdateFlags, cache: var StateCache): Result[BlockRewards, cstring]=
## 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)
if is_execution_enabled(state, blck.body):
? process_execution_payload(
state, blck.body.execution_payload,
func(_: bellatrix.ExecutionPayload): bool = true) # [New in Bellatrix]
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
var operations_rewards = ? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
operations_rewards.sync_aggregate = ? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok(operations_rewards)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/capella/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
type SomeCapellaBlock =
capella.BeaconBlock | capella.SigVerifiedBeaconBlock | capella.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var capella.BeaconState, blck: SomeCapellaBlock,
flags: UpdateFlags, cache: var StateCache): Result[BlockRewards, cstring] =
## 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)
# Consensus specs v1.4.0 unconditionally assume is_execution_enabled is
# true, but intentionally keep such a check.
if is_execution_enabled(state, blck.body):
? process_withdrawals(
state, blck.body.execution_payload) # [New in Capella]
? process_execution_payload(
state, blck.body.execution_payload,
func(_: capella.ExecutionPayload): bool = true) # [Modified in Capella]
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
var operations_rewards = ? process_operations(
cfg, state, blck.body, base_reward_per_increment,
flags, cache) # [Modified in Capella]
operations_rewards.sync_aggregate = ? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok(operations_rewards)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/deneb/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
type SomeDenebBlock =
deneb.BeaconBlock | deneb.SigVerifiedBeaconBlock | deneb.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var deneb.BeaconState, blck: SomeDenebBlock,
flags: UpdateFlags, cache: var StateCache): Result[BlockRewards, cstring] =
## 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)
# Consensus specs v1.4.0 unconditionally assume is_execution_enabled is
# true, but intentionally keep such a check.
if is_execution_enabled(state, blck.body):
? process_withdrawals(state, blck.body.execution_payload)
? process_execution_payload(
state, blck.body,
func(_: deneb.ExecutionPayload): bool = true) # [Modified in Deneb]
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
var operations_rewards = ? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
operations_rewards.sync_aggregate = ? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok(operations_rewards)
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.1/specs/electra/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
type SomeElectraBlock =
electra.BeaconBlock | electra.SigVerifiedBeaconBlock | electra.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var electra.BeaconState, blck: SomeElectraBlock,
flags: UpdateFlags, cache: var StateCache): Result[BlockRewards, cstring] =
## 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)
# Consensus specs v1.4.0 unconditionally assume is_execution_enabled is
# true, but intentionally keep such a check.
if is_execution_enabled(state, blck.body):
? process_withdrawals(state, blck.body.execution_payload)
? process_execution_payload(
state, blck.body,
func(_: electra.ExecutionPayload): bool = true)
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
var operations_rewards = ? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
operations_rewards.sync_aggregate = ? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok(operations_rewards)
type SomeFuluBlock =
fulu.BeaconBlock | fulu.SigVerifiedBeaconBlock | fulu.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var fulu.BeaconState, blck: SomeFuluBlock,
flags: UpdateFlags, cache: var StateCache): Result[BlockRewards, cstring] =
## 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)
# Consensus specs v1.4.0 unconditionally assume is_execution_enabled is
# true, but intentionally keep such a check.
if is_execution_enabled(state, blck.body):
? process_withdrawals(state, blck.body.execution_payload)
? process_execution_payload(
state, blck.body,
func(_: fulu.ExecutionPayload): bool = true)
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
var operations_rewards = ? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
operations_rewards.sync_aggregate = ? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok(operations_rewards)