2019-06-28 13:44:44 +00:00
|
|
|
# beacon_chain
|
2024-01-06 14:26:56 +00:00
|
|
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
2019-06-28 13:44:44 +00:00
|
|
|
# Licensed and distributed under either of
|
2019-11-25 15:30:02 +00:00
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
2019-06-28 13:44:44 +00:00
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2024-02-18 01:16:49 +00:00
|
|
|
{.push raises: [].}
|
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
# State transition - epoch processing, as described in
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#epoch-processing
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#epoch-processing
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#epoch-processing
|
2023-04-21 18:52:43 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/capella/beacon-chain.md#epoch-processing
|
2019-06-28 13:44:44 +00:00
|
|
|
#
|
2020-06-09 09:42:53 +00:00
|
|
|
# The entry point is `process_epoch`, which is at the bottom of this file.
|
2019-06-28 13:44:44 +00:00
|
|
|
#
|
2020-11-04 21:52:47 +00:00
|
|
|
# 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
|
2020-11-04 21:52:47 +00:00
|
|
|
# * 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
|
|
|
|
2019-11-12 05:35:52 +00:00
|
|
|
import
|
2024-02-20 05:14:52 +00:00
|
|
|
stew/assign2, chronicles,
|
2020-10-22 11:08:46 +00:00
|
|
|
../extras,
|
2023-09-07 11:14:52 +00:00
|
|
|
"."/[beaconstate, eth2_merkleization, validator]
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2022-12-08 16:21:53 +00:00
|
|
|
from std/math import sum, `^`
|
2024-02-20 05:14:52 +00:00
|
|
|
from stew/bitops2 import setBit
|
2023-01-09 14:15:43 +00:00
|
|
|
from ./datatypes/capella import
|
|
|
|
BeaconState, HistoricalSummary, Withdrawal, WithdrawalIndex
|
2022-10-27 06:29:24 +00:00
|
|
|
|
2021-08-12 13:08:20 +00:00
|
|
|
export extras, phase0, altair
|
|
|
|
|
2019-09-23 13:48:25 +00:00
|
|
|
# Logging utilities
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
|
|
logScope: topics = "consens"
|
|
|
|
|
2020-10-22 11:08:46 +00:00
|
|
|
# Accessors that implement the max condition in `get_total_balance`:
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#get_total_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
template current_epoch*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.current_epoch_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
template previous_epoch*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
template current_epoch_attesters*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.current_epoch_attesters_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
template current_epoch_target_attesters*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.current_epoch_target_attesters_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
template previous_epoch_attesters*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_attesters_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
template previous_epoch_target_attesters*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_target_attesters_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
template previous_epoch_head_attesters*(v: TotalBalances): Gwei =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_head_attesters_raw)
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
func init*(info: var phase0.EpochInfo, state: phase0.BeaconState) =
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances = TotalBalances()
|
|
|
|
info.validators.setLen(state.validators.len)
|
2021-05-07 11:36:21 +00:00
|
|
|
|
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
|
|
|
for i in 0..<state.validators.len:
|
|
|
|
let v = unsafeAddr state.validators[i]
|
2021-05-07 11:36:21 +00:00
|
|
|
var flags: set[RewardFlags]
|
|
|
|
|
|
|
|
if v[].slashed:
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl(RewardFlags.isSlashed)
|
2021-05-07 11:36:21 +00:00
|
|
|
if state.get_current_epoch() >= v[].withdrawable_epoch:
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl RewardFlags.canWithdrawInCurrentEpoch
|
2020-10-22 11:08:46 +00:00
|
|
|
|
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 v[].is_active_validator(state.get_current_epoch()):
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.current_epoch_raw += v[].effective_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
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 v[].is_active_validator(state.get_previous_epoch()):
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl RewardFlags.isActiveInPreviousEpoch
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.previous_epoch_raw += v[].effective_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-11-25 12:20:36 +00:00
|
|
|
info.validators[i] = RewardStatus(
|
2021-05-07 11:36:21 +00:00
|
|
|
current_epoch_effective_balance: v[].effective_balance,
|
|
|
|
flags: flags,
|
|
|
|
)
|
|
|
|
|
|
|
|
func add(a: var RewardDelta, b: RewardDelta) =
|
2020-10-22 11:08:46 +00:00
|
|
|
a.rewards += b.rewards
|
|
|
|
a.penalties += b.penalties
|
|
|
|
|
|
|
|
func process_attestation(
|
2021-10-13 14:24:36 +00:00
|
|
|
info: var phase0.EpochInfo, state: phase0.BeaconState, a: PendingAttestation,
|
2020-10-22 11:08:46 +00:00
|
|
|
cache: var StateCache) =
|
|
|
|
# Collect information about the attestation
|
|
|
|
var
|
2021-05-07 11:36:21 +00:00
|
|
|
flags: set[RewardFlags]
|
2023-01-11 12:29:21 +00:00
|
|
|
is_previous_epoch_attester: Opt[InclusionInfo]
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
if a.data.target.epoch == state.get_current_epoch():
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl RewardFlags.isCurrentEpochAttester
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
if a.data.target.root == get_block_root(state, state.get_current_epoch()):
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl RewardFlags.isCurrentEpochTargetAttester
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
elif a.data.target.epoch == state.get_previous_epoch():
|
2023-01-11 12:29:21 +00:00
|
|
|
is_previous_epoch_attester = Opt.some(InclusionInfo(
|
2020-10-22 11:08:46 +00:00
|
|
|
delay: a.inclusion_delay,
|
|
|
|
proposer_index: a.proposer_index,
|
|
|
|
))
|
|
|
|
|
|
|
|
if a.data.target.root == get_block_root(state, state.get_previous_epoch()):
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl RewardFlags.isPreviousEpochTargetAttester
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot):
|
2021-05-28 15:25:58 +00:00
|
|
|
flags.incl RewardFlags.isPreviousEpochHeadAttester
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
# Update the cache for all participants
|
2023-08-02 23:03:40 +00:00
|
|
|
for validator_index in get_attesting_indices_iter(
|
2020-10-22 11:08:46 +00:00
|
|
|
state, a.data, a.aggregation_bits, cache):
|
2021-11-25 12:20:36 +00:00
|
|
|
template v(): untyped = info.validators[validator_index]
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-05-07 11:36:21 +00:00
|
|
|
v.flags = v.flags + flags
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
if is_previous_epoch_attester.isSome:
|
2021-10-13 14:24:36 +00:00
|
|
|
if v.is_previous_epoch_attester.isSome:
|
2020-10-22 11:08:46 +00:00
|
|
|
if is_previous_epoch_attester.get().delay <
|
|
|
|
v.is_previous_epoch_attester.get().delay:
|
|
|
|
v.is_previous_epoch_attester = is_previous_epoch_attester
|
|
|
|
else:
|
|
|
|
v.is_previous_epoch_attester = is_previous_epoch_attester
|
|
|
|
|
|
|
|
func process_attestations*(
|
2021-10-13 14:24:36 +00:00
|
|
|
info: var phase0.EpochInfo, state: phase0.BeaconState, cache: var StateCache) =
|
2020-10-22 11:08:46 +00:00
|
|
|
# Walk state attestations and update the status information
|
|
|
|
for a in state.previous_epoch_attestations:
|
2021-10-13 14:24:36 +00:00
|
|
|
process_attestation(info, state, a, cache)
|
2020-10-22 11:08:46 +00:00
|
|
|
for a in state.current_epoch_attestations:
|
2021-10-13 14:24:36 +00:00
|
|
|
process_attestation(info, state, a, cache)
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-11-25 12:20:36 +00:00
|
|
|
for idx, v in info.validators:
|
2021-05-28 15:25:58 +00:00
|
|
|
if v.flags.contains RewardFlags.isSlashed:
|
2020-10-22 11:08:46 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
let validator_balance = state.validators[idx].effective_balance
|
|
|
|
|
2021-05-28 15:25:58 +00:00
|
|
|
if v.flags.contains RewardFlags.isCurrentEpochAttester:
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.current_epoch_attesters_raw += validator_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-05-28 15:25:58 +00:00
|
|
|
if v.flags.contains RewardFlags.isCurrentEpochTargetAttester:
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.current_epoch_target_attesters_raw += validator_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
if v.is_previous_epoch_attester.isSome():
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.previous_epoch_attesters_raw += validator_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-05-28 15:25:58 +00:00
|
|
|
if v.flags.contains RewardFlags.isPreviousEpochTargetAttester:
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.previous_epoch_target_attesters_raw += validator_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-05-28 15:25:58 +00:00
|
|
|
if v.flags.contains RewardFlags.isPreviousEpochHeadAttester:
|
2021-11-25 12:20:36 +00:00
|
|
|
info.balances.previous_epoch_head_attesters_raw += validator_balance
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#helpers
|
2021-10-13 14:24:36 +00:00
|
|
|
# get_eligible_validator_indices
|
2021-05-07 11:36:21 +00:00
|
|
|
func is_eligible_validator*(validator: RewardStatus): bool =
|
2021-05-28 15:25:58 +00:00
|
|
|
validator.flags.contains(RewardFlags.isActiveInPreviousEpoch) or
|
|
|
|
(validator.flags.contains(RewardFlags.isSlashed) and not
|
|
|
|
(validator.flags.contains RewardFlags.canWithdrawInCurrentEpoch))
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
func is_eligible_validator*(validator: Validator, previous_epoch: Epoch): bool =
|
|
|
|
is_active_validator(validator, previous_epoch) or
|
|
|
|
(validator.slashed and previous_epoch + 1 < validator.withdrawable_epoch)
|
|
|
|
|
|
|
|
func is_eligible_validator*(validator: ParticipationInfo): bool =
|
|
|
|
validator.flags.contains(ParticipationFlag.eligible)
|
|
|
|
|
2019-09-23 13:48:25 +00:00
|
|
|
# Spec
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
2023-02-23 18:06:57 +00:00
|
|
|
from ./datatypes/deneb import BeaconState
|
2022-12-06 16:43:11 +00:00
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_unslashed_participating_indices
|
2022-07-06 10:33:02 +00:00
|
|
|
func get_unslashed_participating_balances*(
|
2022-12-06 16:43:11 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState):
|
2024-02-26 02:38:21 +00:00
|
|
|
UnslashedParticipatingBalances =
|
2021-08-25 14:43:00 +00:00
|
|
|
let
|
|
|
|
previous_epoch = get_previous_epoch(state)
|
|
|
|
current_epoch = get_current_epoch(state)
|
|
|
|
var res: UnslashedParticipatingBalances
|
|
|
|
|
|
|
|
for validator_index in 0'u64 ..< state.validators.lenu64:
|
2021-10-13 14:24:36 +00:00
|
|
|
let
|
|
|
|
is_active_current_epoch = is_active_validator(
|
|
|
|
state.validators[validator_index], current_epoch)
|
|
|
|
validator_effective_balance =
|
|
|
|
state.validators[validator_index].effective_balance
|
|
|
|
|
|
|
|
if is_active_current_epoch:
|
|
|
|
# Active balance counted also for slashed validators
|
|
|
|
res.current_epoch += validator_effective_balance
|
|
|
|
|
2021-08-25 14:43:00 +00:00
|
|
|
if state.validators[validator_index].slashed:
|
|
|
|
continue
|
2021-10-13 14:24:36 +00:00
|
|
|
|
2021-08-25 14:43:00 +00:00
|
|
|
let
|
|
|
|
is_active_previous_epoch = is_active_validator(
|
|
|
|
state.validators[validator_index], previous_epoch)
|
|
|
|
previous_epoch_participation =
|
|
|
|
state.previous_epoch_participation[validator_index]
|
2021-10-13 14:24:36 +00:00
|
|
|
|
2021-08-25 14:43:00 +00:00
|
|
|
if is_active_previous_epoch:
|
2023-08-02 23:03:40 +00:00
|
|
|
for flag_index in TimelyFlag:
|
2021-08-25 14:43:00 +00:00
|
|
|
if has_flag(previous_epoch_participation, flag_index):
|
|
|
|
res.previous_epoch[flag_index] += validator_effective_balance
|
|
|
|
|
|
|
|
# Only TIMELY_TARGET_FLAG_INDEX is used with the current epoch in Altair
|
2021-12-05 17:32:41 +00:00
|
|
|
# and merge
|
2021-08-25 14:43:00 +00:00
|
|
|
if is_active_current_epoch and has_flag(
|
|
|
|
state.current_epoch_participation[validator_index],
|
|
|
|
TIMELY_TARGET_FLAG_INDEX):
|
|
|
|
res.current_epoch_TIMELY_TARGET += validator_effective_balance
|
|
|
|
|
2023-08-02 23:03:40 +00:00
|
|
|
for flag_index in TimelyFlag:
|
2021-08-25 14:43:00 +00:00
|
|
|
res.previous_epoch[flag_index] =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res.previous_epoch[flag_index])
|
2021-08-25 14:43:00 +00:00
|
|
|
|
|
|
|
res.current_epoch_TIMELY_TARGET =
|
2024-03-19 13:22:07 +00:00
|
|
|
max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res.current_epoch_TIMELY_TARGET)
|
2021-08-24 20:09:03 +00:00
|
|
|
|
2024-03-19 13:22:07 +00:00
|
|
|
res.current_epoch = max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res.current_epoch)
|
2021-10-13 14:24:36 +00:00
|
|
|
|
2021-08-24 20:09:03 +00:00
|
|
|
res
|
|
|
|
|
2021-08-25 14:43:00 +00:00
|
|
|
func is_unslashed_participating_index(
|
2022-12-06 16:43:11 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2023-08-02 23:03:40 +00:00
|
|
|
flag_index: TimelyFlag, epoch: Epoch, validator_index: ValidatorIndex): bool =
|
2021-05-28 15:25:58 +00:00
|
|
|
doAssert epoch in [get_previous_epoch(state), get_current_epoch(state)]
|
2021-08-25 14:43:00 +00:00
|
|
|
# TODO hoist this conditional
|
2021-08-24 20:09:03 +00:00
|
|
|
let epoch_participation =
|
|
|
|
if epoch == get_current_epoch(state):
|
|
|
|
unsafeAddr state.current_epoch_participation
|
|
|
|
else:
|
|
|
|
unsafeAddr state.previous_epoch_participation
|
2021-05-30 20:23:10 +00:00
|
|
|
|
2021-08-25 14:43:00 +00:00
|
|
|
is_active_validator(state.validators[validator_index], epoch) and
|
2022-05-30 13:30:42 +00:00
|
|
|
has_flag(epoch_participation[].item(validator_index), flag_index) and
|
2021-08-25 14:43:00 +00:00
|
|
|
not state.validators[validator_index].slashed
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#justification-and-finalization
|
2022-07-06 10:33:02 +00:00
|
|
|
type FinalityState = object
|
|
|
|
slot: Slot
|
|
|
|
current_epoch_ancestor_root: Eth2Digest
|
|
|
|
previous_epoch_ancestor_root: Eth2Digest
|
|
|
|
justification_bits: JustificationBits
|
|
|
|
previous_justified_checkpoint: Checkpoint
|
|
|
|
current_justified_checkpoint: Checkpoint
|
|
|
|
finalized_checkpoint: Checkpoint
|
|
|
|
|
|
|
|
func toFinalityState(state: ForkyBeaconState): FinalityState =
|
2019-06-28 13:44:44 +00:00
|
|
|
let
|
|
|
|
current_epoch = get_current_epoch(state)
|
2022-07-06 10:33:02 +00:00
|
|
|
previous_epoch = get_previous_epoch(state)
|
|
|
|
FinalityState(
|
|
|
|
slot: state.slot,
|
|
|
|
current_epoch_ancestor_root:
|
|
|
|
if state.slot > current_epoch.start_slot:
|
|
|
|
get_block_root(state, current_epoch)
|
|
|
|
else:
|
|
|
|
ZERO_HASH,
|
|
|
|
previous_epoch_ancestor_root:
|
|
|
|
if state.slot > previous_epoch.start_slot:
|
|
|
|
get_block_root(state, previous_epoch)
|
|
|
|
else:
|
|
|
|
ZERO_HASH,
|
|
|
|
justification_bits:
|
|
|
|
state.justification_bits,
|
|
|
|
previous_justified_checkpoint:
|
|
|
|
state.previous_justified_checkpoint,
|
|
|
|
current_justified_checkpoint:
|
|
|
|
state.current_justified_checkpoint,
|
|
|
|
finalized_checkpoint:
|
|
|
|
state.finalized_checkpoint)
|
|
|
|
|
|
|
|
func get_current_epoch(state: FinalityState): Epoch =
|
|
|
|
state.slot.epoch
|
|
|
|
|
|
|
|
func get_previous_epoch(state: FinalityState): Epoch =
|
|
|
|
get_previous_epoch(get_current_epoch(state))
|
|
|
|
|
|
|
|
func get_block_root(state: FinalityState, epoch: Epoch): Eth2Digest =
|
|
|
|
doAssert state.slot > epoch.start_slot
|
|
|
|
if epoch == get_current_epoch(state):
|
|
|
|
state.current_epoch_ancestor_root
|
|
|
|
else:
|
|
|
|
doAssert epoch == get_previous_epoch(state)
|
|
|
|
state.previous_epoch_ancestor_root
|
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
type
|
|
|
|
JustificationAndFinalizationInfo = object
|
|
|
|
previous_justified_checkpoint: Checkpoint
|
|
|
|
current_justified_checkpoint: Checkpoint
|
|
|
|
finalized_checkpoint: Checkpoint
|
|
|
|
justification_bits: JustificationBits
|
|
|
|
|
2022-07-06 10:33:02 +00:00
|
|
|
proc weigh_justification_and_finalization(
|
2024-02-20 05:14:52 +00:00
|
|
|
state: ForkyBeaconState | FinalityState,
|
2022-07-06 10:33:02 +00:00
|
|
|
total_active_balance: Gwei,
|
|
|
|
previous_epoch_target_balance: Gwei,
|
|
|
|
current_epoch_target_balance: Gwei,
|
2024-02-20 05:14:52 +00:00
|
|
|
flags: UpdateFlags = {}): JustificationAndFinalizationInfo =
|
2021-05-28 15:25:58 +00:00
|
|
|
let
|
|
|
|
previous_epoch = get_previous_epoch(state)
|
|
|
|
current_epoch = get_current_epoch(state)
|
|
|
|
old_previous_justified_checkpoint = state.previous_justified_checkpoint
|
|
|
|
old_current_justified_checkpoint = state.current_justified_checkpoint
|
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
var res = JustificationAndFinalizationInfo(
|
|
|
|
previous_justified_checkpoint: state.previous_justified_checkpoint,
|
|
|
|
current_justified_checkpoint: state.current_justified_checkpoint,
|
|
|
|
finalized_checkpoint: state.finalized_checkpoint,
|
|
|
|
justification_bits: state.justification_bits)
|
|
|
|
|
2021-05-28 15:25:58 +00:00
|
|
|
# Process justifications
|
2024-02-20 05:14:52 +00:00
|
|
|
res.previous_justified_checkpoint = res.current_justified_checkpoint
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
## Spec:
|
|
|
|
## state.justification_bits[1:] = state.justification_bits[:-1]
|
|
|
|
## state.justification_bits[0] = 0b0
|
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#misc
|
2021-05-28 15:25:58 +00:00
|
|
|
const JUSTIFICATION_BITS_LENGTH = 4
|
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
res.justification_bits = JustificationBits(
|
|
|
|
(uint8(res.justification_bits) shl 1) and
|
2022-01-06 07:38:40 +00:00
|
|
|
uint8((2^JUSTIFICATION_BITS_LENGTH) - 1))
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2021-05-30 20:23:10 +00:00
|
|
|
if previous_epoch_target_balance * 3 >= total_active_balance * 2:
|
2024-02-20 05:14:52 +00:00
|
|
|
res.current_justified_checkpoint = Checkpoint(
|
|
|
|
epoch: previous_epoch, root: get_block_root(state, previous_epoch))
|
|
|
|
uint8(res.justification_bits).setBit 1
|
2022-07-13 13:48:09 +00:00
|
|
|
elif strictVerification in flags:
|
2023-04-19 19:42:30 +00:00
|
|
|
fatal "Low attestation participation in previous epoch",
|
2021-05-30 20:23:10 +00:00
|
|
|
total_active_balance,
|
|
|
|
previous_epoch_target_balance,
|
|
|
|
current_epoch_target_balance,
|
|
|
|
epoch = get_current_epoch(state)
|
2023-04-19 19:42:30 +00:00
|
|
|
quit 1
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2021-05-30 20:23:10 +00:00
|
|
|
if current_epoch_target_balance * 3 >= total_active_balance * 2:
|
2024-02-20 05:14:52 +00:00
|
|
|
res.current_justified_checkpoint = Checkpoint(
|
|
|
|
epoch: current_epoch, root: get_block_root(state, current_epoch))
|
|
|
|
uint8(res.justification_bits).setBit 0
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
# Process finalizations
|
2024-02-20 05:14:52 +00:00
|
|
|
let bitfield = uint8(res.justification_bits)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
## The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th
|
|
|
|
## as source
|
|
|
|
if (bitfield and 0b1110) == 0b1110 and
|
|
|
|
old_previous_justified_checkpoint.epoch + 3 == current_epoch:
|
2024-02-20 05:14:52 +00:00
|
|
|
res.finalized_checkpoint = old_previous_justified_checkpoint
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
## The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as
|
|
|
|
## source
|
|
|
|
if (bitfield and 0b110) == 0b110 and
|
|
|
|
old_previous_justified_checkpoint.epoch + 2 == current_epoch:
|
2024-02-20 05:14:52 +00:00
|
|
|
res.finalized_checkpoint = old_previous_justified_checkpoint
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
## The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as
|
|
|
|
## source
|
|
|
|
if (bitfield and 0b111) == 0b111 and
|
|
|
|
old_current_justified_checkpoint.epoch + 2 == current_epoch:
|
2024-02-20 05:14:52 +00:00
|
|
|
res.finalized_checkpoint = old_current_justified_checkpoint
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
## The 1st/2nd most recent epochs are justified, the 1st using the 2nd as
|
|
|
|
## source
|
|
|
|
if (bitfield and 0b11) == 0b11 and
|
|
|
|
old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
2024-02-20 05:14:52 +00:00
|
|
|
res.finalized_checkpoint = old_current_justified_checkpoint
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
res
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#justification-and-finalization
|
2022-07-06 10:33:02 +00:00
|
|
|
proc process_justification_and_finalization*(
|
|
|
|
state: var phase0.BeaconState,
|
|
|
|
balances: TotalBalances, flags: UpdateFlags = {}) =
|
|
|
|
# Initial FFG checkpoint values have a `0x00` stub for `root`.
|
|
|
|
# Skip FFG updates in the first two epochs to avoid corner cases that might
|
|
|
|
# result in modifying this stub.
|
|
|
|
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
|
|
|
return
|
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
let jfRes = weigh_justification_and_finalization(
|
2022-07-06 10:33:02 +00:00
|
|
|
state, balances.current_epoch,
|
|
|
|
balances.previous_epoch_target_attesters,
|
|
|
|
balances.current_epoch_target_attesters, flags)
|
2024-02-20 05:14:52 +00:00
|
|
|
assign(
|
|
|
|
state.previous_justified_checkpoint, jfRes.previous_justified_checkpoint)
|
|
|
|
assign(
|
|
|
|
state.current_justified_checkpoint, jfRes.current_justified_checkpoint)
|
|
|
|
assign(state.finalized_checkpoint, jfRes.finalized_checkpoint)
|
|
|
|
assign(state.justification_bits, jfRes.justification_bits)
|
2022-07-06 10:33:02 +00:00
|
|
|
|
|
|
|
proc compute_unrealized_finality*(
|
|
|
|
state: phase0.BeaconState, cache: var StateCache): FinalityCheckpoints =
|
|
|
|
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
|
|
|
return FinalityCheckpoints(
|
|
|
|
justified: state.current_justified_checkpoint,
|
|
|
|
finalized: state.finalized_checkpoint)
|
|
|
|
|
|
|
|
var info: phase0.EpochInfo
|
|
|
|
info.init(state)
|
|
|
|
info.process_attestations(state, cache)
|
|
|
|
template balances(): auto = info.balances
|
|
|
|
|
|
|
|
var finalityState = state.toFinalityState()
|
2024-02-20 05:14:52 +00:00
|
|
|
let jfRes = weigh_justification_and_finalization(
|
2022-07-06 10:33:02 +00:00
|
|
|
finalityState, balances.current_epoch,
|
|
|
|
balances.previous_epoch_target_attesters,
|
|
|
|
balances.current_epoch_target_attesters)
|
|
|
|
FinalityCheckpoints(
|
2024-02-20 05:14:52 +00:00
|
|
|
justified: jfRes.current_justified_checkpoint,
|
|
|
|
finalized: jfRes.finalized_checkpoint)
|
2022-07-06 10:33:02 +00:00
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#justification-and-finalization
|
2022-07-06 10:33:02 +00:00
|
|
|
proc process_justification_and_finalization*(
|
2023-05-10 02:31:23 +00:00
|
|
|
state: var (altair.BeaconState | bellatrix.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
capella.BeaconState | deneb.BeaconState | electra.BeaconState |
|
|
|
|
fulu.BeaconState),
|
2021-10-13 14:24:36 +00:00
|
|
|
balances: UnslashedParticipatingBalances,
|
2021-12-03 14:46:56 +00:00
|
|
|
flags: UpdateFlags = {}) =
|
2021-05-28 15:25:58 +00:00
|
|
|
# Initial FFG checkpoint values have a `0x00` stub for `root`.
|
|
|
|
# Skip FFG updates in the first two epochs to avoid corner cases that might
|
|
|
|
# result in modifying this stub.
|
|
|
|
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
|
|
|
return
|
2021-08-24 20:09:03 +00:00
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
let jfRes = weigh_justification_and_finalization(
|
2021-10-13 14:24:36 +00:00
|
|
|
state, balances.current_epoch,
|
|
|
|
balances.previous_epoch[TIMELY_TARGET_FLAG_INDEX],
|
|
|
|
balances.current_epoch_TIMELY_TARGET, flags)
|
2024-02-20 05:14:52 +00:00
|
|
|
assign(
|
|
|
|
state.previous_justified_checkpoint, jfRes.previous_justified_checkpoint)
|
|
|
|
assign(
|
|
|
|
state.current_justified_checkpoint, jfRes.current_justified_checkpoint)
|
|
|
|
assign(state.finalized_checkpoint, jfRes.finalized_checkpoint)
|
|
|
|
assign(state.justification_bits, jfRes.justification_bits)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2022-07-06 10:33:02 +00:00
|
|
|
proc compute_unrealized_finality*(
|
2022-12-08 16:21:53 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState): FinalityCheckpoints =
|
2022-07-06 10:33:02 +00:00
|
|
|
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
|
|
|
return FinalityCheckpoints(
|
|
|
|
justified: state.current_justified_checkpoint,
|
|
|
|
finalized: state.finalized_checkpoint)
|
|
|
|
|
|
|
|
let balances = get_unslashed_participating_balances(state)
|
|
|
|
|
|
|
|
var finalityState = state.toFinalityState()
|
2024-02-20 05:14:52 +00:00
|
|
|
let jfRes = weigh_justification_and_finalization(
|
2022-07-06 10:33:02 +00:00
|
|
|
finalityState, balances.current_epoch,
|
|
|
|
balances.previous_epoch[TIMELY_TARGET_FLAG_INDEX],
|
|
|
|
balances.current_epoch_TIMELY_TARGET)
|
|
|
|
FinalityCheckpoints(
|
2024-02-20 05:14:52 +00:00
|
|
|
justified: jfRes.current_justified_checkpoint,
|
|
|
|
finalized: jfRes.finalized_checkpoint)
|
2022-07-06 10:33:02 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#helpers
|
2021-05-28 15:25:58 +00:00
|
|
|
func get_base_reward_sqrt*(state: phase0.BeaconState, index: ValidatorIndex,
|
improve slot processing speeds (#1670)
about 40% better slot processing times (with LTO enabled) - these don't
do BLS but are used
heavily during replay (state transition = slot + block transition)
tests using a recent medalla state and advancing it 1000 slots:
```
./ncli slots --preState2:state-302271-3c1dbf19-c1f944bf.ssz --slot:1000
--postState2:xx.ssz
```
pre:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
39.236, 0.000, 39.236, 39.236, 1,
Load state from file
0.049, 0.002, 0.046, 0.063, 968,
Apply slot
256.504, 81.008, 213.471, 591.902, 32,
Apply epoch slot
28.597, 0.000, 28.597, 28.597, 1,
Save state to file
```
cast:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
37.079, 0.000, 37.079, 37.079, 1,
Load state from file
0.042, 0.002, 0.040, 0.090, 968,
Apply slot
215.552, 68.763, 180.155, 500.103, 32,
Apply epoch slot
25.106, 0.000, 25.106, 25.106, 1,
Save state to file
```
cast+rewards:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
40.049, 0.000, 40.049, 40.049, 1,
Load state from file
0.048, 0.001, 0.045, 0.060, 968,
Apply slot
164.981, 76.273, 142.099, 477.868, 32,
Apply epoch slot
28.498, 0.000, 28.498, 28.498, 1,
Save state to file
```
cast+rewards+shr
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
12.898, 0.000, 12.898, 12.898, 1,
Load state from file
0.039, 0.002, 0.038, 0.054, 968,
Apply slot
139.971, 68.797, 120.088, 428.844, 32,
Apply epoch slot
24.761, 0.000, 24.761, 24.761, 1,
Save state to file
```
2020-09-16 20:59:33 +00:00
|
|
|
total_balance_sqrt: auto): Gwei =
|
2019-11-15 22:37:39 +00:00
|
|
|
# Spec function recalculates total_balance every time, which creates an
|
|
|
|
# O(n^2) situation.
|
2022-05-30 13:30:42 +00:00
|
|
|
let effective_balance = state.validators[index].effective_balance
|
2019-06-28 13:44:44 +00:00
|
|
|
effective_balance * BASE_REWARD_FACTOR div
|
improve slot processing speeds (#1670)
about 40% better slot processing times (with LTO enabled) - these don't
do BLS but are used
heavily during replay (state transition = slot + block transition)
tests using a recent medalla state and advancing it 1000 slots:
```
./ncli slots --preState2:state-302271-3c1dbf19-c1f944bf.ssz --slot:1000
--postState2:xx.ssz
```
pre:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
39.236, 0.000, 39.236, 39.236, 1,
Load state from file
0.049, 0.002, 0.046, 0.063, 968,
Apply slot
256.504, 81.008, 213.471, 591.902, 32,
Apply epoch slot
28.597, 0.000, 28.597, 28.597, 1,
Save state to file
```
cast:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
37.079, 0.000, 37.079, 37.079, 1,
Load state from file
0.042, 0.002, 0.040, 0.090, 968,
Apply slot
215.552, 68.763, 180.155, 500.103, 32,
Apply epoch slot
25.106, 0.000, 25.106, 25.106, 1,
Save state to file
```
cast+rewards:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
40.049, 0.000, 40.049, 40.049, 1,
Load state from file
0.048, 0.001, 0.045, 0.060, 968,
Apply slot
164.981, 76.273, 142.099, 477.868, 32,
Apply epoch slot
28.498, 0.000, 28.498, 28.498, 1,
Save state to file
```
cast+rewards+shr
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
12.898, 0.000, 12.898, 12.898, 1,
Load state from file
0.039, 0.002, 0.038, 0.054, 968,
Apply slot
139.971, 68.797, 120.088, 428.844, 32,
Apply epoch slot
24.761, 0.000, 24.761, 24.761, 1,
Save state to file
```
2020-09-16 20:59:33 +00:00
|
|
|
total_balance_sqrt div BASE_REWARDS_PER_EPOCH
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2021-12-29 02:50:49 +00:00
|
|
|
func get_proposer_reward*(base_reward: Gwei): Gwei =
|
2020-07-07 16:52:12 +00:00
|
|
|
# Spec version recalculates get_total_active_balance(state) quadratically
|
2020-10-22 11:08:46 +00:00
|
|
|
base_reward div PROPOSER_REWARD_QUOTIENT
|
|
|
|
|
|
|
|
func is_in_inactivity_leak(finality_delay: uint64): bool =
|
|
|
|
finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
2020-06-08 18:41:50 +00:00
|
|
|
|
2021-12-29 02:50:49 +00:00
|
|
|
func get_finality_delay*(state: ForkyBeaconState): uint64 =
|
2020-06-08 18:41:50 +00:00
|
|
|
get_previous_epoch(state) - state.finalized_checkpoint.epoch
|
|
|
|
|
2024-03-19 13:22:07 +00:00
|
|
|
func get_attestation_component_reward*(
|
|
|
|
attesting_balance: Gwei,
|
|
|
|
total_balance: Gwei,
|
|
|
|
base_reward: Gwei,
|
|
|
|
finality_delay: uint64): Gwei =
|
2021-12-29 02:50:49 +00:00
|
|
|
if is_in_inactivity_leak(finality_delay):
|
|
|
|
# Since full base reward will be canceled out by inactivity penalty deltas,
|
|
|
|
# optimal participation receives full base reward compensation here.
|
|
|
|
base_reward
|
|
|
|
else:
|
|
|
|
let reward_numerator =
|
2024-03-19 13:22:07 +00:00
|
|
|
base_reward * (attesting_balance div EFFECTIVE_BALANCE_INCREMENT.Gwei)
|
|
|
|
reward_numerator div (total_balance div EFFECTIVE_BALANCE_INCREMENT.Gwei)
|
|
|
|
|
|
|
|
func get_attestation_component_delta(
|
|
|
|
is_unslashed_attester: bool,
|
|
|
|
attesting_balance: Gwei,
|
|
|
|
total_balance: Gwei,
|
|
|
|
base_reward: Gwei,
|
|
|
|
finality_delay: uint64): RewardDelta =
|
2020-06-08 18:41:50 +00:00
|
|
|
# Helper with shared logic for use by get source, target, and head deltas
|
|
|
|
# functions
|
2020-10-22 11:08:46 +00:00
|
|
|
if is_unslashed_attester:
|
2021-12-29 02:50:49 +00:00
|
|
|
RewardDelta(rewards: get_attestation_component_reward(
|
|
|
|
attesting_balance,
|
|
|
|
total_balance,
|
|
|
|
base_reward,
|
|
|
|
finality_delay))
|
2020-10-22 11:08:46 +00:00
|
|
|
else:
|
2021-05-07 11:36:21 +00:00
|
|
|
RewardDelta(penalties: base_reward)
|
2020-06-08 18:41:50 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#components-of-attestation-deltas
|
2024-03-19 13:22:07 +00:00
|
|
|
func get_source_delta*(
|
|
|
|
validator: RewardStatus,
|
|
|
|
base_reward: Gwei,
|
|
|
|
balances: TotalBalances,
|
|
|
|
finality_delay: uint64): RewardDelta =
|
2020-09-08 08:54:55 +00:00
|
|
|
## Return attester micro-rewards/penalties for source-vote for each validator.
|
2020-10-22 11:08:46 +00:00
|
|
|
get_attestation_component_delta(
|
2021-05-07 11:36:21 +00:00
|
|
|
validator.is_previous_epoch_attester.isSome() and
|
2021-05-28 15:25:58 +00:00
|
|
|
not (validator.flags.contains RewardFlags.isSlashed),
|
2021-11-25 12:20:36 +00:00
|
|
|
balances.previous_epoch_attesters,
|
|
|
|
balances.current_epoch,
|
2020-10-22 11:08:46 +00:00
|
|
|
base_reward,
|
|
|
|
finality_delay)
|
|
|
|
|
2024-03-19 13:22:07 +00:00
|
|
|
func get_target_delta*(
|
|
|
|
validator: RewardStatus,
|
|
|
|
base_reward: Gwei,
|
|
|
|
balances: TotalBalances,
|
|
|
|
finality_delay: uint64): RewardDelta =
|
2020-09-08 08:54:55 +00:00
|
|
|
## Return attester micro-rewards/penalties for target-vote for each validator.
|
2020-10-22 11:08:46 +00:00
|
|
|
get_attestation_component_delta(
|
2021-05-28 15:25:58 +00:00
|
|
|
validator.flags.contains(RewardFlags.isPreviousEpochTargetAttester) and
|
|
|
|
not (validator.flags.contains(RewardFlags.isSlashed)),
|
2021-11-25 12:20:36 +00:00
|
|
|
balances.previous_epoch_target_attesters,
|
|
|
|
balances.current_epoch,
|
2020-10-22 11:08:46 +00:00
|
|
|
base_reward,
|
|
|
|
finality_delay)
|
|
|
|
|
2024-03-19 13:22:07 +00:00
|
|
|
func get_head_delta*(
|
|
|
|
validator: RewardStatus,
|
|
|
|
base_reward: Gwei,
|
|
|
|
balances: TotalBalances,
|
|
|
|
finality_delay: uint64): RewardDelta =
|
2020-09-08 08:54:55 +00:00
|
|
|
## Return attester micro-rewards/penalties for head-vote for each validator.
|
2020-10-22 11:08:46 +00:00
|
|
|
get_attestation_component_delta(
|
2021-05-28 15:25:58 +00:00
|
|
|
validator.flags.contains(RewardFlags.isPreviousEpochHeadAttester) and
|
|
|
|
((not validator.flags.contains(RewardFlags.isSlashed))),
|
2021-11-25 12:20:36 +00:00
|
|
|
balances.previous_epoch_head_attesters,
|
|
|
|
balances.current_epoch,
|
2020-10-22 11:08:46 +00:00
|
|
|
base_reward,
|
|
|
|
finality_delay)
|
|
|
|
|
2024-03-19 13:22:07 +00:00
|
|
|
func get_inclusion_delay_delta*(
|
|
|
|
validator: RewardStatus,
|
|
|
|
base_reward: Gwei): (RewardDelta, Opt[(uint64, RewardDelta)]) =
|
2020-09-08 08:54:55 +00:00
|
|
|
## Return proposer and inclusion delay micro-rewards/penalties for each validator.
|
2021-05-28 15:25:58 +00:00
|
|
|
if validator.is_previous_epoch_attester.isSome() and ((not validator.flags.contains(RewardFlags.isSlashed))):
|
2020-10-22 11:08:46 +00:00
|
|
|
let
|
|
|
|
inclusion_info = validator.is_previous_epoch_attester.get()
|
|
|
|
proposer_reward = get_proposer_reward(base_reward)
|
2021-05-07 11:36:21 +00:00
|
|
|
proposer_delta = RewardDelta(rewards: proposer_reward)
|
2020-07-10 09:24:04 +00:00
|
|
|
|
2020-06-08 18:41:50 +00:00
|
|
|
let
|
2020-10-22 11:08:46 +00:00
|
|
|
max_attester_reward = base_reward - proposer_reward
|
2021-05-07 11:36:21 +00:00
|
|
|
delta = RewardDelta(rewards: max_attester_reward div inclusion_info.delay)
|
2020-10-22 11:08:46 +00:00
|
|
|
proposer_index = inclusion_info.proposer_index;
|
2023-01-11 12:29:21 +00:00
|
|
|
return (delta, Opt.some((proposer_index, proposer_delta)))
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2024-03-19 13:22:07 +00:00
|
|
|
func get_inactivity_penalty_delta*(
|
|
|
|
validator: RewardStatus,
|
|
|
|
base_reward: Gwei,
|
|
|
|
finality_delay: uint64): RewardDelta =
|
2020-10-22 11:08:46 +00:00
|
|
|
## Return inactivity reward/penalty deltas for each validator.
|
2021-05-07 11:36:21 +00:00
|
|
|
var delta: RewardDelta
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
if is_in_inactivity_leak(finality_delay):
|
|
|
|
# If validator is performing optimally this cancels all rewards for a neutral balance
|
|
|
|
delta.penalties +=
|
|
|
|
BASE_REWARDS_PER_EPOCH * base_reward - get_proposer_reward(base_reward)
|
|
|
|
|
|
|
|
# Additionally, all validators whose FFG target didn't match are penalized extra
|
|
|
|
# This condition is equivalent to this condition from the spec:
|
|
|
|
# `index not in get_unslashed_attesting_indices(state, matching_target_attestations)`
|
2021-05-28 15:25:58 +00:00
|
|
|
if (validator.flags.contains(RewardFlags.isSlashed)) or
|
|
|
|
((not validator.flags.contains(RewardFlags.isPreviousEpochTargetAttester))):
|
2021-05-07 11:36:21 +00:00
|
|
|
delta.penalties +=
|
|
|
|
validator.current_epoch_effective_balance * finality_delay div
|
|
|
|
INACTIVITY_PENALTY_QUOTIENT
|
2020-10-22 11:08:46 +00:00
|
|
|
|
|
|
|
delta
|
2020-06-08 18:41:50 +00:00
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#get_attestation_deltas
|
2023-05-10 02:31:23 +00:00
|
|
|
func get_attestation_deltas(
|
|
|
|
state: phase0.BeaconState, info: var phase0.EpochInfo) =
|
2021-05-07 11:36:21 +00:00
|
|
|
## Update rewards with attestation reward/penalty deltas for each validator.
|
2020-06-29 18:08:58 +00:00
|
|
|
let
|
2020-10-22 11:08:46 +00:00
|
|
|
finality_delay = get_finality_delay(state)
|
2021-11-25 12:20:36 +00:00
|
|
|
total_balance = info.balances.current_epoch
|
2024-03-19 13:22:07 +00:00
|
|
|
total_balance_sqrt = integer_squareroot(distinctBase(total_balance))
|
2020-10-22 11:08:46 +00:00
|
|
|
# Filter out ineligible validators. All sub-functions of the spec do this
|
|
|
|
# except for `get_inclusion_delay_deltas`. It's safe to do so here because
|
|
|
|
# any validator that is in the unslashed indices of the matching source
|
|
|
|
# attestations is active, and therefore eligible.
|
2021-11-25 12:20:36 +00:00
|
|
|
for index, validator in info.validators.mpairs():
|
2020-10-22 11:08:46 +00:00
|
|
|
if not is_eligible_validator(validator):
|
|
|
|
continue
|
|
|
|
|
|
|
|
let
|
|
|
|
base_reward = get_base_reward_sqrt(
|
|
|
|
state, index.ValidatorIndex, total_balance_sqrt)
|
improve slot processing speeds (#1670)
about 40% better slot processing times (with LTO enabled) - these don't
do BLS but are used
heavily during replay (state transition = slot + block transition)
tests using a recent medalla state and advancing it 1000 slots:
```
./ncli slots --preState2:state-302271-3c1dbf19-c1f944bf.ssz --slot:1000
--postState2:xx.ssz
```
pre:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
39.236, 0.000, 39.236, 39.236, 1,
Load state from file
0.049, 0.002, 0.046, 0.063, 968,
Apply slot
256.504, 81.008, 213.471, 591.902, 32,
Apply epoch slot
28.597, 0.000, 28.597, 28.597, 1,
Save state to file
```
cast:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
37.079, 0.000, 37.079, 37.079, 1,
Load state from file
0.042, 0.002, 0.040, 0.090, 968,
Apply slot
215.552, 68.763, 180.155, 500.103, 32,
Apply epoch slot
25.106, 0.000, 25.106, 25.106, 1,
Save state to file
```
cast+rewards:
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
40.049, 0.000, 40.049, 40.049, 1,
Load state from file
0.048, 0.001, 0.045, 0.060, 968,
Apply slot
164.981, 76.273, 142.099, 477.868, 32,
Apply epoch slot
28.498, 0.000, 28.498, 28.498, 1,
Save state to file
```
cast+rewards+shr
```
All time are ms
Average, StdDev, Min, Max, Samples,
Test
Validation is turned off meaning that no BLS operations are performed
12.898, 0.000, 12.898, 12.898, 1,
Load state from file
0.039, 0.002, 0.038, 0.054, 968,
Apply slot
139.971, 68.797, 120.088, 428.844, 32,
Apply epoch slot
24.761, 0.000, 24.761, 24.761, 1,
Save state to file
```
2020-09-16 20:59:33 +00:00
|
|
|
|
2020-10-22 11:08:46 +00:00
|
|
|
let
|
|
|
|
source_delta = get_source_delta(
|
2021-11-25 12:20:36 +00:00
|
|
|
validator, base_reward, info.balances, finality_delay)
|
2020-10-22 11:08:46 +00:00
|
|
|
target_delta = get_target_delta(
|
2021-11-25 12:20:36 +00:00
|
|
|
validator, base_reward, info.balances, finality_delay)
|
2020-10-22 11:08:46 +00:00
|
|
|
head_delta = get_head_delta(
|
2021-11-25 12:20:36 +00:00
|
|
|
validator, base_reward, info.balances, finality_delay)
|
2020-10-22 11:08:46 +00:00
|
|
|
(inclusion_delay_delta, proposer_delta) =
|
|
|
|
get_inclusion_delay_delta(validator, base_reward)
|
|
|
|
inactivity_delta = get_inactivity_penalty_delta(
|
|
|
|
validator, base_reward, finality_delay)
|
|
|
|
|
|
|
|
validator.delta.add source_delta
|
|
|
|
validator.delta.add target_delta
|
|
|
|
validator.delta.add head_delta
|
|
|
|
validator.delta.add inclusion_delay_delta
|
|
|
|
validator.delta.add inactivity_delta
|
|
|
|
|
|
|
|
if proposer_delta.isSome:
|
|
|
|
let proposer_index = proposer_delta.get()[0]
|
2021-11-25 12:20:36 +00:00
|
|
|
if proposer_index < info.validators.lenu64:
|
|
|
|
info.validators[proposer_index].delta.add(
|
2020-10-22 11:08:46 +00:00
|
|
|
proposer_delta.get()[1])
|
2020-06-08 18:41:50 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#get_base_reward
|
2021-12-29 02:50:49 +00:00
|
|
|
func get_base_reward_increment*(
|
2022-12-06 16:43:11 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2022-10-27 06:29:24 +00:00
|
|
|
index: ValidatorIndex, base_reward_per_increment: Gwei): Gwei =
|
2021-05-28 15:25:58 +00:00
|
|
|
## Return the base reward for the validator defined by ``index`` with respect
|
|
|
|
## to the current ``state``.
|
|
|
|
let increments =
|
2024-03-19 13:22:07 +00:00
|
|
|
state.validators[index].effective_balance div
|
|
|
|
EFFECTIVE_BALANCE_INCREMENT.Gwei
|
2021-10-13 14:24:36 +00:00
|
|
|
increments * base_reward_per_increment
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#get_flag_index_deltas
|
2022-10-27 06:29:24 +00:00
|
|
|
func get_flag_index_reward*(
|
2022-12-06 16:43:11 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2024-03-19 13:22:07 +00:00
|
|
|
base_reward: Gwei,
|
|
|
|
active_increments: uint64,
|
|
|
|
unslashed_participating_increments: uint64,
|
2022-10-27 06:29:24 +00:00
|
|
|
weight, finality_delay: uint64): Gwei =
|
2022-01-27 16:37:30 +00:00
|
|
|
if not is_in_inactivity_leak(finality_delay):
|
2021-12-29 02:50:49 +00:00
|
|
|
let reward_numerator =
|
|
|
|
base_reward * weight * unslashed_participating_increments
|
|
|
|
reward_numerator div (active_increments * WEIGHT_DENOMINATOR)
|
|
|
|
else:
|
|
|
|
0.Gwei
|
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_flag_index_deltas
|
2021-12-29 02:50:49 +00:00
|
|
|
func get_unslashed_participating_increment*(
|
2024-03-19 13:22:07 +00:00
|
|
|
info: altair.EpochInfo | bellatrix.BeaconState,
|
|
|
|
flag_index: TimelyFlag): uint64 =
|
|
|
|
info.balances.previous_epoch[flag_index] div EFFECTIVE_BALANCE_INCREMENT.Gwei
|
2021-12-29 02:50:49 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#get_flag_index_deltas
|
2023-05-10 02:31:23 +00:00
|
|
|
func get_active_increments*(
|
2024-03-19 13:22:07 +00:00
|
|
|
info: altair.EpochInfo | bellatrix.BeaconState): uint64 =
|
|
|
|
info.balances.current_epoch div EFFECTIVE_BALANCE_INCREMENT.Gwei
|
2021-12-29 02:50:49 +00:00
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_flag_index_deltas
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#modified-get_inactivity_penalty_deltas
|
2023-09-07 11:14:52 +00:00
|
|
|
# Combines get_flag_index_deltas() and get_inactivity_penalty_deltas()
|
2024-03-01 16:31:25 +00:00
|
|
|
template get_flag_and_inactivity_delta(
|
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2024-03-01 16:31:25 +00:00
|
|
|
base_reward_per_increment: Gwei, finality_delay: uint64,
|
2024-07-06 22:32:50 +00:00
|
|
|
previous_epoch: Epoch, active_increments: uint64,
|
2024-03-01 16:31:25 +00:00
|
|
|
penalty_denominator: uint64,
|
|
|
|
epoch_participation: ptr EpochParticipationFlags,
|
2024-07-06 22:32:50 +00:00
|
|
|
participating_increments: array[3, uint64], info: var altair.EpochInfo,
|
|
|
|
vidx: ValidatorIndex, inactivity_score: uint64
|
2024-03-19 13:22:07 +00:00
|
|
|
): (ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) =
|
2024-03-01 16:31:25 +00:00
|
|
|
let
|
|
|
|
base_reward = get_base_reward_increment(state, vidx, base_reward_per_increment)
|
|
|
|
pflags =
|
|
|
|
if is_active_validator(state.validators[vidx], previous_epoch) and
|
|
|
|
not state.validators[vidx].slashed:
|
|
|
|
epoch_participation[].item(vidx)
|
|
|
|
else:
|
|
|
|
0
|
|
|
|
|
|
|
|
if has_flag(pflags, TIMELY_SOURCE_FLAG_INDEX):
|
|
|
|
info.validators[vidx].flags.incl ParticipationFlag.timelySourceAttester
|
|
|
|
if has_flag(pflags, TIMELY_TARGET_FLAG_INDEX):
|
|
|
|
info.validators[vidx].flags.incl ParticipationFlag.timelyTargetAttester
|
|
|
|
if has_flag(pflags, TIMELY_HEAD_FLAG_INDEX):
|
|
|
|
info.validators[vidx].flags.incl ParticipationFlag.timelyHeadAttester
|
|
|
|
|
|
|
|
template reward(flag: untyped): untyped =
|
|
|
|
if has_flag(pflags, flag):
|
|
|
|
get_flag_index_reward(
|
|
|
|
state, base_reward, active_increments,
|
|
|
|
participating_increments[ord(flag)],
|
|
|
|
PARTICIPATION_FLAG_WEIGHTS[flag], finality_delay)
|
|
|
|
else:
|
2024-03-19 13:22:07 +00:00
|
|
|
0.Gwei
|
2024-03-01 16:31:25 +00:00
|
|
|
|
|
|
|
template penalty(flag: untyped): untyped =
|
|
|
|
if not has_flag(pflags, flag):
|
|
|
|
base_reward * PARTICIPATION_FLAG_WEIGHTS[flag] div WEIGHT_DENOMINATOR
|
|
|
|
else:
|
2024-03-19 13:22:07 +00:00
|
|
|
0.Gwei
|
2024-03-01 16:31:25 +00:00
|
|
|
|
|
|
|
let inactivity_penalty =
|
|
|
|
if has_flag(pflags, TIMELY_TARGET_FLAG_INDEX):
|
|
|
|
0.Gwei
|
|
|
|
else:
|
|
|
|
let penalty_numerator =
|
2024-07-06 22:32:50 +00:00
|
|
|
state.validators[vidx].effective_balance * inactivity_score
|
2024-03-01 16:31:25 +00:00
|
|
|
penalty_numerator div penalty_denominator
|
|
|
|
|
|
|
|
(vidx, reward(TIMELY_SOURCE_FLAG_INDEX),
|
|
|
|
reward(TIMELY_TARGET_FLAG_INDEX), reward(TIMELY_HEAD_FLAG_INDEX),
|
|
|
|
penalty(TIMELY_SOURCE_FLAG_INDEX), penalty(TIMELY_TARGET_FLAG_INDEX),
|
|
|
|
inactivity_penalty)
|
|
|
|
|
2023-09-08 16:42:18 +00:00
|
|
|
iterator get_flag_and_inactivity_deltas*(
|
2023-09-07 11:14:52 +00:00
|
|
|
cfg: RuntimeConfig,
|
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2023-09-07 11:14:52 +00:00
|
|
|
base_reward_per_increment: Gwei, info: var altair.EpochInfo,
|
2023-09-08 16:42:18 +00:00
|
|
|
finality_delay: uint64):
|
|
|
|
(ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) =
|
2023-09-07 11:14:52 +00:00
|
|
|
## Return the deltas for a given ``flag_index`` by scanning through the
|
|
|
|
## participation flags.
|
|
|
|
#
|
|
|
|
# This deviates from spec by processing all flags at once, so does not take a
|
|
|
|
# flag_index parameter. Fold get_inactivity_penalty_deltas loop into this one
|
|
|
|
# as well.
|
|
|
|
const INACTIVITY_PENALTY_QUOTIENT =
|
|
|
|
when state is altair.BeaconState:
|
|
|
|
INACTIVITY_PENALTY_QUOTIENT_ALTAIR
|
|
|
|
else:
|
|
|
|
INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
|
|
|
|
|
|
|
|
static: doAssert ord(high(TimelyFlag)) == 2
|
|
|
|
|
|
|
|
let
|
|
|
|
previous_epoch = get_previous_epoch(state)
|
|
|
|
active_increments = get_active_increments(info)
|
|
|
|
penalty_denominator =
|
|
|
|
cfg.INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT
|
|
|
|
epoch_participation =
|
|
|
|
if previous_epoch == get_current_epoch(state):
|
|
|
|
unsafeAddr state.current_epoch_participation
|
|
|
|
else:
|
|
|
|
unsafeAddr state.previous_epoch_participation
|
|
|
|
participating_increments = [
|
|
|
|
get_unslashed_participating_increment(info, TIMELY_SOURCE_FLAG_INDEX),
|
|
|
|
get_unslashed_participating_increment(info, TIMELY_TARGET_FLAG_INDEX),
|
|
|
|
get_unslashed_participating_increment(info, TIMELY_HEAD_FLAG_INDEX)]
|
|
|
|
|
|
|
|
for vidx in state.validators.vindices:
|
|
|
|
if not is_eligible_validator(info.validators[vidx]):
|
|
|
|
continue
|
|
|
|
|
2023-09-08 16:42:18 +00:00
|
|
|
# Yielding these as a structure with identifiable names rather than
|
|
|
|
# multiple-return-value style creates spurious nimZeroMem calls.
|
2024-03-01 16:31:25 +00:00
|
|
|
yield get_flag_and_inactivity_delta(
|
|
|
|
state, base_reward_per_increment, finality_delay, previous_epoch,
|
|
|
|
active_increments, penalty_denominator, epoch_participation,
|
2024-07-06 22:32:50 +00:00
|
|
|
participating_increments, info, vidx, state.inactivity_scores[vidx])
|
|
|
|
|
|
|
|
func get_flag_and_inactivity_delta_for_validator(
|
|
|
|
cfg: RuntimeConfig,
|
2024-11-13 03:29:14 +00:00
|
|
|
state: deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2024-07-06 22:32:50 +00:00
|
|
|
base_reward_per_increment: Gwei, info: var altair.EpochInfo,
|
|
|
|
finality_delay: uint64, vidx: ValidatorIndex, inactivity_score: Gwei):
|
|
|
|
Opt[(ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei)] =
|
|
|
|
## Return the deltas for a given ``flag_index`` by scanning through the
|
|
|
|
## participation flags.
|
|
|
|
const INACTIVITY_PENALTY_QUOTIENT =
|
|
|
|
when state is altair.BeaconState:
|
|
|
|
INACTIVITY_PENALTY_QUOTIENT_ALTAIR
|
|
|
|
else:
|
|
|
|
INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
|
|
|
|
|
|
|
|
static: doAssert ord(high(TimelyFlag)) == 2
|
|
|
|
|
|
|
|
let
|
|
|
|
previous_epoch = get_previous_epoch(state)
|
|
|
|
active_increments = get_active_increments(info)
|
|
|
|
penalty_denominator =
|
|
|
|
cfg.INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT
|
|
|
|
epoch_participation =
|
|
|
|
if previous_epoch == get_current_epoch(state):
|
|
|
|
unsafeAddr state.current_epoch_participation
|
|
|
|
else:
|
|
|
|
unsafeAddr state.previous_epoch_participation
|
|
|
|
participating_increments = [
|
|
|
|
get_unslashed_participating_increment(info, TIMELY_SOURCE_FLAG_INDEX),
|
|
|
|
get_unslashed_participating_increment(info, TIMELY_TARGET_FLAG_INDEX),
|
|
|
|
get_unslashed_participating_increment(info, TIMELY_HEAD_FLAG_INDEX)]
|
|
|
|
|
|
|
|
if not is_eligible_validator(info.validators[vidx]):
|
|
|
|
return Opt.none((ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei))
|
|
|
|
|
|
|
|
Opt.some get_flag_and_inactivity_delta(
|
|
|
|
state, base_reward_per_increment, finality_delay, previous_epoch,
|
|
|
|
active_increments, penalty_denominator, epoch_participation,
|
|
|
|
participating_increments, info, vidx, inactivity_score.uint64)
|
2021-11-05 16:49:03 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#rewards-and-penalties-1
|
2022-10-28 08:02:33 +00:00
|
|
|
func process_rewards_and_penalties*(
|
2021-12-03 14:46:56 +00:00
|
|
|
state: var phase0.BeaconState, info: var phase0.EpochInfo) =
|
2020-09-24 17:04:10 +00:00
|
|
|
# No rewards are applied at the end of `GENESIS_EPOCH` because rewards are
|
|
|
|
# for work done in the previous epoch
|
2021-11-25 12:20:36 +00:00
|
|
|
doAssert info.validators.len == state.validators.len
|
2020-10-22 11:08:46 +00:00
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
if get_current_epoch(state) == GENESIS_EPOCH:
|
|
|
|
return
|
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
get_attestation_deltas(state, info)
|
2019-10-01 14:40:41 +00:00
|
|
|
|
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
|
|
|
# Here almost all balances are updated (assuming most validators are active) -
|
|
|
|
# clearing the cache becomes a bottleneck if done item by item because of the
|
|
|
|
# recursive nature of cache clearing - instead, we clear the whole cache then
|
|
|
|
# update the raw list directly
|
|
|
|
state.balances.clearCache()
|
2021-11-25 12:20:36 +00:00
|
|
|
for idx, v in info.validators:
|
2022-05-30 13:30:42 +00:00
|
|
|
var balance = state.balances.item(idx)
|
2021-08-24 20:09:03 +00:00
|
|
|
increase_balance(balance, v.delta.rewards)
|
|
|
|
decrease_balance(balance, v.delta.penalties)
|
|
|
|
state.balances.asSeq()[idx] = balance
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#rewards-and-penalties
|
2022-10-28 08:02:33 +00:00
|
|
|
func process_rewards_and_penalties*(
|
2022-12-06 16:43:11 +00:00
|
|
|
cfg: RuntimeConfig,
|
|
|
|
state: var (altair.BeaconState | bellatrix.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
capella.BeaconState | deneb.BeaconState | electra.BeaconState |
|
|
|
|
fulu.BeaconState),
|
2023-05-10 02:31:23 +00:00
|
|
|
info: var altair.EpochInfo) =
|
2021-05-28 15:25:58 +00:00
|
|
|
if get_current_epoch(state) == GENESIS_EPOCH:
|
|
|
|
return
|
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
let
|
|
|
|
total_active_balance = info.balances.current_epoch
|
|
|
|
base_reward_per_increment = get_base_reward_per_increment(
|
|
|
|
total_active_balance)
|
2022-01-27 16:37:30 +00:00
|
|
|
finality_delay = get_finality_delay(state)
|
2021-08-20 14:41:32 +00:00
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
doAssert state.validators.len() == info.validators.len()
|
2023-09-08 16:42:18 +00:00
|
|
|
for validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2 in
|
|
|
|
get_flag_and_inactivity_deltas(
|
|
|
|
cfg, state, base_reward_per_increment, info, finality_delay):
|
2024-02-20 05:14:52 +00:00
|
|
|
# templatize this loop? or replicate a couple lines of code?
|
2023-09-08 16:42:18 +00:00
|
|
|
info.validators[validator_index].delta.rewards += reward0 + reward1 + reward2
|
|
|
|
info.validators[validator_index].delta.penalties += penalty0 + penalty1 + penalty2
|
2021-06-01 12:40:13 +00:00
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
# Here almost all balances are updated (assuming most validators are active) -
|
|
|
|
# clearing the cache becomes a bottleneck if done item by item because of the
|
|
|
|
# recursive nature of cache clearing - instead, we clear the whole cache then
|
|
|
|
# update the raw list directly
|
2021-08-24 20:09:03 +00:00
|
|
|
state.balances.clearCache()
|
2022-05-30 13:30:42 +00:00
|
|
|
for vidx in state.validators.vindices:
|
|
|
|
var balance = state.balances.item(vidx)
|
|
|
|
increase_balance(balance, info.validators[vidx].delta.rewards)
|
|
|
|
decrease_balance(balance, info.validators[vidx].delta.penalties)
|
|
|
|
state.balances.asSeq()[vidx] = balance
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2023-09-11 09:21:50 +00:00
|
|
|
from std/heapqueue import HeapQueue, `[]`, len, push, replace
|
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#registry-updates
|
2021-10-12 11:36:52 +00:00
|
|
|
func process_registry_updates*(
|
2024-04-24 12:28:47 +00:00
|
|
|
cfg: RuntimeConfig,
|
|
|
|
state: var (phase0.BeaconState | altair.BeaconState |
|
|
|
|
bellatrix.BeaconState | capella.BeaconState |
|
|
|
|
deneb.BeaconState),
|
|
|
|
cache: var StateCache): Result[void, cstring] =
|
2021-10-12 11:36:52 +00:00
|
|
|
## Process activation eligibility and ejections
|
|
|
|
|
|
|
|
# is_active_validator(...) is activation_epoch <= epoch < exit_epoch,
|
|
|
|
# and changes here to either activation_epoch or exit_epoch only take
|
|
|
|
# effect with a compute_activation_exit_epoch(...) delay of, based on
|
|
|
|
# the current epoch, 1 + MAX_SEED_LOOKAHEAD epochs ahead. Thus caches
|
|
|
|
# remain valid for this epoch through though this function along with
|
|
|
|
# the rest of the epoch transition.
|
2023-09-11 09:21:50 +00:00
|
|
|
#
|
|
|
|
# This implementation fuses the two loops over all validators in the
|
|
|
|
# spec code.
|
|
|
|
|
|
|
|
## Queue validators eligible for activation and not dequeued for activation
|
|
|
|
var activation_queue: HeapQueue[(uint64, uint32)]
|
2023-09-20 11:39:56 +00:00
|
|
|
let churn_limit =
|
2023-09-27 15:10:28 +00:00
|
|
|
when typeof(state).kind >= ConsensusFork.Deneb:
|
2023-09-20 11:39:56 +00:00
|
|
|
get_validator_activation_churn_limit(cfg, state, cache)
|
|
|
|
else:
|
|
|
|
get_validator_churn_limit(cfg, state, cache)
|
2024-04-02 12:18:40 +00:00
|
|
|
|
|
|
|
var maybe_exit_queue_info: Opt[ExitQueueInfo]
|
|
|
|
|
2022-05-23 23:39:08 +00:00
|
|
|
for vidx in state.validators.vindices:
|
2024-07-15 19:08:20 +00:00
|
|
|
if is_eligible_for_activation_queue(
|
|
|
|
typeof(state).kind, state.validators.item(vidx)):
|
2022-05-30 13:30:42 +00:00
|
|
|
state.validators.mitem(vidx).activation_eligibility_epoch =
|
2021-10-12 11:36:52 +00:00
|
|
|
get_current_epoch(state) + 1
|
|
|
|
|
2022-05-30 13:30:42 +00:00
|
|
|
if is_active_validator(state.validators.item(vidx), get_current_epoch(state)) and
|
2024-03-19 13:22:07 +00:00
|
|
|
state.validators.item(vidx).effective_balance <= cfg.EJECTION_BALANCE.Gwei:
|
2024-04-02 12:18:40 +00:00
|
|
|
# Typically, there will be no ejected validators, and even more rarely,
|
|
|
|
# more than one. Therefore, only calculate the information required for
|
|
|
|
# initiate_validator_exit if there actually is at least one.
|
|
|
|
let exit_queue_info = maybe_exit_queue_info.valueOr:
|
2024-04-03 01:45:57 +00:00
|
|
|
let initial_exit_queue_info = get_state_exit_queue_info(state)
|
2024-04-02 12:18:40 +00:00
|
|
|
maybe_exit_queue_info = Opt.some initial_exit_queue_info
|
|
|
|
initial_exit_queue_info
|
|
|
|
|
|
|
|
maybe_exit_queue_info = Opt.some (? initiate_validator_exit(
|
|
|
|
cfg, state, vidx, exit_queue_info, cache))
|
2021-10-12 11:36:52 +00:00
|
|
|
|
2022-05-30 13:30:42 +00:00
|
|
|
let validator = unsafeAddr state.validators.item(vidx)
|
2021-10-12 11:36:52 +00:00
|
|
|
if is_eligible_for_activation(state, validator[]):
|
2023-09-11 09:21:50 +00:00
|
|
|
let val_key =
|
|
|
|
(FAR_FUTURE_EPOCH - validator[].activation_eligibility_epoch,
|
|
|
|
high(distinctBase(ValidatorIndex)) - distinctBase(vidx))
|
|
|
|
if activation_queue.len.uint64 < churn_limit:
|
|
|
|
activation_queue.push val_key
|
|
|
|
elif val_key > activation_queue[0]:
|
|
|
|
discard activation_queue.replace val_key
|
2021-10-12 11:36:52 +00:00
|
|
|
|
2023-09-20 11:39:56 +00:00
|
|
|
## Dequeued validators for activation up to activation churn limit
|
|
|
|
## (without resetting activation epoch)
|
2023-09-11 09:21:50 +00:00
|
|
|
doAssert activation_queue.len.uint64 <= churn_limit
|
|
|
|
for i in 0 ..< activation_queue.len:
|
|
|
|
let (_, vidx_complement) = activation_queue[i]
|
|
|
|
state.validators.mitem(
|
|
|
|
high(distinctBase(ValidatorIndex)) - vidx_complement).activation_epoch =
|
|
|
|
compute_activation_exit_epoch(get_current_epoch(state))
|
2021-10-12 11:36:52 +00:00
|
|
|
|
2022-05-25 13:49:29 +00:00
|
|
|
ok()
|
|
|
|
|
2024-08-21 12:25:19 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.5/specs/electra/beacon-chain.md#modified-process_registry_updates
|
2024-04-24 12:28:47 +00:00
|
|
|
func process_registry_updates*(
|
2024-11-13 03:29:14 +00:00
|
|
|
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState),
|
|
|
|
cache: var StateCache): Result[void, cstring] =
|
2024-04-24 12:28:47 +00:00
|
|
|
# Process activation eligibility and ejections
|
|
|
|
for index in 0 ..< state.validators.len:
|
|
|
|
let validator = state.validators.item(index)
|
2024-07-15 19:08:20 +00:00
|
|
|
if is_eligible_for_activation_queue(typeof(state).kind, validator):
|
2024-04-24 12:28:47 +00:00
|
|
|
# Usually not too many at once, so do this individually
|
|
|
|
state.validators.mitem(index).activation_eligibility_epoch =
|
|
|
|
get_current_epoch(state) + 1
|
|
|
|
|
|
|
|
if is_active_validator(validator, get_current_epoch(state)) and
|
|
|
|
distinctBase(validator.effective_balance) <= cfg.EJECTION_BALANCE:
|
|
|
|
discard ? initiate_validator_exit(
|
|
|
|
cfg, state, ValidatorIndex(index), static(default(ExitQueueInfo)), cache)
|
|
|
|
|
|
|
|
# Activate all eligible validators
|
|
|
|
let activation_epoch =
|
|
|
|
compute_activation_exit_epoch(get_current_epoch(state))
|
|
|
|
for index in 0 ..< state.validators.len:
|
|
|
|
if is_eligible_for_activation(state, state.validators.item(index)):
|
|
|
|
state.validators.mitem(index).activation_epoch = activation_epoch
|
|
|
|
|
|
|
|
ok()
|
|
|
|
|
2024-02-22 02:42:57 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/phase0/beacon-chain.md#slashings
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#slashings
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#slashings
|
2021-12-29 02:50:49 +00:00
|
|
|
func get_adjusted_total_slashing_balance*(
|
|
|
|
state: ForkyBeaconState, total_balance: Gwei): Gwei =
|
2022-08-01 06:41:47 +00:00
|
|
|
const multiplier =
|
2021-12-29 02:50:49 +00:00
|
|
|
# tradeoff here about interleaving phase0/altair, but for these
|
|
|
|
# single-constant changes...
|
2022-01-17 12:58:33 +00:00
|
|
|
when state is phase0.BeaconState:
|
2021-12-29 02:50:49 +00:00
|
|
|
PROPORTIONAL_SLASHING_MULTIPLIER
|
|
|
|
elif state is altair.BeaconState:
|
|
|
|
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
|
2022-12-06 16:43:11 +00:00
|
|
|
elif state is bellatrix.BeaconState or state is capella.BeaconState or
|
2024-11-13 03:29:14 +00:00
|
|
|
state is deneb.BeaconState or state is electra.BeaconState or
|
|
|
|
state is fulu.BeaconState:
|
2022-10-27 06:29:24 +00:00
|
|
|
PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX
|
2021-12-29 02:50:49 +00:00
|
|
|
else:
|
2022-01-17 12:58:33 +00:00
|
|
|
{.fatal: "process_slashings: incorrect BeaconState type".}
|
|
|
|
min(sum(state.slashings.data) * multiplier, total_balance)
|
2021-12-29 02:50:49 +00:00
|
|
|
|
2024-02-22 02:42:57 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/phase0/beacon-chain.md#slashings
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#slashings
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#slashings
|
2024-10-07 10:30:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#modified-process_slashings
|
2021-12-29 02:50:49 +00:00
|
|
|
func slashing_penalty_applies*(validator: Validator, epoch: Epoch): bool =
|
2022-01-17 12:58:33 +00:00
|
|
|
validator.slashed and
|
|
|
|
epoch + EPOCHS_PER_SLASHINGS_VECTOR div 2 == validator.withdrawable_epoch
|
2021-12-29 02:50:49 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#slashings
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#slashings
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#slashings
|
2024-10-07 10:30:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#modified-process_slashings
|
2024-09-20 19:32:16 +00:00
|
|
|
func get_slashing_penalty*(
|
|
|
|
consensusFork: static ConsensusFork, validator: Validator,
|
|
|
|
adjusted_total_slashing_balance, total_balance: Gwei): Gwei =
|
2023-05-10 02:31:23 +00:00
|
|
|
# Factored out from penalty numerator to avoid uint64 overflow
|
2024-03-19 13:22:07 +00:00
|
|
|
const increment = EFFECTIVE_BALANCE_INCREMENT.Gwei
|
2024-09-20 19:32:16 +00:00
|
|
|
|
|
|
|
when consensusFork <= ConsensusFork.Deneb:
|
|
|
|
let penalty_numerator = validator.effective_balance div increment *
|
|
|
|
adjusted_total_slashing_balance
|
|
|
|
penalty_numerator div total_balance * increment
|
|
|
|
elif consensusFork == ConsensusFork.Electra:
|
|
|
|
let
|
|
|
|
effective_balance_increments = validator.effective_balance div increment
|
|
|
|
penalty_per_effective_balance_increment =
|
|
|
|
adjusted_total_slashing_balance div (total_balance div increment)
|
|
|
|
|
2024-11-13 03:29:14 +00:00
|
|
|
# [Modified in Electra:EIP7251]
|
|
|
|
penalty_per_effective_balance_increment * effective_balance_increments
|
|
|
|
elif consensusFork == ConsensusFork.Fulu:
|
|
|
|
let
|
|
|
|
effective_balance_increments = validator.effective_balance div increment
|
|
|
|
penalty_per_effective_balance_increment =
|
|
|
|
adjusted_total_slashing_balance div (total_balance div increment)
|
|
|
|
|
2024-09-20 19:32:16 +00:00
|
|
|
# [Modified in Electra:EIP7251]
|
|
|
|
penalty_per_effective_balance_increment * effective_balance_increments
|
|
|
|
else:
|
|
|
|
static: doAssert false
|
2021-12-29 02:50:49 +00:00
|
|
|
|
2024-02-22 02:42:57 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/phase0/beacon-chain.md#slashings
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#slashings
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/bellatrix/beacon-chain.md#slashings
|
2024-10-07 10:30:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#modified-process_slashings
|
2024-07-06 22:32:50 +00:00
|
|
|
func get_slashing(
|
|
|
|
state: ForkyBeaconState, total_balance: Gwei, vidx: ValidatorIndex): Gwei =
|
|
|
|
# For efficiency reasons, it doesn't make sense to have process_slashings use
|
|
|
|
# this per-validator index version, but keep them parallel otherwise.
|
|
|
|
let
|
|
|
|
epoch = get_current_epoch(state)
|
|
|
|
adjusted_total_slashing_balance = get_adjusted_total_slashing_balance(
|
|
|
|
state, total_balance)
|
|
|
|
|
|
|
|
let validator = unsafeAddr state.validators.item(vidx)
|
|
|
|
if slashing_penalty_applies(validator[], epoch):
|
|
|
|
get_slashing_penalty(
|
2024-09-20 19:32:16 +00:00
|
|
|
typeof(state).kind, validator[], adjusted_total_slashing_balance,
|
|
|
|
total_balance)
|
2024-07-06 22:32:50 +00:00
|
|
|
else:
|
|
|
|
0.Gwei
|
|
|
|
|
2021-12-03 14:46:56 +00:00
|
|
|
func process_slashings*(state: var ForkyBeaconState, total_balance: Gwei) =
|
2019-06-28 13:44:44 +00:00
|
|
|
let
|
More 0.8.0 updates (#311)
* replace BeaconState.finalized_{epoch,root} with BeaconState.finalized_checkpoint; rename get_delayed_activation_exit_epoch(...) to compute_activation_exit_epoch(...) and mark as 0.8.0; update get_churn_limit(...)/get_validator_churn_limit(...) to 0.8.0; update process_registry_updates(...) to 0.8.0
* update process_crosslinks(...) to 0.8.0; mark compute_start_slot_of_epoch(...) and get_committee_count(...) as 0.8.0
* mark Fork, is_slashable_validator(...), and get_beacon_proposer_index(...) as 0.8.0
* rename LATEST_SLASHED_EXIT_LENGTH to EPOCHS_PER_SLASHINGS_VECTOR; update process_slashings(...) to 0.8.0; remove pointless type conversion warning in get_previous_epoch(...)
* convert remaining references to finalized_epoch to finalized_checkpoint.epoch
* update slash_validator(...) to 0.8.0; mark inital value, Gwei, and time constants as 0.8.0; mark hash(...) and processBlockHeader(...) as 0.8.0
* rename WHISTLEBLOWING_REWARD_QUOTIENT to WHISTLEBLOWER_REWARD_QUOTIENT; rename LATEST_ACTIVE_INDEX_ROOTS_LENGTH to EPOCHS_PER_HISTORICAL_VECTOR (randao will also get merged into this); remove get_active_index_root(...); mark time parameter, signature domain types, and max operations per block constants as 0.8.0; update rewards and penalties constants to 0.8.0
* update is_valid_indexed_attestation(...) to 0.8.0; mark process_slot(...) as 0.8.0
* replace BeaconState.{current,previous}_justified_{epoch,root} with BeaconState.{current,previous}_justified_checkpoint
2019-07-05 08:30:05 +00:00
|
|
|
epoch = get_current_epoch(state)
|
2021-12-29 02:50:49 +00:00
|
|
|
adjusted_total_slashing_balance = get_adjusted_total_slashing_balance(
|
|
|
|
state, total_balance)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2022-05-23 23:39:08 +00:00
|
|
|
for vidx in state.validators.vindices:
|
2022-05-30 13:30:42 +00:00
|
|
|
let validator = unsafeAddr state.validators.item(vidx)
|
2021-12-29 02:50:49 +00:00
|
|
|
if slashing_penalty_applies(validator[], epoch):
|
2022-05-30 13:30:42 +00:00
|
|
|
let penalty = get_slashing_penalty(
|
2024-09-20 19:32:16 +00:00
|
|
|
typeof(state).kind, validator[], adjusted_total_slashing_balance,
|
|
|
|
total_balance)
|
2022-05-23 23:39:08 +00:00
|
|
|
decrease_balance(state, vidx, penalty)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#eth1-data-votes-updates
|
2021-12-03 14:46:56 +00:00
|
|
|
func process_eth1_data_reset*(state: var ForkyBeaconState) =
|
2021-02-14 19:31:01 +00:00
|
|
|
let next_epoch = get_current_epoch(state) + 1
|
2019-06-28 13:44:44 +00:00
|
|
|
|
|
|
|
# Reset eth1 data votes
|
2020-03-14 21:54:45 +00:00
|
|
|
if next_epoch mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0:
|
2020-05-27 11:36:02 +00:00
|
|
|
state.eth1_data_votes = default(type state.eth1_data_votes)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-04-18 01:00:04 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#effective-balances-updates
|
2024-04-28 03:33:44 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.1/specs/electra/beacon-chain.md#updated-process_effective_balance_updates
|
2024-08-06 11:33:16 +00:00
|
|
|
func process_effective_balance_updates*(state: var ForkyBeaconState) =
|
2024-04-28 03:33:44 +00:00
|
|
|
# Update effective balances with hysteresis
|
|
|
|
for vidx in state.validators.vindices:
|
|
|
|
let
|
|
|
|
balance = state.balances.item(vidx)
|
|
|
|
effective_balance = state.validators.item(vidx).effective_balance
|
2024-08-06 11:33:16 +00:00
|
|
|
|
2024-04-28 03:33:44 +00:00
|
|
|
if effective_balance_might_update(balance, effective_balance):
|
2024-08-06 11:33:16 +00:00
|
|
|
let new_effective_balance = get_effective_balance_update(
|
|
|
|
typeof(state).kind, balance, effective_balance, vidx.distinctBase)
|
2024-04-28 03:33:44 +00:00
|
|
|
# Protect against unnecessary cache invalidation
|
|
|
|
if new_effective_balance != effective_balance:
|
|
|
|
state.validators.mitem(vidx).effective_balance = new_effective_balance
|
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#slashings-balances-updates
|
2021-12-03 14:46:56 +00:00
|
|
|
func process_slashings_reset*(state: var ForkyBeaconState) =
|
2021-02-14 19:31:01 +00:00
|
|
|
let next_epoch = get_current_epoch(state) + 1
|
|
|
|
|
2019-07-10 12:23:02 +00:00
|
|
|
# Reset slashings
|
2020-06-12 16:43:20 +00:00
|
|
|
state.slashings[int(next_epoch mod EPOCHS_PER_SLASHINGS_VECTOR)] = 0.Gwei
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#randao-mixes-updates
|
2021-12-03 14:46:56 +00:00
|
|
|
func process_randao_mixes_reset*(state: var ForkyBeaconState) =
|
2021-02-14 19:31:01 +00:00
|
|
|
let
|
|
|
|
current_epoch = get_current_epoch(state)
|
|
|
|
next_epoch = current_epoch + 1
|
|
|
|
|
2019-06-28 13:44:44 +00:00
|
|
|
# Set randao mix
|
2019-09-04 13:57:18 +00:00
|
|
|
state.randao_mixes[next_epoch mod EPOCHS_PER_HISTORICAL_VECTOR] =
|
2019-06-28 13:44:44 +00:00
|
|
|
get_randao_mix(state, current_epoch)
|
|
|
|
|
2022-05-10 00:28:46 +00:00
|
|
|
func compute_historical_root*(state: var ForkyBeaconState): Eth2Digest =
|
|
|
|
# Equivalent to hash_tree_root(foo: HistoricalBatch), but without using
|
|
|
|
# significant additional stack or heap.
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#historicalbatch
|
2022-05-10 00:28:46 +00:00
|
|
|
# In response to https://github.com/status-im/nimbus-eth2/issues/921
|
|
|
|
hash_tree_root([
|
|
|
|
hash_tree_root(state.block_roots), hash_tree_root(state.state_roots)])
|
|
|
|
|
2024-01-20 11:19:47 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#historical-roots-updates
|
2021-12-03 14:46:56 +00:00
|
|
|
func process_historical_roots_update*(state: var ForkyBeaconState) =
|
2021-10-12 10:17:37 +00:00
|
|
|
## Set historical root accumulator
|
2021-02-14 19:31:01 +00:00
|
|
|
let next_epoch = get_current_epoch(state) + 1
|
|
|
|
|
2020-07-13 14:44:58 +00:00
|
|
|
if next_epoch mod (SLOTS_PER_HISTORICAL_ROOT div SLOTS_PER_EPOCH) == 0:
|
2020-04-23 11:39:38 +00:00
|
|
|
# Equivalent to hash_tree_root(foo: HistoricalBatch), but without using
|
|
|
|
# significant additional stack or heap.
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#historicalbatch
|
2020-10-08 19:02:05 +00:00
|
|
|
# In response to https://github.com/status-im/nimbus-eth2/issues/921
|
2022-05-10 00:28:46 +00:00
|
|
|
if not state.historical_roots.add state.compute_historical_root():
|
2021-04-08 10:11:04 +00:00
|
|
|
raiseAssert "no more room for historical roots, so long and thanks for the fish!"
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#participation-records-rotation
|
2021-12-03 14:46:56 +00:00
|
|
|
func process_participation_record_updates*(state: var phase0.BeaconState) =
|
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
|
|
|
# Rotate current/previous epoch attestations - using swap avoids copying all
|
|
|
|
# elements using a slow genericSeqAssign
|
|
|
|
state.previous_epoch_attestations.clear()
|
|
|
|
swap(state.previous_epoch_attestations, state.current_epoch_attestations)
|
2019-06-28 13:44:44 +00:00
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#participation-flags-updates
|
2022-10-27 06:29:24 +00:00
|
|
|
func process_participation_flag_updates*(
|
2023-02-23 18:06:57 +00:00
|
|
|
state: var (altair.BeaconState | bellatrix.BeaconState |
|
2024-02-26 02:38:21 +00:00
|
|
|
capella.BeaconState | deneb.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
electra.BeaconState | fulu.BeaconState)) =
|
2021-05-28 15:25:58 +00:00
|
|
|
state.previous_epoch_participation = state.current_epoch_participation
|
|
|
|
|
2021-06-24 18:34:08 +00:00
|
|
|
const zero = 0.ParticipationFlags
|
|
|
|
for i in 0 ..< state.current_epoch_participation.len:
|
2022-12-19 12:01:49 +00:00
|
|
|
asList(state.current_epoch_participation)[i] = zero
|
2021-06-24 18:34:08 +00:00
|
|
|
|
|
|
|
# Shouldn't be wasted zeroing, because state.current_epoch_participation only
|
|
|
|
# grows. New elements are automatically initialized to 0, as required.
|
2022-12-19 12:01:49 +00:00
|
|
|
doAssert state.current_epoch_participation.asList.setLen(state.validators.len)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#sync-committee-updates
|
2022-02-17 11:53:55 +00:00
|
|
|
func process_sync_committee_updates*(
|
2022-12-06 16:43:11 +00:00
|
|
|
state: var (altair.BeaconState | bellatrix.BeaconState |
|
2024-02-26 02:38:21 +00:00
|
|
|
capella.BeaconState | deneb.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
electra.BeaconState | fulu.BeaconState)) =
|
2021-05-28 15:25:58 +00:00
|
|
|
let next_epoch = get_current_epoch(state) + 1
|
2022-01-11 10:01:54 +00:00
|
|
|
if next_epoch.is_sync_committee_period():
|
2021-05-28 15:25:58 +00:00
|
|
|
state.current_sync_committee = state.next_sync_committee
|
|
|
|
state.next_sync_committee = get_next_sync_committee(state)
|
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#inactivity-scores
|
2024-02-20 05:14:52 +00:00
|
|
|
template compute_inactivity_update(
|
2024-03-17 12:32:30 +00:00
|
|
|
cfg: RuntimeConfig,
|
2024-02-20 05:14:52 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState,
|
2024-03-17 12:32:30 +00:00
|
|
|
info: altair.EpochInfo,
|
2024-03-19 13:22:07 +00:00
|
|
|
pre_inactivity_score: uint64): uint64 =
|
2024-02-20 05:14:52 +00:00
|
|
|
let previous_epoch = get_previous_epoch(state) # get_eligible_validator_indices()
|
|
|
|
|
|
|
|
# Increase the inactivity score of inactive validators
|
|
|
|
var inactivity_score = pre_inactivity_score
|
|
|
|
# TODO activeness already checked; remove redundant checks between
|
|
|
|
# is_active_validator and is_unslashed_participating_index
|
|
|
|
if is_unslashed_participating_index(
|
2024-07-06 22:32:50 +00:00
|
|
|
state, TIMELY_TARGET_FLAG_INDEX, previous_epoch, index):
|
2024-02-20 05:14:52 +00:00
|
|
|
inactivity_score -= min(1'u64, inactivity_score)
|
|
|
|
else:
|
|
|
|
inactivity_score += cfg.INACTIVITY_SCORE_BIAS
|
|
|
|
# Decrease the inactivity score of all eligible validators during a
|
|
|
|
# leak-free epoch
|
|
|
|
if not_in_inactivity_leak:
|
2024-03-17 12:32:30 +00:00
|
|
|
inactivity_score -=
|
|
|
|
min(cfg.INACTIVITY_SCORE_RECOVERY_RATE, inactivity_score)
|
2024-02-20 05:14:52 +00:00
|
|
|
inactivity_score
|
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#inactivity-scores
|
2021-10-13 14:24:36 +00:00
|
|
|
func process_inactivity_updates*(
|
2022-10-27 06:29:24 +00:00
|
|
|
cfg: RuntimeConfig,
|
2023-02-23 18:06:57 +00:00
|
|
|
state: var (altair.BeaconState | bellatrix.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
capella.BeaconState | deneb.BeaconState | electra.BeaconState |
|
|
|
|
fulu.BeaconState),
|
2021-10-13 14:24:36 +00:00
|
|
|
info: altair.EpochInfo) =
|
2021-05-28 15:25:58 +00:00
|
|
|
# Score updates based on previous epoch participation, skip genesis epoch
|
|
|
|
if get_current_epoch(state) == GENESIS_EPOCH:
|
|
|
|
return
|
|
|
|
|
2021-06-21 08:35:24 +00:00
|
|
|
let
|
2022-01-27 16:37:30 +00:00
|
|
|
finality_delay = get_finality_delay(state)
|
|
|
|
not_in_inactivity_leak = not is_in_inactivity_leak(finality_delay)
|
2021-08-25 14:43:00 +00:00
|
|
|
|
2021-05-28 15:25:58 +00:00
|
|
|
for index in 0'u64 ..< state.validators.lenu64:
|
2024-03-01 16:31:25 +00:00
|
|
|
if not is_eligible_validator(info.validators[index]):
|
|
|
|
continue
|
|
|
|
|
2024-02-20 05:14:52 +00:00
|
|
|
let
|
|
|
|
pre_inactivity_score = state.inactivity_scores.asSeq()[index]
|
2024-07-06 22:32:50 +00:00
|
|
|
index = index.ValidatorIndex # intentional shadowing
|
2024-02-20 05:14:52 +00:00
|
|
|
inactivity_score =
|
2024-03-17 12:32:30 +00:00
|
|
|
compute_inactivity_update(cfg, state, info, pre_inactivity_score)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
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
|
|
|
# Most inactivity scores remain at 0 - avoid invalidating cache
|
|
|
|
if pre_inactivity_score != inactivity_score:
|
|
|
|
state.inactivity_scores[index] = inactivity_score
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-06-22 05:28:19 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/capella/beacon-chain.md#historical-summaries-updates
|
2023-01-09 14:15:43 +00:00
|
|
|
func process_historical_summaries_update*(
|
2024-11-13 03:29:14 +00:00
|
|
|
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState |
|
|
|
|
fulu.BeaconState)):
|
2023-01-09 14:15:43 +00:00
|
|
|
Result[void, cstring] =
|
|
|
|
# Set historical block root accumulator.
|
|
|
|
let next_epoch = get_current_epoch(state) + 1
|
|
|
|
if next_epoch mod (SLOTS_PER_HISTORICAL_ROOT div SLOTS_PER_EPOCH) == 0:
|
|
|
|
let historical_summary = HistoricalSummary(
|
|
|
|
block_summary_root: hash_tree_root(state.block_roots),
|
|
|
|
state_summary_root: hash_tree_root(state.state_roots),
|
|
|
|
)
|
|
|
|
if not state.historical_summaries.add(historical_summary):
|
|
|
|
return err("process_historical_summaries_update: state.historical_summaries full")
|
|
|
|
|
|
|
|
ok()
|
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
from "."/signatures import verify_deposit_signature
|
|
|
|
from ".."/validator_bucket_sort import
|
|
|
|
BucketSortedValidators, add, findValidatorIndex, sortValidatorBuckets
|
|
|
|
|
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#new-apply_pending_deposit
|
|
|
|
func apply_pending_deposit(
|
2024-11-13 03:29:14 +00:00
|
|
|
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState),
|
|
|
|
deposit: PendingDeposit, validator_index: Opt[ValidatorIndex]):
|
|
|
|
Result[void, cstring] =
|
2024-10-06 11:15:56 +00:00
|
|
|
## Applies ``deposit`` to the ``state``.
|
|
|
|
if validator_index.isNone:
|
|
|
|
# Verify the deposit signature (proof of possession) which is not checked by
|
|
|
|
# the deposit contract
|
|
|
|
let deposit_data = DepositData(
|
|
|
|
pubkey: deposit.pubkey,
|
|
|
|
withdrawal_credentials: deposit.withdrawal_credentials,
|
|
|
|
amount: deposit.amount, signature: deposit.signature)
|
|
|
|
if verify_deposit_signature(cfg, deposit_data):
|
|
|
|
? add_validator_to_registry(state, deposit_data, deposit_data.amount)
|
|
|
|
else:
|
|
|
|
# Increase balance
|
|
|
|
increase_balance(state, validator_index.get, deposit.amount)
|
|
|
|
|
|
|
|
ok()
|
|
|
|
|
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#new-process_pending_deposits
|
|
|
|
func process_pending_deposits*(
|
2024-11-13 03:29:14 +00:00
|
|
|
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState) ,
|
2024-05-23 21:51:09 +00:00
|
|
|
cache: var StateCache): Result[void, cstring] =
|
2024-08-09 13:02:04 +00:00
|
|
|
let
|
|
|
|
next_epoch = get_current_epoch(state) + 1
|
|
|
|
available_for_processing = state.deposit_balance_to_consume +
|
|
|
|
get_activation_exit_churn_limit(cfg, state, cache)
|
2024-04-24 12:28:47 +00:00
|
|
|
var
|
|
|
|
processed_amount = 0.Gwei
|
2024-06-15 22:15:27 +00:00
|
|
|
next_deposit_index = 0
|
2024-10-06 11:15:56 +00:00
|
|
|
deposits_to_postpone: seq[PendingDeposit]
|
|
|
|
is_churn_limit_reached = false
|
|
|
|
bsv: ref BucketSortedValidators # initialized when required
|
|
|
|
let finalized_slot = start_slot(state.finalized_checkpoint.epoch)
|
|
|
|
|
|
|
|
for deposit in state.pending_deposits:
|
|
|
|
# Do not process deposit requests if Eth1 bridge deposits are not yet applied.
|
|
|
|
if deposit.slot > GENESIS_SLOT and # Is deposit request
|
|
|
|
# There are pending Eth1 bridge deposits
|
|
|
|
state.eth1_deposit_index < state.deposit_requests_start_index:
|
|
|
|
break
|
2024-04-24 12:28:47 +00:00
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# Check if deposit has been finalized, otherwise, stop processing.
|
|
|
|
if deposit.slot > finalized_slot:
|
|
|
|
break
|
2024-06-15 22:15:27 +00:00
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# Check if number of processed deposits has not reached the limit,
|
|
|
|
# otherwise, stop processing.
|
|
|
|
if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH:
|
|
|
|
break
|
2024-06-15 22:15:27 +00:00
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# Don't initialize this unless it's going to be used
|
|
|
|
if bsv.isNil:
|
|
|
|
bsv = sortValidatorBuckets(state.validators.asSeq)
|
|
|
|
|
|
|
|
# Read validator state
|
|
|
|
var
|
|
|
|
is_validator_exited = false
|
|
|
|
is_validator_withdrawn = false
|
|
|
|
let index =
|
|
|
|
findValidatorIndex(state.validators.asSeq, bsv[], deposit.pubkey)
|
|
|
|
if index.isOk:
|
|
|
|
let validator = state.validators.item(index.get)
|
|
|
|
is_validator_exited = validator.exit_epoch < FAR_FUTURE_EPOCH
|
|
|
|
is_validator_withdrawn = validator.withdrawable_epoch < next_epoch
|
|
|
|
|
|
|
|
if is_validator_withdrawn:
|
|
|
|
# Deposited balance will never become active. Increase balance but do
|
|
|
|
# not consume churn
|
|
|
|
|
|
|
|
# can't fail because it's not adding a validator, so only increase_balance
|
|
|
|
discard apply_pending_deposit(cfg, state, deposit, index)
|
|
|
|
elif is_validator_exited:
|
|
|
|
# Validator is exiting, postpone the deposit until after withdrawable
|
|
|
|
# epoch
|
|
|
|
deposits_to_postpone.add(deposit)
|
2024-06-15 22:15:27 +00:00
|
|
|
else:
|
2024-10-06 11:15:56 +00:00
|
|
|
# Check if deposit fits in the churn, otherwise, do no more deposit
|
|
|
|
# processing in this epoch.
|
|
|
|
is_churn_limit_reached =
|
|
|
|
processed_amount + deposit.amount > available_for_processing
|
|
|
|
if is_churn_limit_reached:
|
2024-06-15 22:15:27 +00:00
|
|
|
break
|
2024-10-06 11:15:56 +00:00
|
|
|
|
|
|
|
# Consume churn and apply deposit.
|
|
|
|
processed_amount += deposit.amount
|
|
|
|
|
|
|
|
# Can only fail due to add_validator_to_registry
|
|
|
|
if apply_pending_deposit(cfg, state, deposit, index).isOk:
|
|
|
|
if index.isNone: # this will have added a new validator
|
|
|
|
let last_validator_index = state.validators.len - 1
|
|
|
|
if last_validator_index >= 0 and
|
|
|
|
last_validator_index.int64 <= static(high(ValidatorIndex).int64):
|
|
|
|
bsv[].add(last_validator_index.ValidatorIndex)
|
2024-06-15 22:15:27 +00:00
|
|
|
|
|
|
|
# Regardless of how the deposit was handled, we move on in the queue.
|
|
|
|
next_deposit_index += 1
|
2024-04-24 12:28:47 +00:00
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
state.pending_deposits =
|
|
|
|
HashList[PendingDeposit, Limit PENDING_DEPOSITS_LIMIT].init(
|
|
|
|
state.pending_deposits.asSeq[next_deposit_index..^1] &
|
|
|
|
deposits_to_postpone)
|
2024-04-24 12:28:47 +00:00
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# Accumulate churn only if the churn limit has been hit.
|
|
|
|
if is_churn_limit_reached:
|
2024-04-24 12:28:47 +00:00
|
|
|
state.deposit_balance_to_consume =
|
|
|
|
available_for_processing - processed_amount
|
2024-10-06 11:15:56 +00:00
|
|
|
else:
|
|
|
|
state.deposit_balance_to_consume = Gwei(0)
|
2024-06-15 22:15:27 +00:00
|
|
|
|
2024-05-23 21:51:09 +00:00
|
|
|
ok()
|
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.7/specs/electra/beacon-chain.md#new-process_pending_consolidations
|
2024-05-23 21:51:09 +00:00
|
|
|
func process_pending_consolidations*(
|
2024-11-13 03:29:14 +00:00
|
|
|
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState) ):
|
2024-05-23 21:51:09 +00:00
|
|
|
Result[void, cstring] =
|
2024-08-09 13:02:04 +00:00
|
|
|
let next_epoch = get_current_epoch(state) + 1
|
2024-04-24 12:28:47 +00:00
|
|
|
var next_pending_consolidation = 0
|
|
|
|
for pending_consolidation in state.pending_consolidations:
|
|
|
|
let source_validator =
|
|
|
|
state.validators.item(pending_consolidation.source_index)
|
|
|
|
if source_validator.slashed:
|
|
|
|
next_pending_consolidation += 1
|
|
|
|
continue
|
2024-08-09 13:02:04 +00:00
|
|
|
if source_validator.withdrawable_epoch > next_epoch:
|
2024-04-24 12:28:47 +00:00
|
|
|
break
|
|
|
|
|
2024-05-23 21:51:09 +00:00
|
|
|
let
|
|
|
|
source_validator_index = ValidatorIndex.init(
|
|
|
|
pending_consolidation.source_index).valueOr:
|
|
|
|
return err("process_pending_consolidations: source index out of range")
|
|
|
|
target_validator_index = ValidatorIndex.init(
|
|
|
|
pending_consolidation.target_index).valueOr:
|
|
|
|
return err("process_pending_consolidations: target index out of range")
|
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# Calculate the consolidated balance
|
|
|
|
let
|
|
|
|
max_effective_balance = get_max_effective_balance(source_validator)
|
|
|
|
source_effective_balance = min(
|
|
|
|
state.balances.item(pending_consolidation.source_index),
|
|
|
|
max_effective_balance)
|
2024-04-24 12:28:47 +00:00
|
|
|
|
|
|
|
# Move active balance to target. Excess balance is withdrawable.
|
2024-10-06 11:15:56 +00:00
|
|
|
decrease_balance(state, source_validator_index, source_effective_balance)
|
|
|
|
increase_balance(state, target_validator_index, source_effective_balance)
|
|
|
|
next_pending_consolidation += 1
|
2024-04-24 12:28:47 +00:00
|
|
|
|
|
|
|
state.pending_consolidations =
|
|
|
|
HashList[PendingConsolidation, Limit PENDING_CONSOLIDATIONS_LIMIT].init(
|
|
|
|
state.pending_consolidations.asSeq[next_pending_consolidation..^1])
|
|
|
|
|
2024-05-23 21:51:09 +00:00
|
|
|
ok()
|
|
|
|
|
2024-04-17 03:51:16 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#epoch-processing
|
2021-05-05 06:54:21 +00:00
|
|
|
proc process_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: RuntimeConfig, state: var phase0.BeaconState, flags: UpdateFlags,
|
2022-05-25 13:49:29 +00:00
|
|
|
cache: var StateCache, info: var phase0.EpochInfo): Result[void, cstring] =
|
2023-05-10 02:31:23 +00:00
|
|
|
let epoch = get_current_epoch(state)
|
2022-07-06 10:33:02 +00:00
|
|
|
info.init(state)
|
2021-10-13 14:24:36 +00:00
|
|
|
info.process_attestations(state, cache)
|
2019-08-14 08:56:32 +00:00
|
|
|
|
2021-11-25 12:20:36 +00:00
|
|
|
process_justification_and_finalization(state, info.balances, flags)
|
2020-05-09 12:43:15 +00:00
|
|
|
|
|
|
|
# state.slot hasn't been incremented yet.
|
2023-05-10 02:31:23 +00:00
|
|
|
if strictVerification in flags and epoch >= 2:
|
|
|
|
doAssert state.current_justified_checkpoint.epoch + 2 >= epoch
|
2020-07-28 17:35:32 +00:00
|
|
|
|
2023-05-10 02:31:23 +00:00
|
|
|
if strictVerification in flags and epoch >= 3:
|
2020-05-09 12:43:15 +00:00
|
|
|
# Rule 2/3/4 finalization results in the most pessimal case. The other
|
|
|
|
# three finalization rules finalize more quickly as long as the any of
|
|
|
|
# the finalization rules triggered.
|
2023-05-10 02:31:23 +00:00
|
|
|
doAssert state.finalized_checkpoint.epoch + 3 >= epoch
|
2019-08-14 08:56:32 +00:00
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
process_rewards_and_penalties(state, info)
|
2022-05-25 13:49:29 +00:00
|
|
|
? process_registry_updates(cfg, state, cache)
|
2021-11-25 12:20:36 +00:00
|
|
|
process_slashings(state, info.balances.current_epoch)
|
2021-06-03 09:42:25 +00:00
|
|
|
process_eth1_data_reset(state)
|
|
|
|
process_effective_balance_updates(state)
|
|
|
|
process_slashings_reset(state)
|
|
|
|
process_randao_mixes_reset(state)
|
|
|
|
process_historical_roots_update(state)
|
|
|
|
process_participation_record_updates(state)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2022-05-25 13:49:29 +00:00
|
|
|
ok()
|
|
|
|
|
2021-10-13 14:24:36 +00:00
|
|
|
func init*(
|
|
|
|
info: var altair.EpochInfo,
|
2022-12-06 16:43:11 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState) =
|
2021-10-13 14:24:36 +00:00
|
|
|
# init participation, overwriting the full structure
|
|
|
|
info.balances = get_unslashed_participating_balances(state)
|
|
|
|
info.validators.setLen(state.validators.len())
|
|
|
|
|
|
|
|
let previous_epoch = get_previous_epoch(state)
|
|
|
|
for index in 0..<state.validators.len():
|
|
|
|
var flags: set[ParticipationFlag]
|
|
|
|
if is_eligible_validator(state.validators[index], previous_epoch):
|
|
|
|
flags.incl ParticipationFlag.eligible
|
|
|
|
|
|
|
|
info.validators[index] = ParticipationInfo(
|
|
|
|
flags: flags
|
|
|
|
)
|
|
|
|
|
|
|
|
func init*(
|
2022-10-27 06:29:24 +00:00
|
|
|
T: type altair.EpochInfo,
|
2022-12-06 16:43:11 +00:00
|
|
|
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
|
2024-11-13 03:29:14 +00:00
|
|
|
deneb.BeaconState | electra.BeaconState | fulu.BeaconState): T =
|
2021-10-13 14:24:36 +00:00
|
|
|
init(result, state)
|
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#epoch-processing
|
2021-05-28 15:25:58 +00:00
|
|
|
proc process_epoch*(
|
2022-11-21 07:44:49 +00:00
|
|
|
cfg: RuntimeConfig,
|
2023-01-09 14:15:43 +00:00
|
|
|
state: var (altair.BeaconState | bellatrix.BeaconState),
|
2022-05-25 13:49:29 +00:00
|
|
|
flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo):
|
|
|
|
Result[void, cstring] =
|
2023-05-10 02:31:23 +00:00
|
|
|
let epoch = get_current_epoch(state)
|
2021-10-13 14:24:36 +00:00
|
|
|
info.init(state)
|
2021-05-30 20:23:10 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#justification-and-finalization
|
2023-05-10 02:31:23 +00:00
|
|
|
# [Modified in Altair]
|
2021-10-13 14:24:36 +00:00
|
|
|
process_justification_and_finalization(state, info.balances, flags)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
# state.slot hasn't been incremented yet.
|
2023-05-10 02:31:23 +00:00
|
|
|
if strictVerification in flags and epoch >= 2:
|
|
|
|
doAssert state.current_justified_checkpoint.epoch + 2 >= epoch
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2023-05-10 02:31:23 +00:00
|
|
|
if strictVerification in flags and epoch >= 3:
|
2021-05-28 15:25:58 +00:00
|
|
|
# Rule 2/3/4 finalization results in the most pessimal case. The other
|
|
|
|
# three finalization rules finalize more quickly as long as the any of
|
|
|
|
# the finalization rules triggered.
|
2023-05-10 02:31:23 +00:00
|
|
|
doAssert state.finalized_checkpoint.epoch + 3 >= epoch
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2023-05-10 02:31:23 +00:00
|
|
|
process_inactivity_updates(cfg, state, info) # [New in Altair]
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#rewards-and-penalties
|
2023-05-10 02:31:23 +00:00
|
|
|
process_rewards_and_penalties(cfg, state, info) # [Modified in Altair]
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#registry-updates
|
2022-05-25 13:49:29 +00:00
|
|
|
? process_registry_updates(cfg, state, cache)
|
2021-05-28 15:25:58 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#slashings
|
2023-05-10 02:31:23 +00:00
|
|
|
process_slashings(state, info.balances.current_epoch) # [Modified in Altair]
|
2021-05-28 15:25:58 +00:00
|
|
|
|
|
|
|
process_eth1_data_reset(state)
|
|
|
|
process_effective_balance_updates(state)
|
|
|
|
process_slashings_reset(state)
|
|
|
|
process_randao_mixes_reset(state)
|
|
|
|
process_historical_roots_update(state)
|
2023-05-10 02:31:23 +00:00
|
|
|
process_participation_flag_updates(state) # [New in Altair]
|
|
|
|
process_sync_committee_updates(state) # [New in Altair]
|
2022-05-25 13:49:29 +00:00
|
|
|
|
|
|
|
ok()
|
2023-01-09 14:15:43 +00:00
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/capella/beacon-chain.md#epoch-processing
|
2023-01-09 14:15:43 +00:00
|
|
|
proc process_epoch*(
|
|
|
|
cfg: RuntimeConfig,
|
2024-04-24 12:28:47 +00:00
|
|
|
state: var (capella.BeaconState | deneb.BeaconState),
|
|
|
|
flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo):
|
|
|
|
Result[void, cstring] =
|
|
|
|
let epoch = get_current_epoch(state)
|
|
|
|
info.init(state)
|
|
|
|
|
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#justification-and-finalization
|
|
|
|
process_justification_and_finalization(state, info.balances, flags)
|
|
|
|
|
|
|
|
# state.slot hasn't been incremented yet.
|
|
|
|
if strictVerification in flags:
|
|
|
|
# Rule 2/3/4 finalization results in the most pessimal case. The other
|
|
|
|
# three finalization rules finalize more quickly as long as the any of
|
|
|
|
# the finalization rules triggered.
|
|
|
|
if (epoch >= 2 and state.current_justified_checkpoint.epoch + 2 < epoch) or
|
|
|
|
(epoch >= 3 and state.finalized_checkpoint.epoch + 3 < epoch):
|
|
|
|
fatal "The network did not finalize",
|
|
|
|
epoch, finalizedEpoch = state.finalized_checkpoint.epoch
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
process_inactivity_updates(cfg, state, info)
|
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#rewards-and-penalties
|
2024-04-24 12:28:47 +00:00
|
|
|
process_rewards_and_penalties(cfg, state, info)
|
|
|
|
|
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#registry-updates
|
|
|
|
? process_registry_updates(cfg, state, cache)
|
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#slashings
|
2024-04-24 12:28:47 +00:00
|
|
|
process_slashings(state, info.balances.current_epoch)
|
|
|
|
|
|
|
|
process_eth1_data_reset(state)
|
|
|
|
process_effective_balance_updates(state)
|
|
|
|
process_slashings_reset(state)
|
|
|
|
process_randao_mixes_reset(state)
|
|
|
|
? process_historical_summaries_update(state) # [Modified in Capella]
|
|
|
|
process_participation_flag_updates(state)
|
|
|
|
process_sync_committee_updates(state)
|
|
|
|
|
|
|
|
ok()
|
|
|
|
|
2024-04-28 09:15:03 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.1/specs/electra/beacon-chain.md#epoch-processing
|
2024-04-24 12:28:47 +00:00
|
|
|
proc process_epoch*(
|
2024-11-13 03:29:14 +00:00
|
|
|
cfg: RuntimeConfig, state: var (electra.BeaconState | fulu.BeaconState),
|
2023-01-09 14:15:43 +00:00
|
|
|
flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo):
|
|
|
|
Result[void, cstring] =
|
2023-05-10 02:31:23 +00:00
|
|
|
let epoch = get_current_epoch(state)
|
2023-01-09 14:15:43 +00:00
|
|
|
info.init(state)
|
|
|
|
|
2024-11-24 12:16:09 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/beacon-chain.md#justification-and-finalization
|
2023-01-09 14:15:43 +00:00
|
|
|
process_justification_and_finalization(state, info.balances, flags)
|
|
|
|
|
|
|
|
# state.slot hasn't been incremented yet.
|
2023-02-23 02:10:07 +00:00
|
|
|
if strictVerification in flags:
|
2023-01-09 14:15:43 +00:00
|
|
|
# Rule 2/3/4 finalization results in the most pessimal case. The other
|
|
|
|
# three finalization rules finalize more quickly as long as the any of
|
|
|
|
# the finalization rules triggered.
|
2023-05-10 02:31:23 +00:00
|
|
|
if (epoch >= 2 and state.current_justified_checkpoint.epoch + 2 < epoch) or
|
|
|
|
(epoch >= 3 and state.finalized_checkpoint.epoch + 3 < epoch):
|
2023-02-23 02:10:07 +00:00
|
|
|
fatal "The network did not finalize",
|
2023-05-10 02:31:23 +00:00
|
|
|
epoch, finalizedEpoch = state.finalized_checkpoint.epoch
|
2023-02-23 02:10:07 +00:00
|
|
|
quit 1
|
2023-01-09 14:15:43 +00:00
|
|
|
|
|
|
|
process_inactivity_updates(cfg, state, info)
|
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#rewards-and-penalties
|
2023-01-09 14:15:43 +00:00
|
|
|
process_rewards_and_penalties(cfg, state, info)
|
|
|
|
|
2024-10-09 06:37:35 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/beacon-chain.md#registry-updates
|
2024-04-28 09:15:03 +00:00
|
|
|
? process_registry_updates(cfg, state, cache) # [Modified in Electra:EIP7251]
|
2023-01-09 14:15:43 +00:00
|
|
|
|
2024-03-14 06:26:36 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#slashings
|
2023-01-09 14:15:43 +00:00
|
|
|
process_slashings(state, info.balances.current_epoch)
|
|
|
|
|
|
|
|
process_eth1_data_reset(state)
|
2024-10-06 11:15:56 +00:00
|
|
|
? process_pending_deposits(cfg, state, cache) # [New in Electra:EIP7251]
|
|
|
|
? process_pending_consolidations(cfg, state) # [New in Electra:EIP7251]
|
2024-04-28 09:15:03 +00:00
|
|
|
process_effective_balance_updates(state) # [Modified in Electra:EIP7251]
|
2023-01-09 14:15:43 +00:00
|
|
|
process_slashings_reset(state)
|
|
|
|
process_randao_mixes_reset(state)
|
2023-05-10 02:31:23 +00:00
|
|
|
? process_historical_summaries_update(state) # [Modified in Capella]
|
2023-01-09 14:15:43 +00:00
|
|
|
process_participation_flag_updates(state)
|
|
|
|
process_sync_committee_updates(state)
|
|
|
|
|
|
|
|
ok()
|
2024-07-06 22:32:50 +00:00
|
|
|
|
|
|
|
proc get_validator_balance_after_epoch*(
|
2024-11-13 03:29:14 +00:00
|
|
|
cfg: RuntimeConfig, state: deneb.BeaconState | electra.BeaconState |
|
|
|
|
fulu.BeaconState,
|
2024-08-06 11:33:16 +00:00
|
|
|
cache: var StateCache, info: var altair.EpochInfo,
|
2024-07-06 22:32:50 +00:00
|
|
|
index: ValidatorIndex): Gwei =
|
|
|
|
# Run a subset of process_epoch() which affects an individual validator,
|
|
|
|
# without modifying state itself
|
|
|
|
info.init(state) # TODO avoid quadratic aspects here
|
|
|
|
|
|
|
|
# Can't use process_justification_and_finalization(), but use its helper
|
|
|
|
# function. Used to calculate inactivity_score.
|
|
|
|
let jf_info =
|
|
|
|
# process_justification_and_finalization() skips first two epochs
|
|
|
|
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
|
|
|
JustificationAndFinalizationInfo(
|
|
|
|
previous_justified_checkpoint: state.previous_justified_checkpoint,
|
|
|
|
current_justified_checkpoint: state.current_justified_checkpoint,
|
|
|
|
finalized_checkpoint: state.finalized_checkpoint,
|
|
|
|
justification_bits: state.justification_bits)
|
|
|
|
else:
|
|
|
|
weigh_justification_and_finalization(
|
|
|
|
state, info.balances.current_epoch,
|
|
|
|
info.balances.previous_epoch[TIMELY_TARGET_FLAG_INDEX],
|
2024-08-06 11:33:16 +00:00
|
|
|
info.balances.current_epoch_TIMELY_TARGET, {})
|
2024-07-06 22:32:50 +00:00
|
|
|
|
|
|
|
# Used as part of process_rewards_and_penalties
|
|
|
|
let inactivity_score =
|
|
|
|
# process_inactivity_updates skips GENESIS_EPOCH and ineligible validators
|
|
|
|
if get_current_epoch(state) == GENESIS_EPOCH or
|
|
|
|
not is_eligible_validator(info.validators[index]):
|
|
|
|
0.Gwei
|
|
|
|
else:
|
|
|
|
let
|
|
|
|
finality_delay =
|
|
|
|
get_previous_epoch(state) - jf_info.finalized_checkpoint.epoch
|
|
|
|
not_in_inactivity_leak = not is_in_inactivity_leak(finality_delay)
|
|
|
|
pre_inactivity_score = state.inactivity_scores.asSeq()[index]
|
|
|
|
|
|
|
|
# This is a template which uses not_in_inactivity_leak and index
|
|
|
|
compute_inactivity_update(cfg, state, info, pre_inactivity_score).Gwei
|
|
|
|
|
|
|
|
# process_rewards_and_penalties for a single validator
|
|
|
|
let reward_and_penalties_balance = block:
|
|
|
|
# process_rewards_and_penalties doesn't run at GENESIS_EPOCH
|
|
|
|
if get_current_epoch(state) == GENESIS_EPOCH:
|
|
|
|
state.balances.item(index)
|
|
|
|
else:
|
|
|
|
let
|
|
|
|
total_active_balance = info.balances.current_epoch
|
|
|
|
base_reward_per_increment = get_base_reward_per_increment(
|
|
|
|
total_active_balance)
|
|
|
|
finality_delay = get_finality_delay(state)
|
|
|
|
|
|
|
|
var balance = state.balances.item(index)
|
|
|
|
let maybeDelta = get_flag_and_inactivity_delta_for_validator(
|
|
|
|
cfg, state, base_reward_per_increment, info, finality_delay, index,
|
|
|
|
inactivity_score)
|
|
|
|
if maybeDelta.isOk:
|
|
|
|
# Can't use isErrOr in generics
|
|
|
|
let (validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2) =
|
|
|
|
maybeDelta.get
|
|
|
|
info.validators[validator_index].delta.rewards += reward0 + reward1 + reward2
|
|
|
|
info.validators[validator_index].delta.penalties += penalty0 + penalty1 + penalty2
|
|
|
|
increase_balance(balance, info.validators[index].delta.rewards)
|
|
|
|
decrease_balance(balance, info.validators[index].delta.penalties)
|
|
|
|
balance
|
|
|
|
|
|
|
|
# The two directly balance-changing operations, from Altair through Deneb,
|
|
|
|
# are these. The rest is necessary to look past a single epoch transition,
|
|
|
|
# but that's not the use case here.
|
|
|
|
var post_epoch_balance = reward_and_penalties_balance
|
|
|
|
decrease_balance(
|
|
|
|
post_epoch_balance,
|
|
|
|
get_slashing(state, info.balances.current_epoch, index))
|
|
|
|
|
2024-10-06 11:15:56 +00:00
|
|
|
# Electra adds apply_pending_deposit as a potential balance-changing epoch
|
|
|
|
# operations. This should probably be cached, so its 16+ invocations, each
|
|
|
|
# time, e.g., withdrawals are calculated don't repeat, if it's empirically
|
|
|
|
# too expensive. Limits exist on how large this structure can get though.
|
|
|
|
#
|
|
|
|
# TODO withdrawals and consolidation request processing can also affect this
|
2024-07-06 22:32:50 +00:00
|
|
|
when type(state).kind >= ConsensusFork.Electra:
|
2024-10-06 11:15:56 +00:00
|
|
|
for deposit in state.pending_deposits:
|
|
|
|
discard
|
2024-07-06 22:32:50 +00:00
|
|
|
|
|
|
|
post_epoch_balance
|
2024-08-06 11:33:16 +00:00
|
|
|
|
|
|
|
proc get_next_slot_expected_withdrawals*(
|
|
|
|
cfg: RuntimeConfig, state: deneb.BeaconState, cache: var StateCache,
|
|
|
|
info: var altair.EpochInfo): seq[Withdrawal] =
|
|
|
|
get_expected_withdrawals_aux(state, (state.slot + 1).epoch) do:
|
|
|
|
# validator_index is defined by an injected symbol within the template
|
|
|
|
get_validator_balance_after_epoch(
|
|
|
|
cfg, state, cache, info, validator_index.ValidatorIndex)
|
|
|
|
|
|
|
|
proc get_next_slot_expected_withdrawals*(
|
|
|
|
cfg: RuntimeConfig, state: electra.BeaconState, cache: var StateCache,
|
|
|
|
info: var altair.EpochInfo): seq[Withdrawal] =
|
|
|
|
let (res, _) = get_expected_withdrawals_with_partial_count_aux(
|
|
|
|
state, (state.slot + 1).epoch) do:
|
|
|
|
# validator_index is defined by an injected symbol within the template
|
|
|
|
get_validator_balance_after_epoch(
|
|
|
|
cfg, state, cache, info, validator_index.ValidatorIndex)
|
|
|
|
res
|