add Electra overloads for spec functions; add Electra block processing (#5963)

This commit is contained in:
tersec 2024-02-26 02:38:21 +00:00 committed by GitHub
parent acb1eb1ac6
commit f65c1121d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 139 additions and 36 deletions

View File

@ -228,7 +228,7 @@ func verify_blob_sidecar_inclusion_proof*(
ok()
func create_blob_sidecars*(
forkyBlck: deneb.SignedBeaconBlock,
forkyBlck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock,
kzg_proofs: KzgProofs,
blobs: Blobs): seq[BlobSidecar] =
template kzg_commitments: untyped =
@ -382,7 +382,8 @@ func contextEpoch*(update: SomeForkyLightClientUpdate): Epoch =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#is_merge_transition_complete
func is_merge_transition_complete*(
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState): bool =
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState): bool =
const defaultExecutionPayloadHeader =
default(typeof(state.latest_execution_payload_header))
state.latest_execution_payload_header != defaultExecutionPayloadHeader
@ -398,26 +399,32 @@ func is_execution_block*(blck: SomeForkyBeaconBlock): bool =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#is_merge_transition_block
func is_merge_transition_block(
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState,
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState,
body: bellatrix.BeaconBlockBody | bellatrix.TrustedBeaconBlockBody |
bellatrix.SigVerifiedBeaconBlockBody |
capella.BeaconBlockBody | capella.TrustedBeaconBlockBody |
capella.SigVerifiedBeaconBlockBody |
deneb.BeaconBlockBody | deneb.TrustedBeaconBlockBody |
deneb.SigVerifiedBeaconBlockBody): bool =
deneb.SigVerifiedBeaconBlockBody |
electra.BeaconBlockBody | electra.TrustedBeaconBlockBody |
electra.SigVerifiedBeaconBlockBody): bool =
const defaultExecutionPayload = default(typeof(body.execution_payload))
not is_merge_transition_complete(state) and
body.execution_payload != defaultExecutionPayload
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#is_execution_enabled
func is_execution_enabled*(
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState,
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState,
body: bellatrix.BeaconBlockBody | bellatrix.TrustedBeaconBlockBody |
bellatrix.SigVerifiedBeaconBlockBody |
capella.BeaconBlockBody | capella.TrustedBeaconBlockBody |
capella.SigVerifiedBeaconBlockBody |
deneb.BeaconBlockBody | deneb.TrustedBeaconBlockBody |
deneb.SigVerifiedBeaconBlockBody): bool =
deneb.SigVerifiedBeaconBlockBody |
electra.BeaconBlockBody | electra.TrustedBeaconBlockBody |
electra.SigVerifiedBeaconBlockBody): bool =
is_merge_transition_block(state, body) or is_merge_transition_complete(state)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#compute_timestamp_at_slot
@ -449,8 +456,8 @@ func toExecutionWithdrawal*(
# https://eips.ethereum.org/EIPS/eip-4895
proc computeWithdrawalsTrieRoot*(
payload: capella.ExecutionPayload | deneb.ExecutionPayload
): ExecutionHash256 =
payload: capella.ExecutionPayload | deneb.ExecutionPayload |
electra.ExecutionPayload): ExecutionHash256 =
if payload.withdrawals.len == 0:
return EMPTY_ROOT_HASH

View File

@ -159,18 +159,15 @@ func noRollback*(state: var altair.HashedBeaconState) =
func noRollback*(state: var bellatrix.HashedBeaconState) =
trace "Skipping rollback of broken Bellatrix state"
from ./datatypes/capella import
ExecutionPayload, HashedBeaconState, SignedBLSToExecutionChangeList,
asSigVerified
func noRollback*(state: var capella.HashedBeaconState) =
trace "Skipping rollback of broken Capella state"
from ./datatypes/deneb import HashedBeaconState
func noRollback*(state: var deneb.HashedBeaconState) =
trace "Skipping rollback of broken Deneb state"
func noRollback*(state: var electra.HashedBeaconState) =
trace "Skipping rollback of broken Electra state"
func maybeUpgradeStateToAltair(
cfg: RuntimeConfig, state: var ForkedHashedBeaconState) =
# Both process_slots() and state_transition_block() call this, so only run it

View File

