capella test vector support (#4261)

This commit is contained in:
tersec 2022-10-27 06:29:24 +00:00 committed by GitHub
parent 69ed3a2fd6
commit 06ccf5b80c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1442 additions and 59 deletions

View File

@ -19,6 +19,8 @@ import
./datatypes/[phase0, altair, bellatrix],
"."/[eth2_merkleization, forks, signatures, validator]
from ./datatypes/capella import BeaconState, ExecutionPayloadHeader, Withdrawal
export extras, forks, validator
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#increase_balance
@ -143,6 +145,8 @@ func get_slashing_penalty*(state: ForkyBeaconState,
validator_effective_balance div MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
elif state is bellatrix.BeaconState:
validator_effective_balance div MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX
elif state is capella.BeaconState:
validator_effective_balance div MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX
else:
{.fatal: "invalid BeaconState type".}
@ -158,7 +162,8 @@ func get_whistleblower_reward*(validator_effective_balance: Gwei): Gwei =
func get_proposer_reward(state: ForkyBeaconState, whistleblower_reward: Gwei): Gwei =
when state is phase0.BeaconState:
whistleblower_reward div PROPOSER_REWARD_QUOTIENT
elif state is altair.BeaconState or state is bellatrix.BeaconState:
elif state is altair.BeaconState or state is bellatrix.BeaconState or
state is capella.BeaconState:
whistleblower_reward * PROPOSER_WEIGHT div WEIGHT_DENOMINATOR
else:
{.fatal: "invalid BeaconState type".}
@ -563,9 +568,9 @@ func check_attestation_index*(
check_attestation_index(data.index, committees_per_slot)
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_attestation_participation_flag_indices
func get_attestation_participation_flag_indices(state: altair.BeaconState | bellatrix.BeaconState,
data: AttestationData,
inclusion_delay: uint64): seq[int] =
func get_attestation_participation_flag_indices(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState,
data: AttestationData, inclusion_delay: uint64): seq[int] =
## Return the flag indices that are satisfied by an attestation.
let justified_checkpoint =
if data.target.epoch == get_current_epoch(state):
@ -618,8 +623,8 @@ func get_base_reward_per_increment*(
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_base_reward
func get_base_reward(
state: altair.BeaconState | bellatrix.BeaconState, index: ValidatorIndex,
base_reward_per_increment: Gwei): Gwei =
state: altair.BeaconState | bellatrix.BeaconState | capella.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``.
let increments =
@ -717,7 +722,7 @@ proc process_attestation*(
pa[].inclusion_delay = state.slot - attestation.data.slot
pa[].proposer_index = proposer_index.get().uint64
# Altair and Bellatrix
# Altair, Bellatrix, and Capella
template updateParticipationFlags(epoch_participation: untyped) =
let proposer_reward = get_proposer_reward(
state, attestation, base_reward_per_increment, cache, epoch_participation)
@ -729,7 +734,8 @@ proc process_attestation*(
addPendingAttestation(state.current_epoch_attestations)
else:
addPendingAttestation(state.previous_epoch_attestations)
elif state is altair.BeaconState or state is bellatrix.BeaconState:
elif state is altair.BeaconState or state is bellatrix.BeaconState or
state is capella.BeaconState:
doAssert base_reward_per_increment > 0.Gwei
if attestation.data.target.epoch == get_current_epoch(state):
updateParticipationFlags(state.current_epoch_participation)
@ -741,7 +747,8 @@ proc process_attestation*(
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_next_sync_committee_indices
func get_next_sync_committee_keys(state: altair.BeaconState | bellatrix.BeaconState):
func get_next_sync_committee_keys(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState):
array[SYNC_COMMITTEE_SIZE, ValidatorPubKey] =
## Return the sequence of sync committee indices, with possible duplicates,
## for the next sync committee.
@ -777,7 +784,8 @@ func get_next_sync_committee_keys(state: altair.BeaconState | bellatrix.BeaconSt
res
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_next_sync_committee
func get_next_sync_committee*(state: altair.BeaconState | bellatrix.BeaconState):
func get_next_sync_committee*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState):
SyncCommittee =
## Return the *next* sync committee for a given ``state``.
var res: SyncCommittee
@ -934,7 +942,88 @@ func upgrade_to_bellatrix*(cfg: RuntimeConfig, pre: altair.BeaconState):
next_sync_committee: pre.next_sync_committee,
# Execution-layer
latest_execution_payload_header: ExecutionPayloadHeader()
latest_execution_payload_header: default(bellatrix.ExecutionPayloadHeader)
)
# https://github.com/ethereum/consensus-specs/blob/b90436c98837924c3a929652b57b07ac9d3c2254/specs/capella/fork.md#upgrading-the-state
func upgrade_to_capella*(cfg: RuntimeConfig, pre: bellatrix.BeaconState):
ref capella.BeaconState =
let
epoch = get_current_epoch(pre)
latest_execution_payload_header = capella.ExecutionPayloadHeader(
parent_hash: pre.latest_execution_payload_header.parent_hash,
fee_recipient: pre.latest_execution_payload_header.fee_recipient,
state_root: pre.latest_execution_payload_header.state_root,
receipts_root: pre.latest_execution_payload_header.receipts_root,
logs_bloom: pre.latest_execution_payload_header.logs_bloom,
prev_randao: pre.latest_execution_payload_header.prev_randao,
block_number: pre.latest_execution_payload_header.block_number,
gas_limit: pre.latest_execution_payload_header.gas_limit,
gas_used: pre.latest_execution_payload_header.gas_used,
timestamp: pre.latest_execution_payload_header.timestamp,
extra_data: pre.latest_execution_payload_header.extra_data,
base_fee_per_gas: pre.latest_execution_payload_header.base_fee_per_gas,
block_hash: pre.latest_execution_payload_header.block_hash,
transactions_root: pre.latest_execution_payload_header.transactions_root,
withdrawals_root: Eth2Digest() # [New in Capella]
)
(ref capella.BeaconState)(
# Versioning
genesis_time: pre.genesis_time,
genesis_validators_root: pre.genesis_validators_root,
slot: pre.slot,
fork: Fork(
previous_version: pre.fork.current_version,
current_version: cfg.CAPELLA_FORK_VERSION,
epoch: epoch,
),
# History
latest_block_header: pre.latest_block_header,
block_roots: pre.block_roots,
state_roots: pre.state_roots,
historical_roots: pre.historical_roots,
# Eth1
eth1_data: pre.eth1_data,
eth1_data_votes: pre.eth1_data_votes,
eth1_deposit_index: pre.eth1_deposit_index,
# Registry
validators: pre.validators,
balances: pre.balances,
# Randomness
randao_mixes: pre.randao_mixes,
# Slashings
slashings: pre.slashings,
# Participation
previous_epoch_participation: pre.previous_epoch_participation,
current_epoch_participation: pre.current_epoch_participation,
# Finality
justification_bits: pre.justification_bits,
previous_justified_checkpoint: pre.previous_justified_checkpoint,
current_justified_checkpoint: pre.current_justified_checkpoint,
finalized_checkpoint: pre.finalized_checkpoint,
# Inactivity
inactivity_scores: pre.inactivity_scores,
# Sync
current_sync_committee: pre.current_sync_committee,
next_sync_committee: pre.next_sync_committee,
# Execution-layer
latest_execution_payload_header: latest_execution_payload_header,
# Withdrawals
withdrawal_queue: HashList[Withdrawal, Limit WITHDRAWAL_QUEUE_LIMIT](),
next_withdrawal_index: 0,
next_partial_withdrawal_validator_index: 0
)
template isValidInState*(idx: ValidatorIndex, state: ForkyBeaconState): bool =
@ -969,8 +1058,8 @@ func latest_block_root*(state: ForkedHashedBeaconState): Eth2Digest =
withState(state): latest_block_root(forkyState)
func get_sync_committee_cache*(
state: altair.BeaconState | bellatrix.BeaconState, cache: var StateCache):
SyncCommitteeCache =
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState,
cache: var StateCache): SyncCommitteeCache =
let period = state.slot.sync_committee_period()
cache.sync_committees.withValue(period, v) do:

View File

@ -0,0 +1,439 @@
# beacon_chain
# Copyright (c) 2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
# Types specific to capella (ie known to have changed across hard forks) - see
# `base` for types and guidelines common across forks
# TODO Careful, not nil analysis is broken / incomplete and the semantics will
# likely change in future versions of the language:
# https://github.com/nim-lang/RFCs/issues/250
{.experimental: "notnil".}
when (NimMajor, NimMinor) < (1, 4):
{.push raises: [Defect].}
else:
{.push raises: [].}
import
stew/byteutils,
json_serialization,
ssz_serialization/types as sszTypes,
../digest,
"."/[base, phase0, altair, bellatrix]
export json_serialization, base
type
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#custom-types
WithdrawalIndex = uint64
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#withdrawal
Withdrawal* = object
index*: WithdrawalIndex
validator_index*: uint64
address*: ExecutionAddress
amount*: Gwei
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#blstoexecutionchange
BLSToExecutionChange* = object
validator_index*: uint64
from_bls_pubkey*: ValidatorPubKey
to_execution_address*: ExecutionAddress
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#signedblstoexecutionchange
SignedBLSToExecutionChange* = object
message*: BLSToExecutionChange
signature*: ValidatorSig
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#executionpayload
ExecutionPayload* = object
parent_hash*: Eth2Digest
fee_recipient*: ExecutionAddress # 'beneficiary' in the yellow paper
state_root*: Eth2Digest
receipts_root*: Eth2Digest # 'receipts root' in the yellow paper
logs_bloom*: BloomLogs
prev_randao*: Eth2Digest # 'difficulty' in the yellow paper
block_number*: uint64 # 'number' in the yellow paper
gas_limit*: uint64
gas_used*: uint64
timestamp*: uint64
extra_data*: List[byte, MAX_EXTRA_DATA_BYTES]
base_fee_per_gas*: UInt256
# Extra payload fields
block_hash*: Eth2Digest # Hash of execution block
transactions*: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
withdrawals*: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] # [New in Capella]
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#executionpayloadheader
ExecutionPayloadHeader* = object
parent_hash*: Eth2Digest
fee_recipient*: ExecutionAddress
state_root*: Eth2Digest
receipts_root*: Eth2Digest
logs_bloom*: BloomLogs
prev_randao*: Eth2Digest
block_number*: uint64
gas_limit*: uint64
gas_used*: uint64
timestamp*: uint64
extra_data*: List[byte, MAX_EXTRA_DATA_BYTES]
base_fee_per_gas*: UInt256
# Extra payload fields
block_hash*: Eth2Digest # Hash of execution block
transactions_root*: Eth2Digest
withdrawals_root*: Eth2Digest # [New in Capella]
ExecutePayload* = proc(
execution_payload: ExecutionPayload): bool {.gcsafe, raises: [Defect].}
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#beaconstate
BeaconState* = object
# Versioning
genesis_time*: uint64
genesis_validators_root*: Eth2Digest
slot*: Slot
fork*: Fork
# History
latest_block_header*: BeaconBlockHeader
## `latest_block_header.state_root == ZERO_HASH` temporarily
block_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
## Needed to process attestations, older to newer
state_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
historical_roots*: HashList[Eth2Digest, Limit HISTORICAL_ROOTS_LIMIT]
# Eth1
eth1_data*: Eth1Data
eth1_data_votes*:
HashList[Eth1Data, Limit(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)]
eth1_deposit_index*: uint64
# Registry
validators*: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]
balances*: HashList[Gwei, Limit VALIDATOR_REGISTRY_LIMIT]
# Randomness
randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]
# Slashings
slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, Gwei]
## Per-epoch sums of slashed effective balances
# Participation
previous_epoch_participation*: EpochParticipationFlags
current_epoch_participation*: EpochParticipationFlags
# Finality
justification_bits*: JustificationBits
previous_justified_checkpoint*: Checkpoint
## Previous epoch snapshot
current_justified_checkpoint*: Checkpoint
finalized_checkpoint*: Checkpoint
# Inactivity
inactivity_scores*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT] # [New in Altair]
# Light client sync committees
current_sync_committee*: SyncCommittee # [New in Altair]
next_sync_committee*: SyncCommittee # [New in Altair]
# Execution
latest_execution_payload_header*: ExecutionPayloadHeader
# Withdrawals
withdrawal_queue*: HashList[Withdrawal, WITHDRAWAL_QUEUE_LIMIT] # [New in Capella]
next_withdrawal_index*: WithdrawalIndex # [New in Capella]
next_partial_withdrawal_validator_index*: uint64 # [New in Capella]
# TODO Careful, not nil analysis is broken / incomplete and the semantics will
# likely change in future versions of the language:
# https://github.com/nim-lang/RFCs/issues/250
BeaconStateRef* = ref BeaconState not nil
NilableBeaconStateRef* = ref BeaconState
HashedBeaconState* = object
data*: BeaconState
root*: Eth2Digest # hash_tree_root(data)
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose
## a new block. Once the block as been proposed, it is transmitted to
## validators that will have a chance to vote on it through attestations.
## Each block collects attestations, or votes, on past blocks, thus a chain
## is formed.
slot*: Slot
proposer_index*: uint64 # `ValidatorIndex` after validation
parent_root*: Eth2Digest
## Root hash of the previous block
state_root*: Eth2Digest
## The state root, _after_ this block has been processed
body*: BeaconBlockBody
SigVerifiedBeaconBlock* = object
## A BeaconBlock that contains verified signatures
## but that has not been verified for state transition
slot*: Slot
proposer_index*: uint64 # `ValidatorIndex` after validation
parent_root*: Eth2Digest
## Root hash of the previous block
state_root*: Eth2Digest
## The state root, _after_ this block has been processed
body*: SigVerifiedBeaconBlockBody
TrustedBeaconBlock* = object
## When we receive blocks from outside sources, they are untrusted and go
## through several layers of validation. Blocks that have gone through
## validations can be trusted to be well-formed, with a correct signature,
## having a parent and applying cleanly to the state that their parent
## left them with.
##
## When loading such blocks from the database, to rewind states for example,
## it is expensive to redo the validations (in particular, the signature
## checks), thus `TrustedBlock` uses a `TrustedSig` type to mark that these
## checks can be skipped.
##
## TODO this could probably be solved with some type trickery, but there
## too many bugs in nim around generics handling, and we've used up
## the trickery budget in the serialization library already. Until
## then, the type must be manually kept compatible with its untrusted
## cousin.
slot*: Slot
proposer_index*: uint64 # `ValidatorIndex` after validation
parent_root*: Eth2Digest
state_root*: Eth2Digest
body*: TrustedBeaconBlockBody
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#beaconblockbody
BeaconBlockBody* = object
randao_reveal*: ValidatorSig
eth1_data*: Eth1Data
## Eth1 data vote
graffiti*: GraffitiBytes
## Arbitrary data
# Operations
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
attester_slashings*: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
attestations*: List[Attestation, Limit MAX_ATTESTATIONS]
deposits*: List[Deposit, Limit MAX_DEPOSITS]
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
sync_aggregate*: SyncAggregate
# Execution
execution_payload*: ExecutionPayload
# Capella operations
bls_to_execution_changes*: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella]
SigVerifiedBeaconBlockBody* = object
## A BeaconBlock body with signatures verified
## including:
## - Randao reveal
## - Attestations
## - ProposerSlashing (SignedBeaconBlockHeader)
## - AttesterSlashing (IndexedAttestation)
## - SignedVoluntaryExits
## - SyncAggregate
##
## However:
## - ETH1Data (Deposits) can contain invalid BLS signatures
##
## The block state transition has NOT been verified
randao_reveal*: TrustedSig
eth1_data*: Eth1Data
## Eth1 data vote
graffiti*: GraffitiBytes
## Arbitrary data
# Operations
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
deposits*: List[Deposit, Limit MAX_DEPOSITS]
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
sync_aggregate*: TrustedSyncAggregate
# Execution
execution_payload*: ExecutionPayload
# Capella operations
bls_to_execution_changes*: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella]
TrustedBeaconBlockBody* = object
## A full verified block
randao_reveal*: TrustedSig
eth1_data*: Eth1Data
## Eth1 data vote
graffiti*: GraffitiBytes
## Arbitrary data
# Operations
proposer_slashings*: List[TrustedProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
attester_slashings*: List[TrustedAttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
deposits*: List[Deposit, Limit MAX_DEPOSITS]
voluntary_exits*: List[TrustedSignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
sync_aggregate*: TrustedSyncAggregate
# Execution
execution_payload*: ExecutionPayload
# Capella operations
bls_to_execution_changes*: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella]
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#signedbeaconblock
SignedBeaconBlock* = object
message*: BeaconBlock
signature*: ValidatorSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
SigVerifiedSignedBeaconBlock* = object
## A SignedBeaconBlock with signatures verified
## including:
## - Block signature
## - BeaconBlockBody
## - Randao reveal
## - Attestations
## - ProposerSlashing (SignedBeaconBlockHeader)
## - AttesterSlashing (IndexedAttestation)
## - SignedVoluntaryExits
##
## - ETH1Data (Deposits) can contain invalid BLS signatures
##
## The block state transition has NOT been verified
message*: SigVerifiedBeaconBlock
signature*: TrustedSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
MsgTrustedSignedBeaconBlock* = object
message*: TrustedBeaconBlock
signature*: ValidatorSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
TrustedSignedBeaconBlock* = object
message*: TrustedBeaconBlock
signature*: TrustedSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
SomeSignedBeaconBlock* =
SignedBeaconBlock |
SigVerifiedSignedBeaconBlock |
MsgTrustedSignedBeaconBlock |
TrustedSignedBeaconBlock
SomeBeaconBlock* =
BeaconBlock |
SigVerifiedBeaconBlock |
TrustedBeaconBlock
SomeBeaconBlockBody* =
BeaconBlockBody |
SigVerifiedBeaconBlockBody |
TrustedBeaconBlockBody
BlockParams = object
parentHash*: string
timestamp*: string
BoolReturnValidRPC = object
valid*: bool
BoolReturnSuccessRPC = object
success*: bool
func fromHex*(T: typedesc[BloomLogs], s: string): T {.
raises: [Defect, ValueError].} =
hexToByteArray(s, result.data)
func fromHex*(T: typedesc[ExecutionAddress], s: string): T {.
raises: [Defect, ValueError].} =
hexToByteArray(s, result.data)
proc writeValue*(writer: var JsonWriter, value: ExecutionAddress) {.
raises: [Defect, IOError].} =
writer.writeValue to0xHex(value.data)
proc readValue*(reader: var JsonReader, value: var ExecutionAddress) {.
raises: [Defect, IOError, SerializationError].} =
try:
hexToByteArray(reader.readValue(string), value.data)
except ValueError:
raiseUnexpectedValue(reader,
"ExecutionAddress value should be a valid hex string")
func shortLog*(v: SomeBeaconBlock): auto =
(
slot: shortLog(v.slot),
proposer_index: v.proposer_index,
parent_root: shortLog(v.parent_root),
state_root: shortLog(v.state_root),
eth1data: v.body.eth1_data,
graffiti: $v.body.graffiti,
proposer_slashings_len: v.body.proposer_slashings.len(),
attester_slashings_len: v.body.attester_slashings.len(),
attestations_len: v.body.attestations.len(),
deposits_len: v.body.deposits.len(),
voluntary_exits_len: v.body.voluntary_exits.len(),
sync_committee_participants: countOnes(v.body.sync_aggregate.sync_committee_bits)
)
func shortLog*(v: SomeSignedBeaconBlock): auto =
(
blck: shortLog(v.message),
signature: shortLog(v.signature)
)
template asSigned*(
x: SigVerifiedSignedBeaconBlock |
MsgTrustedSignedBeaconBlock |
TrustedSignedBeaconBlock): SignedBeaconBlock =
isomorphicCast[SignedBeaconBlock](x)
template asSigVerified*(
x: SignedBeaconBlock |
MsgTrustedSignedBeaconBlock |
TrustedSignedBeaconBlock): SigVerifiedSignedBeaconBlock =
isomorphicCast[SigVerifiedSignedBeaconBlock](x)
template asSigVerified*(
x: BeaconBlock | TrustedBeaconBlock): SigVerifiedBeaconBlock =
isomorphicCast[SigVerifiedBeaconBlock](x)
template asMsgTrusted*(
x: SignedBeaconBlock |
SigVerifiedSignedBeaconBlock |
TrustedSignedBeaconBlock): MsgTrustedSignedBeaconBlock =
isomorphicCast[MsgTrustedSignedBeaconBlock](x)
template asTrusted*(
x: SignedBeaconBlock |
SigVerifiedSignedBeaconBlock |
MsgTrustedSignedBeaconBlock): TrustedSignedBeaconBlock =
isomorphicCast[TrustedSignedBeaconBlock](x)

View File

@ -33,6 +33,9 @@ const
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF* = DomainType([byte 0x08, 0x00, 0x00, 0x00])
DOMAIN_CONTRIBUTION_AND_PROOF* = DomainType([byte 0x09, 0x00, 0x00, 0x00])
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#domain-types
DOMAIN_BLS_TO_EXECUTION_CHANGE* = DomainType([byte 0x0a, 0x00, 0x00, 0x00])
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#transition-settings
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH* = FAR_FUTURE_EPOCH

View File

@ -14,18 +14,28 @@ else:
import
ssz_serialization/[merkleization, proofs],
./ssz_codec,
./datatypes/[phase0, altair]
./ssz_codec
from ./datatypes/phase0 import HashedBeaconState, SignedBeaconBlock
from ./datatypes/altair import HashedBeaconState, SignedBeaconBlock
from ./datatypes/bellatrix import HashedBeaconState, SignedBeaconBlock
from ./datatypes/capella import HashedBeaconState, SignedBeaconBlock
export ssz_codec, merkleization, proofs
type
DepositsMerkleizer* = SszMerkleizer[DEPOSIT_CONTRACT_LIMIT]
func hash_tree_root*(x: phase0.HashedBeaconState | altair.HashedBeaconState) {.
# Can't use `ForkyHashedBeaconState`/`ForkyHashedSignedBeaconBlock` without
# creating recursive module dependency through `forks`.
func hash_tree_root*(
x: phase0.HashedBeaconState | altair.HashedBeaconState |
bellatrix.HashedBeaconState | capella.HashedBeaconState) {.
error: "HashedBeaconState should not be hashed".}
func hash_tree_root*(x: phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock) {.
func hash_tree_root*(
x: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock) {.
error: "SignedBeaconBlock should not be hashed".}
func depositCountU64(s: DepositContractState): uint64 =

View File

@ -16,7 +16,7 @@ else:
import
ssz_serialization,
./ssz_codec,
./datatypes/[phase0, altair, bellatrix],
./datatypes/[phase0, altair, bellatrix, capella],
./eth2_merkleization
export phase0, altair, ssz_codec, ssz_serialization, eth2_merkleization
@ -48,6 +48,12 @@ template readSszBytes*(
template readSszBytes*(
data: openArray[byte], val: var bellatrix.TrustedSignedBeaconBlock, updateRoot = true) =
readAndUpdateRoot(data, val, updateRoot)
template readSszBytes*(
data: openArray[byte], val: var capella.SignedBeaconBlock, updateRoot = true) =
readAndUpdateRoot(data, val, updateRoot)
template readSszBytes*(
data: openArray[byte], val: var capella.TrustedSignedBeaconBlock, updateRoot = true) =
readAndUpdateRoot(data, val, updateRoot)
template readSszBytes*(
data: openArray[byte], val: var auto, updateRoot: bool) =

View File

@ -15,7 +15,7 @@ import
chronicles,
../extras,
"."/[block_id, eth2_merkleization, eth2_ssz_serialization, presets],
./datatypes/[phase0, altair, bellatrix],
./datatypes/[phase0, altair, bellatrix, capella],
./mev/bellatrix_mev
export
@ -47,7 +47,8 @@ type
ForkyBeaconState* =
phase0.BeaconState |
altair.BeaconState |
bellatrix.BeaconState
bellatrix.BeaconState |
capella.BeaconState
ForkyHashedBeaconState* =
phase0.HashedBeaconState |
@ -88,7 +89,8 @@ type
ForkyBeaconBlock* =
phase0.BeaconBlock |
altair.BeaconBlock |
bellatrix.BeaconBlock
bellatrix.BeaconBlock |
capella.BeaconBlock
ForkySigVerifiedBeaconBlock* =
phase0.SigVerifiedBeaconBlock |

View File

@ -20,7 +20,7 @@ import
chronicles,
eth/eip1559, eth/common/[eth_types, eth_types_rlp],
# Internal
./datatypes/[phase0, altair, bellatrix],
./datatypes/[phase0, altair, bellatrix, capella],
"."/[eth2_merkleization, forks, ssz_codec]
# TODO although eth2_merkleization already exports ssz_codec, *sometimes* code
@ -319,8 +319,10 @@ func contextEpoch*(update: SomeLightClientUpdate): Epoch =
update.attested_header.slot.epoch
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#is_merge_transition_complete
func is_merge_transition_complete*(state: bellatrix.BeaconState): bool =
const defaultExecutionPayloadHeader = default(ExecutionPayloadHeader)
func is_merge_transition_complete*(
state: bellatrix.BeaconState | capella.BeaconState): bool =
const defaultExecutionPayloadHeader =
default(typeof(state.latest_execution_payload_header))
state.latest_execution_payload_header != defaultExecutionPayloadHeader
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/sync/optimistic.md#helpers
@ -354,7 +356,8 @@ func compute_timestamp_at_slot*(state: ForkyBeaconState, slot: Slot): uint64 =
let slots_since_genesis = slot - GENESIS_SLOT
state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT
proc emptyPayloadToBlockHeader*(payload: ExecutionPayload): ExecutionBlockHeader =
proc emptyPayloadToBlockHeader*(
payload: bellatrix.ExecutionPayload): ExecutionBlockHeader =
## This function assumes that the payload is empty!
doAssert payload.transactions.len == 0
@ -377,7 +380,8 @@ proc emptyPayloadToBlockHeader*(payload: ExecutionPayload): ExecutionBlockHeader
fee : some payload.base_fee_per_gas
)
func build_empty_execution_payload*(state: bellatrix.BeaconState): ExecutionPayload =
func build_empty_execution_payload*(
state: bellatrix.BeaconState): bellatrix.ExecutionPayload =
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
## without any transactions.
let
@ -388,7 +392,7 @@ func build_empty_execution_payload*(state: bellatrix.BeaconState): ExecutionPayl
GasInt.saturate latest.gas_used,
latest.base_fee_per_gas)
var payload = ExecutionPayload(
var payload = bellatrix.ExecutionPayload(
parent_hash: latest.block_hash,
state_root: latest.state_root, # no changes to the state
receipts_root: EMPTY_ROOT_HASH,

View File

@ -1,4 +1,4 @@
import
./mainnet/[altair_preset, bellatrix_preset, phase0_preset]
./mainnet/[altair_preset, bellatrix_preset, capella_preset, phase0_preset]
export altair_preset, bellatrix_preset, phase0_preset
export altair_preset, bellatrix_preset, capella_preset, phase0_preset

View File

@ -0,0 +1,25 @@
# Mainnet preset - Capella
# https://github.com/ethereum/consensus-specs/blob/86e2f8fd7de25a7478c240f0cf5ba3c5264e96bf/presets/mainnet/capella.yaml
const
# Misc
# ---------------------------------------------------------------
# 2**8 (= 256) withdrawals
MAX_PARTIAL_WITHDRAWALS_PER_EPOCH* = 256
# State list lengths
# ---------------------------------------------------------------
# 2**40 (= 1,099,511,627,776) withdrawals
WITHDRAWAL_QUEUE_LIMIT* = 1099511627776
# Max operations per block
# ---------------------------------------------------------------
# 2**4 (= 16)
MAX_BLS_TO_EXECUTION_CHANGES* = 16
# Execution
# ---------------------------------------------------------------
# 2**4 (= 16) withdrawals
MAX_WITHDRAWALS_PER_PAYLOAD* = 16

View File

@ -1,4 +1,4 @@
import
./minimal/[altair_preset, bellatrix_preset, phase0_preset]
./minimal/[altair_preset, bellatrix_preset, capella_preset, phase0_preset]
export altair_preset, bellatrix_preset, phase0_preset
export altair_preset, bellatrix_preset, capella_preset, phase0_preset

View File

@ -0,0 +1,26 @@
# Minimal preset - Capella
# https://github.com/ethereum/consensus-specs/blob/86e2f8fd7de25a7478c240f0cf5ba3c5264e96bf/presets/minimal/capella.yaml
const
# Misc
# ---------------------------------------------------------------
# # [customized] 16 for more interesting tests at low validator count
MAX_PARTIAL_WITHDRAWALS_PER_EPOCH* = 16
# State list lengths
# ---------------------------------------------------------------
# 2**40 (= 1,099,511,627,776) withdrawals
WITHDRAWAL_QUEUE_LIMIT* = 1099511627776
# Max operations per block
# ---------------------------------------------------------------
# 2**4 (= 16)
MAX_BLS_TO_EXECUTION_CHANGES* = 16
# Execution
# ---------------------------------------------------------------
# [customized] Lower than MAX_PARTIAL_WITHDRAWALS_PER_EPOCH so not all
# processed in one block
MAX_WITHDRAWALS_PER_PAYLOAD* = 8

View File

@ -23,6 +23,8 @@ import
./datatypes/[phase0, altair, bellatrix], ./mev/bellatrix_mev, ./helpers,
./eth2_merkleization
from ./datatypes/capella import BLSToExecutionChange, SignedBLSToExecutionChange
export phase0, altair
template withTrust(sig: SomeSig, body: untyped): bool =
@ -368,3 +370,19 @@ proc verify_builder_signature*(
pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool =
let signing_root = compute_builder_signing_root(fork, msg)
blsVerify(pubkey, signing_root.data, signature)
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
func compute_bls_to_execution_change_signing_root(
fork: Fork, genesis_validators_root: Eth2Digest,
epoch: Epoch, msg: BLSToExecutionChange): Eth2Digest =
let domain = get_domain(
fork, DOMAIN_BLS_TO_EXECUTION_CHANGE, epoch, genesis_validators_root)
compute_signing_root(msg, domain)
proc verify_bls_to_execution_change_signature*(
fork: Fork, genesis_validators_root: Eth2Digest, epoch: Epoch,
msg: SignedBLSToExecutionChange,
pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool =
let signing_root = compute_bls_to_execution_change_signing_root(
fork, genesis_validators_root, epoch, msg.message)
blsVerify(pubkey, signing_root.data, signature)

View File

@ -29,6 +29,9 @@ import
./datatypes/[phase0, altair, bellatrix],
"."/[beaconstate, eth2_merkleization, helpers, validator, signatures]
from ./datatypes/capella import
BeaconState, MAX_WITHDRAWALS_PER_PAYLOAD, SignedBLSToExecutionChange
export extras, phase0, altair
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#block-header
@ -311,7 +314,7 @@ proc process_deposit*(cfg: RuntimeConfig,
static: doAssert state.balances.maxLen == state.validators.maxLen
raiseAssert "adding validator succeeded, so should balances"
when state is altair.BeaconState or state is bellatrix.BeaconState:
when state is altair.BeaconState or state is bellatrix.BeaconState or state is capella.BeaconState:
if not state.previous_epoch_participation.add(ParticipationFlags(0)):
return err("process_deposit: too many validators (previous_epoch_participation)")
if not state.current_epoch_participation.add(ParticipationFlags(0)):
@ -437,7 +440,7 @@ func get_proposer_reward*(participant_reward: Gwei): Gwei =
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#sync-committee-processing
proc process_sync_aggregate*(
state: var (altair.BeaconState | bellatrix.BeaconState),
state: var (altair.BeaconState | bellatrix.BeaconState | capella.BeaconState),
sync_aggregate: SomeSyncAggregate, total_active_balance: Gwei,
cache: var StateCache):
Result[void, cstring] =
@ -493,8 +496,8 @@ proc process_sync_aggregate*(
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#process_execution_payload
proc process_execution_payload*(
state: var bellatrix.BeaconState, payload: ExecutionPayload,
notify_new_payload: ExecutePayload): Result[void, cstring] =
state: var bellatrix.BeaconState, payload: bellatrix.ExecutionPayload,
notify_new_payload: bellatrix.ExecutePayload): Result[void, cstring] =
## Verify consistency of the parent hash with respect to the previous
## execution payload header
if is_merge_transition_complete(state):
@ -515,7 +518,7 @@ proc process_execution_payload*(
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = ExecutionPayloadHeader(
state.latest_execution_payload_header = bellatrix.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
@ -533,6 +536,107 @@ proc process_execution_payload*(
ok()
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#modified-process_execution_payload
proc process_execution_payload*(
state: var capella.BeaconState, payload: capella.ExecutionPayload,
notify_new_payload: capella.ExecutePayload): Result[void, cstring] =
## Verify consistency of the parent hash with respect to the previous
## execution payload header
if is_merge_transition_complete(state):
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = capella.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals)) # [New in Capella]
ok()
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
proc process_bls_to_execution_change*(
state: var capella.BeaconState,
signed_address_change: SignedBLSToExecutionChange): Result[void, cstring] =
let address_change = signed_address_change.message
if not (address_change.validator_index < state.validators.lenu64):
return err("process_bls_to_execution_change: invalid validator index")
var withdrawal_credentials =
state.validators.item(address_change.validator_index).withdrawal_credentials
if not (withdrawal_credentials.data[0] == BLS_WITHDRAWAL_PREFIX):
return err("process_bls_to_execution_change: invalid withdrawal prefix")
# TODO what's usual convention here re 32 hardcoded constant?
if not (withdrawal_credentials.data.toOpenArray(1, 31) ==
eth2digest(address_change.from_bls_pubkey.blob).data.toOpenArray(1, 31)):
return err("process_bls_to_execution_change: invalid withdrawal credentials")
if not verify_bls_to_execution_change_signature(
state.fork, state.genesis_validators_root, state.get_current_epoch,
signed_address_change, address_change.from_bls_pubkey,
signed_address_change.signature):
return err("process_bls_to_execution_change: invalid signature")
withdrawal_credentials.data[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX
withdrawal_credentials.data.fill(1, 11, 0)
withdrawal_credentials.data[12..31] =
address_change.to_execution_address.data
state.validators.mitem(address_change.validator_index).withdrawal_credentials =
withdrawal_credentials
ok()
# https://github.com/ethereum/consensus-specs/blob/53b63cedc586c3e1cc2ff737e85c1ed8a3eb45c6/specs/capella/beacon-chain.md#new-process_withdrawals
func process_withdrawals*(
state: var capella.BeaconState, payload: capella.ExecutionPayload):
Result[void, cstring] =
let
num_withdrawals =
min(MAX_WITHDRAWALS_PER_PAYLOAD, len(state.withdrawal_queue))
dequeued_withdrawals = state.withdrawal_queue.asSeq[0 ..< num_withdrawals]
if not (len(dequeued_withdrawals) == len(payload.withdrawals)):
return err("process_withdrawals: different numbers of dequeued and payload withdrawals")
for i in 0 ..< len(dequeued_withdrawals):
if not (dequeued_withdrawals[i] == payload.withdrawals[i]):
return err("process_withdrawals: mismatched queued and payload withdrawals")
# Remove dequeued withdrawals from state
if num_withdrawals > 0:
state.withdrawal_queue.asSeq.delete(0, num_withdrawals - 1)
state.withdrawal_queue.resetCache()
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
# copy of datatypes/phase0.nim
@ -597,7 +701,6 @@ proc process_block*(
if is_execution_enabled(state, blck.body):
? process_execution_payload(
state, blck.body.execution_payload,
# TODO this is enough to pass consensus spec tests
func(_: ExecutionPayload): bool = true)
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)

View File

@ -30,6 +30,8 @@ import
./datatypes/[phase0, altair, bellatrix],
"."/[beaconstate, eth2_merkleization, helpers, validator]
from ./datatypes/capella import BeaconState
export extras, phase0, altair
# Logging utilities
@ -173,7 +175,7 @@ func is_eligible_validator*(validator: ParticipationInfo): bool =
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_unslashed_participating_indices
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#get_total_balance
func get_unslashed_participating_balances*(
state: altair.BeaconState | bellatrix.BeaconState
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState
): UnslashedParticipatingBalances =
let
previous_epoch = get_previous_epoch(state)
@ -224,8 +226,8 @@ func get_unslashed_participating_balances*(
res
func is_unslashed_participating_index(
state: altair.BeaconState | bellatrix.BeaconState, flag_index: int, epoch: Epoch,
validator_index: ValidatorIndex): bool =
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState,
flag_index: int, epoch: Epoch, validator_index: ValidatorIndex): bool =
doAssert epoch in [get_previous_epoch(state), get_current_epoch(state)]
# TODO hoist this conditional
let epoch_participation =
@ -420,7 +422,7 @@ proc compute_unrealized_finality*(
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#justification-and-finalization
proc process_justification_and_finalization*(
state: var (altair.BeaconState | bellatrix.BeaconState),
state: var (altair.BeaconState | bellatrix.BeaconState | capella.BeaconState),
balances: UnslashedParticipatingBalances,
flags: UpdateFlags = {}) =
# Initial FFG checkpoint values have a `0x00` stub for `root`.
@ -624,8 +626,8 @@ func get_attestation_deltas(state: phase0.BeaconState, info: var phase0.EpochInf
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_base_reward
func get_base_reward_increment*(
state: altair.BeaconState | bellatrix.BeaconState, index: ValidatorIndex,
base_reward_per_increment: Gwei): Gwei =
state: altair.BeaconState | bellatrix.BeaconState | capella.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``.
let increments =
@ -633,10 +635,11 @@ func get_base_reward_increment*(
increments * base_reward_per_increment
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_flag_index_deltas
func get_flag_index_reward*(state: altair.BeaconState | bellatrix.BeaconState,
base_reward: Gwei, active_increments: Gwei,
unslashed_participating_increments: Gwei,
weight, finality_delay: uint64): Gwei =
func get_flag_index_reward*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState,
base_reward: Gwei, active_increments: Gwei,
unslashed_participating_increments: Gwei,
weight, finality_delay: uint64): Gwei =
if not is_in_inactivity_leak(finality_delay):
let reward_numerator =
base_reward * weight * unslashed_participating_increments
@ -655,10 +658,9 @@ func get_active_increments*(info: altair.EpochInfo | bellatrix.BeaconState): Gwe
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#get_flag_index_deltas
iterator get_flag_index_deltas*(
state: altair.BeaconState | bellatrix.BeaconState, flag_index: int,
base_reward_per_increment: Gwei,
info: var altair.EpochInfo,
finality_delay: uint64):
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState,
flag_index: int, base_reward_per_increment: Gwei,
info: var altair.EpochInfo, finality_delay: uint64):
(ValidatorIndex, RewardDelta) =
## Return the deltas for a given ``flag_index`` by scanning through the
## participation flags.
@ -722,8 +724,8 @@ iterator get_inactivity_penalty_deltas*(
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#modified-get_inactivity_penalty_deltas
iterator get_inactivity_penalty_deltas*(
cfg: RuntimeConfig, state: bellatrix.BeaconState, info: altair.EpochInfo):
(ValidatorIndex, Gwei) =
cfg: RuntimeConfig, state: bellatrix.BeaconState | capella.BeaconState,
info: altair.EpochInfo): (ValidatorIndex, Gwei) =
## Return the inactivity penalty deltas by considering timely target
## participation flags and inactivity scores.
let
@ -768,7 +770,7 @@ func process_rewards_and_penalties(
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#rewards-and-penalties
func process_rewards_and_penalties(
cfg: RuntimeConfig, state: var (altair.BeaconState | bellatrix.BeaconState),
cfg: RuntimeConfig, state: var (altair.BeaconState | bellatrix.BeaconState | capella.BeaconState),
info: var altair.EpochInfo)
=
if get_current_epoch(state) == GENESIS_EPOCH:
@ -868,6 +870,8 @@ func get_adjusted_total_slashing_balance*(
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
elif state is bellatrix.BeaconState:
PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX
elif state is capella.BeaconState:
PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX
else:
{.fatal: "process_slashings: incorrect BeaconState type".}
min(sum(state.slashings.data) * multiplier, total_balance)
@ -983,7 +987,8 @@ func process_participation_record_updates*(state: var phase0.BeaconState) =
swap(state.previous_epoch_attestations, state.current_epoch_attestations)
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#participation-flags-updates
func process_participation_flag_updates*(state: var (altair.BeaconState | bellatrix.BeaconState)) =
func process_participation_flag_updates*(
state: var (altair.BeaconState | bellatrix.BeaconState | capella.BeaconState)) =
state.previous_epoch_participation = state.current_epoch_participation
const zero = 0.ParticipationFlags
@ -998,7 +1003,7 @@ func process_participation_flag_updates*(state: var (altair.BeaconState | bellat
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#sync-committee-updates
func process_sync_committee_updates*(
state: var (altair.BeaconState | bellatrix.BeaconState)) =
state: var (altair.BeaconState | bellatrix.BeaconState | capella.BeaconState)) =
let next_epoch = get_current_epoch(state) + 1
if next_epoch.is_sync_committee_period():
state.current_sync_committee = state.next_sync_committee
@ -1006,7 +1011,8 @@ func process_sync_committee_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#inactivity-scores
func process_inactivity_updates*(
cfg: RuntimeConfig, state: var (altair.BeaconState | bellatrix.BeaconState),
cfg: RuntimeConfig,
state: var (altair.BeaconState | bellatrix.BeaconState | capella.BeaconState),
info: altair.EpochInfo) =
# Score updates based on previous epoch participation, skip genesis epoch
if get_current_epoch(state) == GENESIS_EPOCH:
@ -1076,7 +1082,7 @@ proc process_epoch*(
func init*(
info: var altair.EpochInfo,
state: altair.BeaconState | bellatrix.BeaconState) =
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState) =
# init participation, overwriting the full structure
info.balances = get_unslashed_participating_balances(state)
info.validators.setLen(state.validators.len())
@ -1092,7 +1098,8 @@ func init*(
)
func init*(
T: type altair.EpochInfo, state: altair.BeaconState | bellatrix.BeaconState): T =
T: type altair.EpochInfo,
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState): T =
init(result, state)
# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#epoch-processing

View File

@ -0,0 +1,17 @@
# beacon_chain
# Copyright (c) 2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
./test_fixture_fork,
./test_fixture_operations,
#./test_fixture_sanity_blocks, # TODO needs forked
#./test_fixture_sanity_slots, # TODO needs forked
./test_fixture_ssz_consensus_objects,
./test_fixture_state_transition_epoch
#./test_fixture_transition # TODO needs forked

View File

@ -0,0 +1,44 @@
# beacon_chain
# Copyright (c) 2021-2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
# Standard library
os,
# Beacon chain internals
../../../beacon_chain/spec/[beaconstate, helpers],
../../../beacon_chain/spec/datatypes/[bellatrix, capella],
# Test utilities
../../testutil,
../fixtures_utils,
../../helpers/debug_state
const OpForkDir = SszTestsDir/const_preset/"capella"/"fork"/"fork"/"pyspec_tests"
proc runTest(identifier: string) =
let testDir = OpForkDir / identifier
proc `testImpl _ fork _ identifier`() =
test identifier:
let
preState = newClone(
parseTest(testDir/"pre.ssz_snappy", SSZ, bellatrix.BeaconState))
postState = newClone(
parseTest(testDir/"post.ssz_snappy", SSZ, capella.BeaconState))
let cfg = defaultRuntimeConfig
let upgradedState = upgrade_to_capella(cfg, preState[])
check: upgradedState[].hash_tree_root() == postState[].hash_tree_root()
reportDiff(upgradedState, postState)
`testImpl _ fork _ identifier`()
suite "EF - Capella - Fork " & preset():
for kind, path in walkDir(OpForkDir, relative = true, checkDir = true):
runTest(path)

View File

@ -0,0 +1,207 @@
# beacon_chain
# Copyright (c) 2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
# Standard library
std/[os, sequtils, sets, strutils],
# Utilities
chronicles,
unittest2,
stew/results,
# Beacon chain internals
../../../beacon_chain/spec/[beaconstate, state_transition_block],
../../../beacon_chain/spec/datatypes/capella,
# Test utilities
../../testutil,
../fixtures_utils,
../../helpers/debug_state
const
OpDir = SszTestsDir/const_preset/"capella"/"operations"
OpAttestationsDir = OpDir/"attestation"
OpAttSlashingDir = OpDir/"attester_slashing"
OpBlockHeaderDir = OpDir/"block_header"
OpBlsToExecutionChangeDir = OpDir/"bls_to_execution_change"
OpDepositsDir = OpDir/"deposit"
OpExecutionPayloadDir = OpDir/"execution_payload"
OpProposerSlashingDir = OpDir/"proposer_slashing"
OpSyncAggregateDir = OpDir/"sync_aggregate"
OpVoluntaryExitDir = OpDir/"voluntary_exit"
OpWithdrawalsDir = OpDir/"withdrawals"
baseDescription = "EF - Capella - Operations - "
doAssert toHashSet(mapIt(toSeq(walkDir(OpDir, relative = false)), it.path)) ==
toHashSet([
OpAttestationsDir, OpAttSlashingDir, OpBlockHeaderDir,
OpBlsToExecutionChangeDir, OpDepositsDir, OpExecutionPayloadDir,
OpProposerSlashingDir, OpSyncAggregateDir, OpVoluntaryExitDir,
OpWithdrawalsDir])
proc runTest[T, U](
testSuiteDir: string, testSuiteName: string, applyFile: string,
applyProc: U, identifier: string) =
let testDir = testSuiteDir / "pyspec_tests" / identifier
proc testImpl() =
let prefix =
if fileExists(testDir/"post.ssz_snappy"):
"[Valid] "
else:
"[Invalid] "
test prefix & baseDescription & testSuiteName & " - " & identifier:
let preState = newClone(
parseTest(testDir/"pre.ssz_snappy", SSZ, capella.BeaconState))
let done = applyProc(
preState[], parseTest(testDir/(applyFile & ".ssz_snappy"), SSZ, T))
if fileExists(testDir/"post.ssz_snappy"):
let postState =
newClone(parseTest(
testDir/"post.ssz_snappy", SSZ, capella.BeaconState))
reportDiff(preState, postState)
check:
done.isOk()
preState[].hash_tree_root() == postState[].hash_tree_root()
else:
check: done.isErr() # No post state = processing should fail
testImpl()
suite baseDescription & "Attestation " & preset():
proc applyAttestation(
preState: var capella.BeaconState, attestation: Attestation):
Result[void, cstring] =
var cache = StateCache()
let
total_active_balance = get_total_active_balance(preState, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
process_attestation(
preState, attestation, {}, base_reward_per_increment, cache)
for path in walkTests(OpAttestationsDir):
runTest[Attestation, typeof applyAttestation](
OpAttestationsDir, "Attestation", "attestation", applyAttestation, path)
suite baseDescription & "Attester Slashing " & preset():
proc applyAttesterSlashing(
preState: var capella.BeaconState, attesterSlashing: AttesterSlashing):
Result[void, cstring] =
var cache = StateCache()
process_attester_slashing(
defaultRuntimeConfig, preState, attesterSlashing, {}, cache)
for path in walkTests(OpAttSlashingDir):
runTest[AttesterSlashing, typeof applyAttesterSlashing](
OpAttSlashingDir, "Attester Slashing", "attester_slashing",
applyAttesterSlashing, path)
suite baseDescription & "Block Header " & preset():
func applyBlockHeader(
preState: var capella.BeaconState, blck: capella.BeaconBlock):
Result[void, cstring] =
var cache = StateCache()
process_block_header(preState, blck, {}, cache)
for path in walkTests(OpBlockHeaderDir):
runTest[capella.BeaconBlock, typeof applyBlockHeader](
OpBlockHeaderDir, "Block Header", "block", applyBlockHeader, path)
suite baseDescription & "BLS to execution change " & preset():
proc applyBlsToExecutionChange(
preState: var capella.BeaconState,
signed_address_change: SignedBLSToExecutionChange):
Result[void, cstring] =
process_bls_to_execution_change(preState, signed_address_change)
for path in walkTests(OpBlsToExecutionChangeDir):
runTest[SignedBLSToExecutionChange, typeof applyBlsToExecutionChange](
OpBlsToExecutionChangeDir, "BLS to execution change", "address_change",
applyBlsToExecutionChange, path)
suite baseDescription & "Deposit " & preset():
proc applyDeposit(
preState: var capella.BeaconState, deposit: Deposit):
Result[void, cstring] =
process_deposit(defaultRuntimeConfig, preState, deposit, {})
for path in walkTests(OpDepositsDir):
runTest[Deposit, typeof applyDeposit](
OpDepositsDir, "Deposit", "deposit", applyDeposit, path)
suite baseDescription & "Execution Payload " & preset():
for path in walkTests(OpExecutionPayloadDir):
proc applyExecutionPayload(
preState: var capella.BeaconState,
executionPayload: capella.ExecutionPayload):
Result[void, cstring] =
let payloadValid =
readFile(OpExecutionPayloadDir/"pyspec_tests"/path/"execution.yaml").
contains("execution_valid: true")
func executePayload(_: capella.ExecutionPayload): bool = payloadValid
process_execution_payload(
preState, executionPayload, executePayload)
runTest[capella.ExecutionPayload, typeof applyExecutionPayload](
OpExecutionPayloadDir, "Execution Payload", "execution_payload",
applyExecutionPayload, path)
suite baseDescription & "Proposer Slashing " & preset():
proc applyProposerSlashing(
preState: var capella.BeaconState, proposerSlashing: ProposerSlashing):
Result[void, cstring] =
var cache = StateCache()
process_proposer_slashing(
defaultRuntimeConfig, preState, proposerSlashing, {}, cache)
for path in walkTests(OpProposerSlashingDir):
runTest[ProposerSlashing, typeof applyProposerSlashing](
OpProposerSlashingDir, "Proposer Slashing", "proposer_slashing",
applyProposerSlashing, path)
suite baseDescription & "Sync Aggregate " & preset():
proc applySyncAggregate(
preState: var capella.BeaconState, syncAggregate: SyncAggregate):
Result[void, cstring] =
var cache = StateCache()
process_sync_aggregate(
preState, syncAggregate, get_total_active_balance(preState, cache), cache)
for path in walkTests(OpSyncAggregateDir):
runTest[SyncAggregate, typeof applySyncAggregate](
OpSyncAggregateDir, "Sync Aggregate", "sync_aggregate",
applySyncAggregate, path)
suite baseDescription & "Voluntary Exit " & preset():
proc applyVoluntaryExit(
preState: var capella.BeaconState, voluntaryExit: SignedVoluntaryExit):
Result[void, cstring] =
var cache = StateCache()
process_voluntary_exit(
defaultRuntimeConfig, preState, voluntaryExit, {}, cache)
for path in walkTests(OpVoluntaryExitDir):
runTest[SignedVoluntaryExit, typeof applyVoluntaryExit](
OpVoluntaryExitDir, "Voluntary Exit", "voluntary_exit",
applyVoluntaryExit, path)
suite baseDescription & "Withdrawals " & preset():
proc applyWithdrawals(
preState: var capella.BeaconState,
executionPayload: capella.ExecutionPayload): Result[void, cstring] =
process_withdrawals(preState, executionPayload)
for path in walkTests(OpWithdrawalsDir):
runTest[capella.ExecutionPayload, typeof applyWithdrawals](
OpWithdrawalsDir, "Withdrawals", "execution_payload",
applyWithdrawals, path)

View File

@ -0,0 +1,85 @@
# beacon_chain
# Copyright (c) 2020-2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
# Standard library
std/os,
# Beacon chain internals
../../beacon_chain/spec/[beaconstate, validator, helpers, state_transition_epoch],
../../beacon_chain/spec/datatypes/[altair, capella],
# Test utilities
../../testutil,
../fixtures_utils
const
RewardsDirBase = SszTestsDir/const_preset/"capella"/"rewards"
RewardsDirBasic = RewardsDirBase/"basic"/"pyspec_tests"
RewardsDirLeak = RewardsDirBase/"leak"/"pyspec_tests"
RewardsDirRandom = RewardsDirBase/"random"/"pyspec_tests"
func init(T: type Deltas, len: int): T =
if not result.rewards.setLen(len):
raiseAssert "setLen"
if not result.penalties.setLen(len):
raiseAssert "setLen"
proc runTest(rewardsDir, identifier: string) =
let testDir = rewardsDir / identifier
proc `testImpl _ rewards _ identifier`() =
test "EF - Capella - Rewards - " & identifier & preset():
var info: altair.EpochInfo
let
state = newClone(
parseTest(testDir/"pre.ssz_snappy", SSZ, capella.BeaconState))
flagDeltas = [
parseTest(testDir/"source_deltas.ssz_snappy", SSZ, Deltas),
parseTest(testDir/"target_deltas.ssz_snappy", SSZ, Deltas),
parseTest(testDir/"head_deltas.ssz_snappy", SSZ, Deltas)]
inactivityPenaltyDeltas =
parseTest(testDir/"inactivity_penalty_deltas.ssz_snappy", SSZ, Deltas)
info.init(state[])
let
total_balance = info.balances.current_epoch
base_reward_per_increment = get_base_reward_per_increment(total_balance)
static: doAssert PARTICIPATION_FLAG_WEIGHTS.len == 3
var
flagDeltas2 = [
Deltas.init(state[].validators.len),
Deltas.init(state[].validators.len),
Deltas.init(state[].validators.len)]
inactivityPenaltyDeltas2 = Deltas.init(state[].validators.len)
let finality_delay = get_finality_delay(state[])
for flag_index in 0 ..< PARTICIPATION_FLAG_WEIGHTS.len:
for validator_index, delta in get_flag_index_deltas(
state[], flag_index, base_reward_per_increment, info, finality_delay):
if not is_eligible_validator(info.validators[validator_index]):
continue
flagDeltas2[flag_index].rewards[validator_index] = delta.rewards
flagDeltas2[flag_index].penalties[validator_index] = delta.penalties
for validator_index, delta in get_inactivity_penalty_deltas(
defaultRuntimeConfig, state[], info):
inactivityPenaltyDeltas2.penalties[validator_index] = delta
check:
flagDeltas == flagDeltas2
inactivityPenaltyDeltas == inactivityPenaltyDeltas2
`testImpl _ rewards _ identifier`()
suite "EF - Capella - Rewards " & preset():
for rewardsDir in [RewardsDirBasic, RewardsDirLeak, RewardsDirRandom]:
for kind, path in walkDir(rewardsDir, relative = true, checkDir = true):
runTest(rewardsDir, path)

View File

@ -0,0 +1,157 @@
# beacon_chain
# Copyright (c) 2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
# Standard library
os, strutils, streams, strformat,
macros, sets,
# Third-party
yaml,
# Beacon chain internals
../../beacon_chain/spec/datatypes/capella,
# Status libraries
snappy,
# Test utilities
../../testutil, ../fixtures_utils
from ../../beacon_chain/spec/datatypes/bellatrix import PowBlock
# SSZ tests of consensus objects (minimal/mainnet preset specific)
# Parsing definitions
# ----------------------------------------------------------------
const
SSZDir = SszTestsDir/const_preset/"capella"/"ssz_static"
type
SSZHashTreeRoot = object
# The test files have the values at the "root"
# so we **must** use "root" as a field name
root: string
# Some have a signing_root field
signing_root {.defaultVal: "".}: string
# Note this only tracks HashTreeRoot
# Checking the values against the yaml file is TODO (require more flexible Yaml parser)
proc checkSSZ(T: type capella.SignedBeaconBlock, dir: string, expectedHash: SSZHashTreeRoot) =
# Deserialize into a ref object to not fill Nim stack
let encoded = snappy.decode(
readFileBytes(dir/"serialized.ssz_snappy"), MaxObjectSize)
let deserialized = newClone(sszDecodeEntireInput(encoded, T))
# SignedBeaconBlocks usually not hashed because they're identified by
# htr(BeaconBlock), so do it manually
check: expectedHash.root == "0x" & toLowerAscii($hash_tree_root(
[hash_tree_root(deserialized.message),
hash_tree_root(deserialized.signature)]))
check deserialized.root == hash_tree_root(deserialized.message)
check SSZ.encode(deserialized[]) == encoded
check sszSize(deserialized[]) == encoded.len
# TODO check the value (requires YAML loader)
proc checkSSZ(T: type, dir: string, expectedHash: SSZHashTreeRoot) =
# Deserialize into a ref object to not fill Nim stack
let encoded = snappy.decode(
readFileBytes(dir/"serialized.ssz_snappy"), MaxObjectSize)
let deserialized = newClone(sszDecodeEntireInput(encoded, T))
check: expectedHash.root == "0x" & toLowerAscii($hash_tree_root(deserialized[]))
check SSZ.encode(deserialized[]) == encoded
check sszSize(deserialized[]) == encoded.len
# TODO check the value (requires YAML loader)
proc loadExpectedHashTreeRoot(dir: string): SSZHashTreeRoot =
let s = openFileStream(dir/"roots.yaml")
yaml.load(s, result)
s.close()
# Test runner
# ----------------------------------------------------------------
suite "EF - Capella - SSZ consensus objects " & preset():
doAssert dirExists(SSZDir), "You need to run the \"download_test_vectors.sh\" script to retrieve the consensus spec test vectors."
for pathKind, sszType in walkDir(SSZDir, relative = true, checkDir = true):
doAssert pathKind == pcDir
test &" Testing {sszType}":
let path = SSZDir/sszType
for pathKind, sszTestKind in walkDir(
path, relative = true, checkDir = true):
doAssert pathKind == pcDir
let path = SSZDir/sszType/sszTestKind
for pathKind, sszTestCase in walkDir(
path, relative = true, checkDir = true):
let path = SSZDir/sszType/sszTestKind/sszTestCase
let hash = loadExpectedHashTreeRoot(path)
case sszType:
of "AggregateAndProof": checkSSZ(AggregateAndProof, path, hash)
of "Attestation": checkSSZ(Attestation, path, hash)
of "AttestationData": checkSSZ(AttestationData, path, hash)
of "AttesterSlashing": checkSSZ(AttesterSlashing, path, hash)
of "BeaconBlock": checkSSZ(capella.BeaconBlock, path, hash)
of "BeaconBlockBody": checkSSZ(capella.BeaconBlockBody, path, hash)
of "BeaconBlockHeader": checkSSZ(BeaconBlockHeader, path, hash)
of "BeaconState": checkSSZ(capella.BeaconState, path, hash)
of "BLSToExecutionChange": checkSSZ(BLSToExecutionChange, path, hash)
of "Checkpoint": checkSSZ(Checkpoint, path, hash)
of "ContributionAndProof": checkSSZ(ContributionAndProof, path, hash)
of "Deposit": checkSSZ(Deposit, path, hash)
of "DepositData": checkSSZ(DepositData, path, hash)
of "DepositMessage": checkSSZ(DepositMessage, path, hash)
of "Eth1Block": checkSSZ(Eth1Block, path, hash)
of "Eth1Data": checkSSZ(Eth1Data, path, hash)
of "ExecutionPayload": checkSSZ(ExecutionPayload, path, hash)
of "ExecutionPayloadHeader":
checkSSZ(ExecutionPayloadHeader, path, hash)
of "Fork": checkSSZ(Fork, path, hash)
of "ForkData": checkSSZ(ForkData, path, hash)
of "HistoricalBatch": checkSSZ(HistoricalBatch, path, hash)
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
of "LightClientBootstrap":
checkSSZ(LightClientBootstrap, path, hash)
of "LightClientUpdate":
checkSSZ(LightClientUpdate, path, hash)
of "LightClientFinalityUpdate":
checkSSZ(LightClientFinalityUpdate, path, hash)
of "LightClientOptimisticUpdate":
checkSSZ(LightClientOptimisticUpdate, path, hash)
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
of "PowBlock": checkSSZ(PowBlock, path, hash)
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)
of "SignedAggregateAndProof":
checkSSZ(SignedAggregateAndProof, path, hash)
of "SignedBeaconBlock":
checkSSZ(capella.SignedBeaconBlock, path, hash)
of "SignedBeaconBlockHeader":
checkSSZ(SignedBeaconBlockHeader, path, hash)
of "SignedBLSToExecutionChange":
checkSSZ(SignedBLSToExecutionChange, path, hash)
of "SignedContributionAndProof":
checkSSZ(SignedContributionAndProof, path, hash)
of "SignedVoluntaryExit": checkSSZ(SignedVoluntaryExit, path, hash)
of "SigningData": checkSSZ(SigningData, path, hash)
of "SyncAggregate": checkSSZ(SyncAggregate, path, hash)
of "SyncAggregatorSelectionData":
checkSSZ(SyncAggregatorSelectionData, path, hash)
of "SyncCommittee": checkSSZ(SyncCommittee, path, hash)
of "SyncCommitteeContribution":
checkSSZ(SyncCommitteeContribution, path, hash)
of "SyncCommitteeMessage": checkSSZ(SyncCommitteeMessage, path, hash)
of "Withdrawal": checkSSZ(Withdrawal, path, hash)
of "Validator": checkSSZ(Validator, path, hash)
of "VoluntaryExit": checkSSZ(VoluntaryExit, path, hash)
else:
raise newException(ValueError, "Unsupported test: " & sszType)

View File

@ -0,0 +1,141 @@
# beacon_chain
# Copyright (c) 2018-2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
# Standard library
std/[os, strutils],
# Status internals
chronicles,
# Beacon chain internals
../../../beacon_chain/spec/[beaconstate, presets, state_transition_epoch],
../../../beacon_chain/spec/datatypes/[altair, capella],
# Test utilities
../../testutil,
../fixtures_utils,
./test_fixture_rewards,
../../helpers/debug_state
const RootDir = SszTestsDir/const_preset/"capella"/"epoch_processing"
template runSuite(
suiteDir, testName: string, transitionProc: untyped): untyped =
suite "EF - Capella - Epoch Processing - " & testName & preset():
for testDir in walkDirRec(suiteDir, yieldFilter = {pcDir}, checkDir = true):
let unitTestName = testDir.rsplit(DirSep, 1)[1]
test testName & " - " & unitTestName & preset():
# BeaconState objects are stored on the heap to avoid stack overflow
type T = capella.BeaconState
let preState {.inject.} = newClone(parseTest(testDir/"pre.ssz_snappy", SSZ, T))
var cache {.inject, used.} = StateCache()
template state: untyped {.inject, used.} = preState[]
template cfg: untyped {.inject, used.} = defaultRuntimeConfig
if transitionProc.isOk:
let postState =
newClone(parseTest(testDir/"post.ssz_snappy", SSZ, T))
check: hash_tree_root(preState[]) == hash_tree_root(postState[])
reportDiff(preState, postState)
else:
check: not fileExists(testDir/"post.ssz_snappy")
# Justification & Finalization
# ---------------------------------------------------------------
const JustificationFinalizationDir = RootDir/"justification_and_finalization"/"pyspec_tests"
runSuite(JustificationFinalizationDir, "Justification & Finalization"):
let info = altair.EpochInfo.init(state)
process_justification_and_finalization(state, info.balances)
Result[void, cstring].ok()
# Inactivity updates
# ---------------------------------------------------------------
const InactivityDir = RootDir/"inactivity_updates"/"pyspec_tests"
runSuite(InactivityDir, "Inactivity"):
let info = altair.EpochInfo.init(state)
process_inactivity_updates(cfg, state, info)
Result[void, cstring].ok()
# Rewards & Penalties
# ---------------------------------------------------------------
# in test_fixture_rewards
# Registry updates
# ---------------------------------------------------------------
const RegistryUpdatesDir = RootDir/"registry_updates"/"pyspec_tests"
runSuite(RegistryUpdatesDir, "Registry updates"):
process_registry_updates(cfg, state, cache)
# Slashings
# ---------------------------------------------------------------
const SlashingsDir = RootDir/"slashings"/"pyspec_tests"
runSuite(SlashingsDir, "Slashings"):
let info = altair.EpochInfo.init(state)
process_slashings(state, info.balances.current_epoch)
Result[void, cstring].ok()
# Eth1 data reset
# ---------------------------------------------------------------
const Eth1DataResetDir = RootDir/"eth1_data_reset/"/"pyspec_tests"
runSuite(Eth1DataResetDir, "Eth1 data reset"):
process_eth1_data_reset(state)
Result[void, cstring].ok()
# Effective balance updates
# ---------------------------------------------------------------
const EffectiveBalanceUpdatesDir = RootDir/"effective_balance_updates"/"pyspec_tests"
runSuite(EffectiveBalanceUpdatesDir, "Effective balance updates"):
process_effective_balance_updates(state)
Result[void, cstring].ok()
# Slashings reset
# ---------------------------------------------------------------
const SlashingsResetDir = RootDir/"slashings_reset"/"pyspec_tests"
runSuite(SlashingsResetDir, "Slashings reset"):
process_slashings_reset(state)
Result[void, cstring].ok()
# RANDAO mixes reset
# ---------------------------------------------------------------
const RandaoMixesResetDir = RootDir/"randao_mixes_reset"/"pyspec_tests"
runSuite(RandaoMixesResetDir, "RANDAO mixes reset"):
process_randao_mixes_reset(state)
Result[void, cstring].ok()
# Historical roots update
# ---------------------------------------------------------------
const HistoricalRootsUpdateDir = RootDir/"historical_roots_update"/"pyspec_tests"
runSuite(HistoricalRootsUpdateDir, "Historical roots update"):
process_historical_roots_update(state)
Result[void, cstring].ok()
# Participation flag updates
# ---------------------------------------------------------------
const ParticipationFlagDir = RootDir/"participation_flag_updates"/"pyspec_tests"
runSuite(ParticipationFlagDir, "Participation flag updates"):
process_participation_flag_updates(state)
Result[void, cstring].ok()
# Sync committee updates
# ---------------------------------------------------------------
# These are only for minimal, not mainnet
const SyncCommitteeDir = RootDir/"sync_committee_updates"/"pyspec_tests"
runSuite(SyncCommitteeDir, "Sync committee updates"):
process_sync_committee_updates(state)
Result[void, cstring].ok()