From 415b11aa67c18882a7fb1b8fd2243f74e636e50d Mon Sep 17 00:00:00 2001 From: tersec Date: Mon, 5 Dec 2022 21:36:53 +0000 Subject: [PATCH] EIP4844 tweaks to pass SSZ consensus object tests (#4390) --- ConsensusSpecPreset-mainnet.md | 52 +++++- ConsensusSpecPreset-minimal.md | 52 +++++- beacon_chain/consensus_object_pools/README.md | 2 +- .../consensus_object_pools/blockchain_dag.nim | 2 +- beacon_chain/gossip_processing/README.md | 4 +- .../gossip_processing/gossip_validation.nim | 18 +- beacon_chain/rpc/rest_config_api.nim | 2 +- beacon_chain/rpc/rest_validator_api.nim | 2 +- beacon_chain/spec/datatypes/altair.nim | 4 +- beacon_chain/spec/datatypes/bellatrix.nim | 2 +- beacon_chain/spec/datatypes/capella.nim | 6 +- beacon_chain/spec/datatypes/constants.nim | 2 +- beacon_chain/spec/datatypes/eip4844.nim | 101 +++++++++-- beacon_chain/spec/datatypes/phase0.nim | 2 +- .../spec/eth2_apis/rest_keymanager_types.nim | 2 +- beacon_chain/spec/eth2_ssz_serialization.nim | 8 + beacon_chain/spec/helpers.nim | 10 +- beacon_chain/spec/network.nim | 2 +- .../spec/presets/minimal/eip4844_preset.nim | 6 +- beacon_chain/spec/state_transition_block.nim | 2 +- beacon_chain/validators/validator_duties.nim | 2 +- docs/attestation_flow.md | 6 +- .../consensus_spec_tests_preset.nim | 1 + .../eip4844/all_eip4844_fixtures.nim | 17 ++ .../test_fixture_ssz_consensus_objects.nim | 162 ++++++++++++++++++ 25 files changed, 415 insertions(+), 54 deletions(-) create mode 100644 tests/consensus_spec/eip4844/all_eip4844_fixtures.nim create mode 100644 tests/consensus_spec/eip4844/test_fixture_ssz_consensus_objects.nim diff --git a/ConsensusSpecPreset-mainnet.md b/ConsensusSpecPreset-mainnet.md index df6d53152..3cdba252b 100644 --- a/ConsensusSpecPreset-mainnet.md +++ b/ConsensusSpecPreset-mainnet.md @@ -1516,6 +1516,56 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + Testing Withdrawal OK ``` OK: 44/44 Fail: 0/44 Skip: 0/44 +## EF - EIP4844 - SSZ consensus objects [Preset: mainnet] +```diff ++ Testing AggregateAndProof OK ++ Testing Attestation OK ++ Testing AttestationData OK ++ Testing AttesterSlashing OK ++ Testing BLSToExecutionChange OK ++ Testing BeaconBlock OK ++ Testing BeaconBlockBody OK ++ Testing BeaconBlockHeader OK ++ Testing BeaconState OK ++ Testing BlobsSidecar OK ++ Testing Checkpoint OK ++ Testing ContributionAndProof OK ++ Testing Deposit OK ++ Testing DepositData OK ++ Testing DepositMessage OK ++ Testing Eth1Block OK ++ Testing Eth1Data OK ++ Testing ExecutionPayload OK ++ Testing ExecutionPayloadHeader OK ++ Testing Fork OK ++ Testing ForkData OK ++ Testing HistoricalBatch OK ++ Testing IndexedAttestation OK ++ Testing LightClientBootstrap OK ++ Testing LightClientFinalityUpdate OK ++ Testing LightClientOptimisticUpdate OK ++ Testing LightClientUpdate OK ++ Testing PendingAttestation OK ++ Testing PowBlock OK ++ Testing ProposerSlashing OK ++ Testing SignedAggregateAndProof OK ++ Testing SignedBLSToExecutionChange OK ++ Testing SignedBeaconBlock OK ++ Testing SignedBeaconBlockAndBlobsSidecar OK ++ Testing SignedBeaconBlockHeader OK ++ Testing SignedContributionAndProof OK ++ Testing SignedVoluntaryExit OK ++ Testing SigningData OK ++ Testing SyncAggregate OK ++ Testing SyncAggregatorSelectionData OK ++ Testing SyncCommittee OK ++ Testing SyncCommitteeContribution OK ++ Testing SyncCommitteeMessage OK ++ Testing Validator OK ++ Testing VoluntaryExit OK ++ Testing Withdrawal OK +``` +OK: 46/46 Fail: 0/46 Skip: 0/46 ## EF - Phase 0 - Epoch Processing - Effective balance updates [Preset: mainnet] ```diff + Effective balance updates - effective_balance_hysteresis [Preset: mainnet] OK @@ -1937,4 +1987,4 @@ OK: 48/48 Fail: 0/48 Skip: 0/48 OK: 50/50 Fail: 0/50 Skip: 0/50 ---TOTAL--- -OK: 1691/1699 Fail: 0/1699 Skip: 8/1699 +OK: 1737/1745 Fail: 0/1745 Skip: 8/1745 diff --git a/ConsensusSpecPreset-minimal.md b/ConsensusSpecPreset-minimal.md index 38b1d56cd..a617f63b9 100644 --- a/ConsensusSpecPreset-minimal.md +++ b/ConsensusSpecPreset-minimal.md @@ -1642,6 +1642,56 @@ OK: 5/5 Fail: 0/5 Skip: 0/5 + Testing Withdrawal OK ``` OK: 44/44 Fail: 0/44 Skip: 0/44 +## EF - EIP4844 - SSZ consensus objects [Preset: minimal] +```diff ++ Testing AggregateAndProof OK ++ Testing Attestation OK ++ Testing AttestationData OK ++ Testing AttesterSlashing OK ++ Testing BLSToExecutionChange OK ++ Testing BeaconBlock OK ++ Testing BeaconBlockBody OK ++ Testing BeaconBlockHeader OK ++ Testing BeaconState OK ++ Testing BlobsSidecar OK ++ Testing Checkpoint OK ++ Testing ContributionAndProof OK ++ Testing Deposit OK ++ Testing DepositData OK ++ Testing DepositMessage OK ++ Testing Eth1Block OK ++ Testing Eth1Data OK ++ Testing ExecutionPayload OK ++ Testing ExecutionPayloadHeader OK ++ Testing Fork OK ++ Testing ForkData OK ++ Testing HistoricalBatch OK ++ Testing IndexedAttestation OK ++ Testing LightClientBootstrap OK ++ Testing LightClientFinalityUpdate OK ++ Testing LightClientOptimisticUpdate OK ++ Testing LightClientUpdate OK ++ Testing PendingAttestation OK ++ Testing PowBlock OK ++ Testing ProposerSlashing OK ++ Testing SignedAggregateAndProof OK ++ Testing SignedBLSToExecutionChange OK ++ Testing SignedBeaconBlock OK ++ Testing SignedBeaconBlockAndBlobsSidecar OK ++ Testing SignedBeaconBlockHeader OK ++ Testing SignedContributionAndProof OK ++ Testing SignedVoluntaryExit OK ++ Testing SigningData OK ++ Testing SyncAggregate OK ++ Testing SyncAggregatorSelectionData OK ++ Testing SyncCommittee OK ++ Testing SyncCommitteeContribution OK ++ Testing SyncCommitteeMessage OK ++ Testing Validator OK ++ Testing VoluntaryExit OK ++ Testing Withdrawal OK +``` +OK: 46/46 Fail: 0/46 Skip: 0/46 ## EF - Phase 0 - Epoch Processing - Effective balance updates [Preset: minimal] ```diff + Effective balance updates - effective_balance_hysteresis [Preset: minimal] OK @@ -2078,4 +2128,4 @@ OK: 52/52 Fail: 0/52 Skip: 0/52 OK: 51/51 Fail: 0/51 Skip: 0/51 ---TOTAL--- -OK: 1820/1828 Fail: 0/1828 Skip: 8/1828 +OK: 1866/1874 Fail: 0/1874 Skip: 8/1874 diff --git a/beacon_chain/consensus_object_pools/README.md b/beacon_chain/consensus_object_pools/README.md index 0a029a566..c177ad3bf 100644 --- a/beacon_chain/consensus_object_pools/README.md +++ b/beacon_chain/consensus_object_pools/README.md @@ -4,7 +4,7 @@ This folder holds the various consensus object pools needed for a blockchain cli Object in those pools have passed the "gossip validation" filter according to specs: -- blocks: https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#beacon_block +- blocks: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#beacon_block - aggregate attestations: https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof - unaggregated attestation: https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.2/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id - voluntary exits: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#voluntary_exit diff --git a/beacon_chain/consensus_object_pools/blockchain_dag.nim b/beacon_chain/consensus_object_pools/blockchain_dag.nim index 0b48c1a00..d39e99ce9 100644 --- a/beacon_chain/consensus_object_pools/blockchain_dag.nim +++ b/beacon_chain/consensus_object_pools/blockchain_dag.nim @@ -665,7 +665,7 @@ proc getStateByParent( dag: ChainDAGRef, bid: BlockId, state: var ForkedHashedBeaconState): bool = ## Try to load the state referenced by the parent of the given `bid` - this ## state can be used to advance to the `bid` state itself. - var slot = bid.slot + let slot = bid.slot let summary = dag.db.getBeaconBlockSummary(bid.root).valueOr: diff --git a/beacon_chain/gossip_processing/README.md b/beacon_chain/gossip_processing/README.md index 6413e7bc4..85340cf83 100644 --- a/beacon_chain/gossip_processing/README.md +++ b/beacon_chain/gossip_processing/README.md @@ -9,9 +9,9 @@ This folder holds a collection of modules to: Gossip validation is different from consensus verification in particular for blocks. -- Blocks: https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#beacon_block +- Blocks: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#beacon_block - Attestations (aggregated): https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof -- Attestations (unaggregated): https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.2/specs/phase0/p2p-interface.md#attestation-subnets +- Attestations (unaggregated): https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#attestation-subnets - Voluntary exits: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#voluntary_exit - Proposer slashings: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#proposer_slashing - Attester slashing: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#attester_slashing diff --git a/beacon_chain/gossip_processing/gossip_validation.nim b/beacon_chain/gossip_processing/gossip_validation.nim index e6db20635..821f68265 100644 --- a/beacon_chain/gossip_processing/gossip_validation.nim +++ b/beacon_chain/gossip_processing/gossip_validation.nim @@ -180,7 +180,7 @@ template validateBeaconBlockBellatrix( parent: BlockRef): untyped = discard -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/bellatrix/p2p-interface.md#beacon_block +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/bellatrix/p2p-interface.md#beacon_block template validateBeaconBlockBellatrix( signed_beacon_block: bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock, parent: BlockRef): untyped = @@ -532,7 +532,7 @@ proc validateAttestation*( let (cryptoFut, sig) = deferredCrypto.get() # Await the crypto check - var x = (await cryptoFut) + let x = (await cryptoFut) case x of BatchResult.Invalid: return checkedReject("Attestation: invalid signature") @@ -702,7 +702,7 @@ proc validateAggregate*( block: # [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid. - var x = await aggregatorFut + let x = await aggregatorFut case x of BatchResult.Invalid: return checkedReject("Aggregate: invalid aggregator signature") @@ -714,7 +714,7 @@ proc validateAggregate*( block: # [REJECT] aggregate_and_proof.selection_proof - var x = await slotFut + let x = await slotFut case x of BatchResult.Invalid: return checkedReject("Aggregate: invalid slot signature") @@ -726,7 +726,7 @@ proc validateAggregate*( block: # [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid. - var x = await aggregateFut + let x = await aggregateFut case x of BatchResult.Invalid: return checkedReject("Aggregate: invalid aggregate signature") @@ -903,7 +903,7 @@ proc validateSyncCommitteeMessage*( let (cryptoFut, sig) = deferredCrypto.get() - var x = (await cryptoFut) + let x = (await cryptoFut) case x of BatchResult.Invalid: return errReject("SyncCommitteeMessage: invalid signature") @@ -1000,7 +1000,7 @@ proc validateContribution*( block: # [REJECT] The aggregator signature, signed_contribution_and_proof.signature, is valid - var x = await aggregatorFut + let x = await aggregatorFut case x of BatchResult.Invalid: return errReject("SignedContributionAndProof: invalid aggregator signature") @@ -1011,7 +1011,7 @@ proc validateContribution*( discard block: - var x = await proofFut + let x = await proofFut case x of BatchResult.Invalid: return errReject("SignedContributionAndProof: invalid proof") @@ -1023,7 +1023,7 @@ proc validateContribution*( block: # [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid. - var x = await contributionFut + let x = await contributionFut case x of BatchResult.Invalid: return errReject("SignedContributionAndProof: invalid contribution signature") diff --git a/beacon_chain/rpc/rest_config_api.nim b/beacon_chain/rpc/rest_config_api.nim index 33332634f..85b0239da 100644 --- a/beacon_chain/rpc/rest_config_api.nim +++ b/beacon_chain/rpc/rest_config_api.nim @@ -246,7 +246,7 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) = ATTESTATION_SUBNET_COUNT: Base10.toString(ATTESTATION_SUBNET_COUNT), - # https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/validator.md#constants + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/validator.md#constants TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE: Base10.toString(uint64(TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE)), SYNC_COMMITTEE_SUBNET_COUNT: diff --git a/beacon_chain/rpc/rest_validator_api.nim b/beacon_chain/rpc/rest_validator_api.nim index d06d2a6d1..a0dcacb18 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -562,7 +562,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) = dres.get() # Since our validation logic supports batch processing, we will submit all # aggregated attestations for validation. - var pending = + let pending = block: var res: seq[Future[SendResult]] for proof in proofs: diff --git a/beacon_chain/spec/datatypes/altair.nim b/beacon_chain/spec/datatypes/altair.nim index 4dd38d8b3..82bba71fc 100644 --- a/beacon_chain/spec/datatypes/altair.nim +++ b/beacon_chain/spec/datatypes/altair.nim @@ -5,7 +5,7 @@ # * 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 altair (ie known to have changed across hard forks) - see +# Types specific to altair (i.e. 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 @@ -45,7 +45,7 @@ const TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE* = 16 SYNC_COMMITTEE_SUBNET_COUNT* = 4 - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/light-client/sync-protocol.md#constants + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/sync-protocol.md#constants # All of these indices are rooted in `BeaconState`. # The first member (`genesis_time`) is 32, subsequent members +1 each. # If there are ever more than 32 members in `BeaconState`, indices change! diff --git a/beacon_chain/spec/datatypes/bellatrix.nim b/beacon_chain/spec/datatypes/bellatrix.nim index 70afe5955..fe521f48f 100644 --- a/beacon_chain/spec/datatypes/bellatrix.nim +++ b/beacon_chain/spec/datatypes/bellatrix.nim @@ -5,7 +5,7 @@ # * 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 bellatrix (ie known to have changed across hard forks) - see +# Types specific to bellatrix (i.e. 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 diff --git a/beacon_chain/spec/datatypes/capella.nim b/beacon_chain/spec/datatypes/capella.nim index 931532590..2a6304be4 100644 --- a/beacon_chain/spec/datatypes/capella.nim +++ b/beacon_chain/spec/datatypes/capella.nim @@ -5,7 +5,7 @@ # * 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 +# Types specific to capella (i.e. 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 @@ -48,7 +48,7 @@ type message*: BLSToExecutionChange signature*: ValidatorSig - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/capella/beacon-chain.md#executionpayload + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/capella/beacon-chain.md#executionpayload ExecutionPayload* = object parent_hash*: Eth2Digest fee_recipient*: ExecutionAddress # 'beneficiary' in the yellow paper @@ -68,7 +68,7 @@ type transactions*: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] withdrawals*: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] # [New in Capella] - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/capella/beacon-chain.md#executionpayloadheader + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/capella/beacon-chain.md#executionpayloadheader ExecutionPayloadHeader* = object parent_hash*: Eth2Digest fee_recipient*: ExecutionAddress diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index 687df7116..4e1a03343 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -36,7 +36,7 @@ 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/v1.3.0-alpha.0/specs/capella/beacon-chain.md#domain-types + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/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.3.0-alpha.1/specs/bellatrix/beacon-chain.md#transition-settings diff --git a/beacon_chain/spec/datatypes/eip4844.nim b/beacon_chain/spec/datatypes/eip4844.nim index b52f56e91..ddeab8c03 100644 --- a/beacon_chain/spec/datatypes/eip4844.nim +++ b/beacon_chain/spec/datatypes/eip4844.nim @@ -5,7 +5,7 @@ # * 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 +# Types specific to eip4844 (i.e. 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 @@ -26,15 +26,18 @@ import export json_serialization, base +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/eip4844/polynomial-commitments.md#constants +const BYTES_PER_FIELD_ELEMENT = 32 + type # this block belongs elsewhere - will figure out after implementing c-kzg bindings KZGCommitment* = array[48, byte] KZGProof* = array[48, byte] BLSFieldElement* = array[32, byte] - Blob* = List[BLSFieldElement, Limit FIELD_ELEMENTS_PER_BLOB] + Blob* = array[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB, byte] - BlobsSideCar* = object + BlobsSidecar* = object beacon_block_root*: Eth2Digest beacon_block_slot*: Slot blobs*: List[Blob, Limit MAX_BLOBS_PER_BLOCK] @@ -44,7 +47,7 @@ type beacon_block*: SignedBeaconBlock blobs_sidecar*: BlobsSidecar - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/eip4844/beacon-chain.md#executionpayload + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/eip4844/beacon-chain.md#executionpayload ExecutionPayload* = object parent_hash*: Eth2Digest fee_recipient*: ExecutionAddress # 'beneficiary' in the yellow paper @@ -65,7 +68,7 @@ type transactions*: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] withdrawals*: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/eip4844/beacon-chain.md#executionpayloadheader + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/eip4844/beacon-chain.md#executionpayloadheader ExecutionPayloadHeader* = object parent_hash*: Eth2Digest fee_recipient*: ExecutionAddress @@ -89,7 +92,80 @@ type ExecutePayload* = proc( execution_payload: ExecutionPayload): bool {.gcsafe, raises: [Defect].} - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/beacon-chain.md#beaconblock + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/capella/beacon-chain.md#beaconstate + # changes indirectly via ExecutionPayloadHeader + 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] + + # Light client sync committees + current_sync_committee*: SyncCommittee + next_sync_committee*: SyncCommittee + + # Execution + latest_execution_payload_header*: ExecutionPayloadHeader + + # Withdrawals + next_withdrawal_index*: WithdrawalIndex # [New in Capella] + next_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.3.0-alpha.1/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 @@ -146,7 +222,7 @@ type state_root*: Eth2Digest body*: TrustedBeaconBlockBody - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/capella/beacon-chain.md#beaconblockbody + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/eip4844/beacon-chain.md#beaconblockbody BeaconBlockBody* = object randao_reveal*: ValidatorSig eth1_data*: Eth1Data @@ -166,9 +242,8 @@ type # Execution execution_payload*: ExecutionPayload - - # Capella operations bls_to_execution_changes*: SignedBLSToExecutionChangeList + blob_kzg_commitments*: List[KZGCommitment, Limit MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] SigVerifiedBeaconBlockBody* = object ## A BeaconBlock body with signatures verified @@ -202,9 +277,8 @@ type # Execution execution_payload*: ExecutionPayload - - # Capella operations bls_to_execution_changes*: SignedBLSToExecutionChangeList + blob_kzg_commitments*: List[KZGCommitment, Limit MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] TrustedBeaconBlockBody* = object ## A full verified block @@ -226,11 +300,10 @@ type # Execution execution_payload*: ExecutionPayload - - # Capella operations bls_to_execution_changes*: SignedBLSToExecutionChangeList + blob_kzg_commitments*: List[KZGCommitment, Limit MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] - # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/beacon-chain.md#signedbeaconblock + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/beacon-chain.md#signedbeaconblock SignedBeaconBlock* = object message*: BeaconBlock signature*: ValidatorSig diff --git a/beacon_chain/spec/datatypes/phase0.nim b/beacon_chain/spec/datatypes/phase0.nim index 3bff280c4..b250aabdb 100644 --- a/beacon_chain/spec/datatypes/phase0.nim +++ b/beacon_chain/spec/datatypes/phase0.nim @@ -5,7 +5,7 @@ # * 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 phase0 (ie known to have changed across hard forks) - see +# Types specific to phase0 (i.e. 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 diff --git a/beacon_chain/spec/eth2_apis/rest_keymanager_types.nim b/beacon_chain/spec/eth2_apis/rest_keymanager_types.nim index caae1a9d7..b356e661b 100644 --- a/beacon_chain/spec/eth2_apis/rest_keymanager_types.nim +++ b/beacon_chain/spec/eth2_apis/rest_keymanager_types.nim @@ -90,7 +90,7 @@ type proc `<`*(x, y: KeystoreInfo | RemoteKeystoreInfo): bool = for a, b in fields(x, y): - var c = cmp(a, b) + let c = cmp(a, b) if c < 0: return true if c > 0: return false return false diff --git a/beacon_chain/spec/eth2_ssz_serialization.nim b/beacon_chain/spec/eth2_ssz_serialization.nim index 2ae8c726c..a9486af9b 100644 --- a/beacon_chain/spec/eth2_ssz_serialization.nim +++ b/beacon_chain/spec/eth2_ssz_serialization.nim @@ -19,6 +19,8 @@ import ./datatypes/[phase0, altair, bellatrix, capella], ./eth2_merkleization +from ./datatypes/eip4844 import SignedBeaconBlock, TrustedSignedBeaconBlock + export phase0, altair, ssz_codec, ssz_serialization, eth2_merkleization proc readAndUpdateRoot(data: openArray[byte], val: var auto, updateRoot = true) {. @@ -54,6 +56,12 @@ template readSszBytes*( template readSszBytes*( data: openArray[byte], val: var capella.TrustedSignedBeaconBlock, updateRoot = true) = readAndUpdateRoot(data, val, updateRoot) +template readSszBytes*( + data: openArray[byte], val: var eip4844.SignedBeaconBlock, updateRoot = true) = + readAndUpdateRoot(data, val, updateRoot) +template readSszBytes*( + data: openArray[byte], val: var eip4844.TrustedSignedBeaconBlock, updateRoot = true) = + readAndUpdateRoot(data, val, updateRoot) template readSszBytes*( data: openArray[byte], val: var auto, updateRoot: bool) = diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index 6324e2b84..79203b912 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -310,13 +310,13 @@ template is_better_update*[A, B: SomeLightClientUpdate]( new_update: A, old_update: B): bool = is_better_data(toMeta(new_update), toMeta(old_update)) -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/light-client/p2p-interface.md#getlightclientbootstrap +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/p2p-interface.md#getlightclientbootstrap func contextEpoch*(bootstrap: altair.LightClientBootstrap): Epoch = bootstrap.header.slot.epoch -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/light-client/p2p-interface.md#lightclientupdatesbyrange -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/light-client/p2p-interface.md#getlightclientfinalityupdate -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/light-client/p2p-interface.md#getlightclientoptimisticupdate +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/p2p-interface.md#lightclientupdatesbyrange +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/p2p-interface.md#getlightclientfinalityupdate +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/p2p-interface.md#getlightclientoptimisticupdate func contextEpoch*(update: SomeLightClientUpdate): Epoch = update.attested_header.slot.epoch @@ -347,7 +347,7 @@ func is_merge_transition_block( not is_merge_transition_complete(state) and body.execution_payload != defaultExecutionPayload -# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#is_execution_enabled +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/bellatrix/beacon-chain.md#is_execution_enabled func is_execution_enabled*( state: bellatrix.BeaconState | capella.BeaconState, body: bellatrix.BeaconBlockBody | bellatrix.TrustedBeaconBlockBody | diff --git a/beacon_chain/spec/network.nim b/beacon_chain/spec/network.nim index 7541e155c..ce2d35111 100644 --- a/beacon_chain/spec/network.nim +++ b/beacon_chain/spec/network.nim @@ -107,7 +107,7 @@ func getLightClientFinalityUpdateTopic*(forkDigest: ForkDigest): string = ## For broadcasting or obtaining the latest `LightClientFinalityUpdate`. eth2Prefix(forkDigest) & "light_client_finality_update/ssz_snappy" -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/light-client/p2p-interface.md#light_client_optimistic_update +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/p2p-interface.md#light_client_optimistic_update func getLightClientOptimisticUpdateTopic*(forkDigest: ForkDigest): string = ## For broadcasting or obtaining the latest `LightClientOptimisticUpdate`. eth2Prefix(forkDigest) & "light_client_optimistic_update/ssz_snappy" diff --git a/beacon_chain/spec/presets/minimal/eip4844_preset.nim b/beacon_chain/spec/presets/minimal/eip4844_preset.nim index 1cacd23d3..08a9e7db0 100644 --- a/beacon_chain/spec/presets/minimal/eip4844_preset.nim +++ b/beacon_chain/spec/presets/minimal/eip4844_preset.nim @@ -1,7 +1,7 @@ # Minimal preset - EIP-4844 -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/presets/mainnet/eip4844.yaml +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/presets/minimal/eip4844.yaml const - # `uint64(4096)` - FIELD_ELEMENTS_PER_BLOB*: uint64 = 4096 + # [customized] + FIELD_ELEMENTS_PER_BLOB*: uint64 = 4 # `uint64(2**4)` (= 16) MAX_BLOBS_PER_BLOCK*: uint64 = 16 diff --git a/beacon_chain/spec/state_transition_block.nim b/beacon_chain/spec/state_transition_block.nim index 4a039d5c7..41559425d 100644 --- a/beacon_chain/spec/state_transition_block.nim +++ b/beacon_chain/spec/state_transition_block.nim @@ -394,7 +394,7 @@ proc process_voluntary_exit*( ? initiate_validator_exit(cfg, state, exited_validator, cache) ok() -# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/capella/beacon-chain.md#new-process_bls_to_execution_change +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/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] = diff --git a/beacon_chain/validators/validator_duties.nim b/beacon_chain/validators/validator_duties.nim index a9f26f3bd..3f6e11dbd 100644 --- a/beacon_chain/validators/validator_duties.nim +++ b/beacon_chain/validators/validator_duties.nim @@ -310,7 +310,7 @@ proc getBlockProposalEth1Data*(node: BeaconNode, state: ForkedHashedBeaconState): BlockProposalEth1Data = if node.eth1Monitor.isNil: - var pendingDepositsCount = + let pendingDepositsCount = getStateField(state, eth1_data).deposit_count - getStateField(state, eth1_deposit_index) if pendingDepositsCount > 0: diff --git a/docs/attestation_flow.md b/docs/attestation_flow.md index 24f40a804..aaf9ecee2 100644 --- a/docs/attestation_flow.md +++ b/docs/attestation_flow.md @@ -6,7 +6,7 @@ This is a WIP document to explain the attestation flows. It is important to distinguish attestation `validation` from attestation `verification`. - Attestation `validation` is defined in the P2P specs. Validated attestations can be forwarded on GossipSub. - - Aggregated: https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof + - Aggregated: https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof - Unaggregated: https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.2/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id - Attestation `verification` is defined in the consensus specs. Verified attestations can affect fork choice and may be included in a block. - https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/beacon-chain.md#attestations @@ -51,8 +51,8 @@ These GossipSub topics are used to listen for attestations: - Unaggregated: `/eth2/{$forkDigest}/beacon_attestation_{subnetIndex}/ssz_snappy` The attestations are then validated by `validateAttestation()` or `validateAggregate()` in either `attestationValidator()` or `aggregateValidator()` according to the P2P specs. -- https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof -- https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.2/specs/phase0/p2p-interface.md#attestation-subnets +- https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof +- https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/phase0/p2p-interface.md#attestation-subnets Finally, valid attestations are added to the local `attestationPool`. Attestations are dropped in case of an error. diff --git a/tests/consensus_spec/consensus_spec_tests_preset.nim b/tests/consensus_spec/consensus_spec_tests_preset.nim index 2e047ec40..a8a393c1f 100644 --- a/tests/consensus_spec/consensus_spec_tests_preset.nim +++ b/tests/consensus_spec/consensus_spec_tests_preset.nim @@ -15,6 +15,7 @@ import ./altair/all_altair_fixtures, ./bellatrix/all_bellatrix_fixtures, ./capella/all_capella_fixtures, + ./eip4844/all_eip4844_fixtures, ./test_fixture_fork_choice, ./test_fixture_light_client_single_merkle_proof, ./test_fixture_light_client_sync, diff --git a/tests/consensus_spec/eip4844/all_eip4844_fixtures.nim b/tests/consensus_spec/eip4844/all_eip4844_fixtures.nim new file mode 100644 index 000000000..d5dfdea62 --- /dev/null +++ b/tests/consensus_spec/eip4844/all_eip4844_fixtures.nim @@ -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, + #./test_fixture_sanity_slots, + ./test_fixture_ssz_consensus_objects + #./test_fixture_state_transition_epoch, + #./test_fixture_transition diff --git a/tests/consensus_spec/eip4844/test_fixture_ssz_consensus_objects.nim b/tests/consensus_spec/eip4844/test_fixture_ssz_consensus_objects.nim new file mode 100644 index 000000000..b34d8c9d5 --- /dev/null +++ b/tests/consensus_spec/eip4844/test_fixture_ssz_consensus_objects.nim @@ -0,0 +1,162 @@ +# 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/eip4844, + # Status libraries + snappy, + # Test utilities + ../../testutil, ../fixtures_utils + +from ../../beacon_chain/spec/datatypes/bellatrix import PowBlock +from ../../beacon_chain/spec/datatypes/capella import + BLSToExecutionChange, SignedBLSToExecutionChange, Withdrawal + +# SSZ tests of consensus objects (minimal/mainnet preset specific) + +# Parsing definitions +# ---------------------------------------------------------------- + +const + SSZDir = SszTestsDir/const_preset/"eip4844"/"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 eip4844.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 - EIP4844 - 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(eip4844.BeaconBlock, path, hash) + of "BeaconBlockBody": checkSSZ(eip4844.BeaconBlockBody, path, hash) + of "BeaconBlockHeader": checkSSZ(BeaconBlockHeader, path, hash) + of "BeaconState": checkSSZ(eip4844.BeaconState, path, hash) + of "BlobsSidecar": checkSSZ(BlobsSidecar, 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(eip4844.SignedBeaconBlock, path, hash) + of "SignedBeaconBlockAndBlobsSidecar": + checkSSZ(eip4844.SignedBeaconBlockAndBlobsSidecar, 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)