@ -410,7 +410,8 @@ proc process_voluntary_exit*(
ok()
proc process_bls_to_execution_change*(
cfg: RuntimeConfig, state: var (capella.BeaconState | deneb.BeaconState),
cfg: RuntimeConfig,
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState),
signed_address_change: SignedBLSToExecutionChange): Result[void, cstring] =
? check_bls_to_execution_change(
cfg.genesisFork, state, signed_address_change, {})
@ -481,7 +482,7 @@ func get_proposer_reward*(participant_reward: Gwei): Gwei =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#sync-aggregate-processing
proc process_sync_aggregate*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
sync_aggregate: SomeSyncAggregate, total_active_balance: Gwei,
flags: UpdateFlags,
cache: var StateCache):
@ -682,10 +683,67 @@ proc process_execution_payload*(
ok()
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
# copy of datatypes/electra.nim
type SomeElectraBeaconBlockBody =
electra.BeaconBlockBody | electra.SigVerifiedBeaconBlockBody |
electra.TrustedBeaconBlockBody
# TODO spec ref URL when available
proc process_execution_payload*(
state: var electra.BeaconState, body: SomeElectraBeaconBlockBody,
notify_new_payload: electra.ExecutePayload): Result[void, cstring] =
template payload: auto = body.execution_payload
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# [New in Deneb] Verify commitments are under limit
if not (lenu64(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK):
return err("process_execution_payload: too many KZG commitments")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = electra.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals),
blob_gas_used: payload.blob_gas_used,
excess_blob_gas: payload.excess_blob_gas)
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/capella/beacon-chain.md#new-process_withdrawals
func process_withdrawals*(
state: var (capella.BeaconState | deneb.BeaconState),
payload: capella.ExecutionPayload | deneb.ExecutionPayload):
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState),
payload: capella.ExecutionPayload | deneb.ExecutionPayload |
electra.ExecutionPayload):
Result[void, cstring] =
let expected_withdrawals = get_expected_withdrawals(state)
@ -897,3 +955,38 @@ proc process_block*(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/deneb/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
type SomeElectraBlock =
electra.BeaconBlock | electra.SigVerifiedBeaconBlock | electra.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var electra.BeaconState, blck: SomeElectraBlock,
flags: UpdateFlags, cache: var StateCache): Result[void, cstring]=
## When there's a new block, we need to verify that the block is sane and
## update the state accordingly - the state is left in an unknown state when
## block application fails (!)
? process_block_header(state, blck, flags, cache)
# Consensus specs v1.4.0 unconditionally assume is_execution_enabled is
# true, but intentionally keep such a check.
if is_execution_enabled(state, blck.body):
? process_withdrawals(state, blck.body.execution_payload)
? process_execution_payload(
state, blck.body,
func(_: electra.ExecutionPayload): bool = true)
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok()

View File

@ -177,7 +177,8 @@ from ./datatypes/deneb import BeaconState
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_unslashed_participating_indices
func get_unslashed_participating_balances*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState): UnslashedParticipatingBalances =
deneb.BeaconState | electra.BeaconState):
UnslashedParticipatingBalances =
let
previous_epoch = get_previous_epoch(state)
current_epoch = get_current_epoch(state)
@ -228,7 +229,7 @@ func get_unslashed_participating_balances*(
func is_unslashed_participating_index(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
flag_index: TimelyFlag, epoch: Epoch, validator_index: ValidatorIndex): bool =
doAssert epoch in [get_previous_epoch(state), get_current_epoch(state)]
# TODO hoist this conditional
@ -445,7 +446,7 @@ proc compute_unrealized_finality*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#justification-and-finalization
proc process_justification_and_finalization*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
balances: UnslashedParticipatingBalances,
flags: UpdateFlags = {}) =
# Initial FFG checkpoint values have a `0x00` stub for `root`.
@ -467,7 +468,7 @@ proc process_justification_and_finalization*(
proc compute_unrealized_finality*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState): FinalityCheckpoints =
deneb.BeaconState | electra.BeaconState): FinalityCheckpoints =
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
return FinalityCheckpoints(
justified: state.current_justified_checkpoint,
@ -658,7 +659,7 @@ func get_attestation_deltas(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_base_reward
func get_base_reward_increment*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
index: ValidatorIndex, base_reward_per_increment: Gwei): Gwei =
## Return the base reward for the validator defined by ``index`` with respect
## to the current ``state``.
@ -669,7 +670,7 @@ func get_base_reward_increment*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_flag_index_deltas
func get_flag_index_reward*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
base_reward: Gwei, active_increments: Gwei,
unslashed_participating_increments: Gwei,
weight, finality_delay: uint64): Gwei =
@ -697,7 +698,7 @@ func get_active_increments*(
iterator get_flag_and_inactivity_deltas*(
cfg: RuntimeConfig,
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
base_reward_per_increment: Gwei, info: var altair.EpochInfo,
finality_delay: uint64):
(ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) =
@ -807,7 +808,7 @@ func process_rewards_and_penalties*(
func process_rewards_and_penalties*(
cfg: RuntimeConfig,
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
info: var altair.EpochInfo) =
if get_current_epoch(state) == GENESIS_EPOCH:
return
@ -914,7 +915,7 @@ func get_adjusted_total_slashing_balance*(
elif state is altair.BeaconState:
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
elif state is bellatrix.BeaconState or state is capella.BeaconState or
state is deneb.BeaconState:
state is deneb.BeaconState or state is electra.BeaconState:
PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX
else:
{.fatal: "process_slashings: incorrect BeaconState type".}
@ -1037,7 +1038,8 @@ func process_participation_record_updates*(state: var phase0.BeaconState) =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#participation-flags-updates
func process_participation_flag_updates*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState)) =
capella.BeaconState | deneb.BeaconState |
electra.BeaconState)) =
state.previous_epoch_participation = state.current_epoch_participation
const zero = 0.ParticipationFlags
@ -1051,7 +1053,8 @@ func process_participation_flag_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#sync-committee-updates
func process_sync_committee_updates*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState)) =
capella.BeaconState | deneb.BeaconState |
electra.BeaconState)) =
let next_epoch = get_current_epoch(state) + 1
if next_epoch.is_sync_committee_period():
state.current_sync_committee = state.next_sync_committee
@ -1060,7 +1063,7 @@ func process_sync_committee_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#inactivity-scores
template compute_inactivity_update(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
info: altair.EpochInfo, pre_inactivity_score: Gwei): Gwei =
if not is_eligible_validator(info.validators[index]):
continue
@ -1086,7 +1089,7 @@ template compute_inactivity_update(
func process_inactivity_updates*(
cfg: RuntimeConfig,
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
info: altair.EpochInfo) =
# Score updates based on previous epoch participation, skip genesis epoch
if get_current_epoch(state) == GENESIS_EPOCH:
@ -1108,7 +1111,7 @@ func process_inactivity_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#historical-summaries-updates
func process_historical_summaries_update*(
state: var (capella.BeaconState | deneb.BeaconState)):
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState)):
Result[void, cstring] =
# Set historical block root accumulator.
let next_epoch = get_current_epoch(state) + 1
@ -1159,7 +1162,7 @@ proc process_epoch*(
func init*(
info: var altair.EpochInfo,
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState) =
deneb.BeaconState | electra.BeaconState) =
# init participation, overwriting the full structure
info.balances = get_unslashed_participating_balances(state)
info.validators.setLen(state.validators.len())
@ -1229,7 +1232,7 @@ proc process_epoch*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#epoch-processing
proc process_epoch*(
cfg: RuntimeConfig,
state: var (capella.BeaconState | deneb.BeaconState),
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState),
flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo):
Result[void, cstring] =
let epoch = get_current_epoch(state)

View File

@ -274,7 +274,7 @@ proc collectEpochRewardsAndPenalties*(
proc collectEpochRewardsAndPenalties*(
rewardsAndPenalties: var seq[RewardsAndPenalties],
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
cache: var StateCache, cfg: RuntimeConfig, flags: UpdateFlags) =
if get_current_epoch(state) == GENESIS_EPOCH:
return

View File

@ -94,4 +94,5 @@ template runForkBlockTests(consensusFork: static ConsensusFork) =
RandomDir, suiteName, path)
withAll(ConsensusFork):
when consensusFork <= ConsensusFork.Deneb:
runForkBlockTests(consensusFork)

View File

@ -31,6 +31,7 @@ suite "Light client" & preset():
res.BELLATRIX_FORK_EPOCH = 2.Epoch
res.CAPELLA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 1).Epoch
res.DENEB_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 2).Epoch
res.ELECTRA_FORK_EPOCH = FAR_FUTURE_EPOCH
res
altairStartSlot = cfg.ALTAIR_FORK_EPOCH.start_slot

View File

@ -34,6 +34,7 @@ suite "Light client processor" & preset():
res.BELLATRIX_FORK_EPOCH = 2.Epoch
res.CAPELLA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 1).Epoch
res.DENEB_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 2).Epoch
res.ELECTRA_FORK_EPOCH = FAR_FUTURE_EPOCH
res
const numValidators = SLOTS_PER_EPOCH