diff --git a/.bazelrc b/.bazelrc index 4ff0eba34949..67b397ae65bf 100644 --- a/.bazelrc +++ b/.bazelrc @@ -24,6 +24,11 @@ build --workspace_status_command=./hack/workspace_status.sh build --define blst_disabled=false run --define blst_disabled=false +# SSZ progressive merkleization is ON by default: gloas (EIP-7688) mandates it +# and the consensus-spec fixtures expect the progressive hash_tree_root values. +# Pass --//tools:disable_progressive_merkleization to build/test the bounded +# form instead. See //tools:BUILD.bazel. + build:blst_disabled --define blst_disabled=true build:blst_disabled --define gotags=blst_disabled diff --git a/.ethspecify.yml b/.ethspecify.yml index b04bd210c853..d0205f6b196a 100644 --- a/.ethspecify.yml +++ b/.ethspecify.yml @@ -1,4 +1,4 @@ -version: v1.7.0-alpha.11 +version: v1.7.0-alpha.14 style: full specrefs: @@ -18,7 +18,6 @@ specrefs: exceptions: presets: # gloas - - BUILDER_PENDING_WITHDRAWALS_LIMIT#gloas - MAX_PAYLOAD_ATTESTATIONS#gloas - PTC_SIZE#gloas @@ -41,19 +40,8 @@ exceptions: - PAYLOAD_STATUS_VALID#bellatrix - SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY#bellatrix # deneb - - BLS_MODULUS#deneb - - BYTES_PER_COMMITMENT#deneb - BYTES_PER_FIELD_ELEMENT#deneb - - BYTES_PER_PROOF#deneb - - FIAT_SHAMIR_PROTOCOL_DOMAIN#deneb - - G1_POINT_AT_INFINITY#deneb - G2_POINT_AT_INFINITY#deneb - - KZG_ENDIANNESS#deneb - - KZG_SETUP_G2_LENGTH#deneb - - KZG_SETUP_G2_MONOMIAL#deneb - - PRIMITIVE_ROOT_OF_UNITY#deneb - - RANDOM_CHALLENGE_KZG_BATCH_DOMAIN#deneb - - RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN#fulu # fulu - UINT256_MAX#fulu # gloas @@ -93,13 +81,16 @@ exceptions: - HEZE_FORK_EPOCH#heze - HEZE_FORK_VERSION#heze - INCLUSION_LIST_DUE_BPS#heze - - MAX_BYTES_PER_INCLUSION_LIST#heze + - MAX_TRANSACTIONS_BYTES_PER_INCLUSION_LIST#heze - MAX_REQUEST_INCLUSION_LIST#heze + - MIN_SLOTS_FOR_INCLUSION_LISTS_REQUESTS#heze + - GAS_LIMIT_SCHEDULE#gloas ssz_objects: # phase0 - Eth1Block#phase0 # fulu + - PartialDataColumnGroupID#fulu - PartialDataColumnHeader#fulu - PartialDataColumnPartsMetadata#fulu - PartialDataColumnSidecar#fulu @@ -144,6 +135,128 @@ exceptions: - BuilderDepositRequest#gloas - BuilderExitRequest#gloas - ExecutionRequests#gloas + - AggregationBits#electra + - AggregationBits#gloas + - AggregationBits#phase0 + - Attestations#electra + - Attestations#gloas + - Attestations#phase0 + - AttesterSlashings#electra + - AttesterSlashings#gloas + - AttesterSlashings#phase0 + - AttestingIndices#electra + - AttestingIndices#gloas + - AttestingIndices#phase0 + - Attnets#phase0 + - BLSToExecutionChanges#capella + - BLSToExecutionChanges#gloas + - Balances#gloas + - Balances#phase0 + - BeaconBlockRoots#deneb + - BeaconBlockRoots#phase0 + - Blob#deneb + - BlobKZGCommitments#deneb + - BlobKZGCommitments#gloas + - Blobs#deneb + - BlockAccessList#gloas + - BlockRoots#phase0 + - BuilderDepositRequests#gloas + - BuilderExitRequests#gloas + - BuilderPendingPayments#gloas + - BuilderPendingWithdrawals#gloas + - Builders#gloas + - Cell#fulu + - CellKZGProofs#fulu + - Cells#fulu + - CellsBitList#fulu + - CellsBitList#gloas + - CommitteeBits#electra + - ConsolidationRequests#electra + - ConsolidationRequests#gloas + - CurrentSyncCommitteeBranch#altair + - CurrentSyncCommitteeBranch#electra + - CurrentSyncCommitteeBranch#gloas + - CustodyColumnBits#gloas + - DataColumn#fulu + - DataColumn#gloas + - DataColumnIndices#fulu + - DataColumnsByRootIdentifiers#fulu + - DepositDataList#phase0 + - DepositProof#phase0 + - DepositRequests#electra + - DepositRequests#gloas + - Deposits#gloas + - Deposits#phase0 + - EpochParticipation#altair + - EpochParticipation#gloas + - ErrorMessage#phase0 + - Eth1DataVotes#phase0 + - ExecutionBranch#capella + - ExecutionBranch#gloas + - ExecutionPayloadAvailability#gloas + - ExecutionPayloadEnvelopeRoots#gloas + - ExtraData#bellatrix + - FinalityBranch#altair + - FinalityBranch#electra + - FinalityBranch#gloas + - HistoricalRoots#phase0 + - HistoricalSummaries#capella + - InactivityScores#altair + - InactivityScores#gloas + - InclusionListBits#heze + - InclusionListCommittee#heze + - JustificationBits#phase0 + - KZGCommitmentInclusionProof#deneb + - KZGCommitmentsInclusionProof#fulu + - KZGProofs#deneb + - KZGProofs#gloas + - LightClientUpdates#altair + - LogsBloom#bellatrix + - NextSyncCommitteeBranch#altair + - NextSyncCommitteeBranch#electra + - NextSyncCommitteeBranch#gloas + - OptionalPartialDataColumnHeader#fulu + - PTC#gloas + - PTCAttestingIndices#gloas + - PTCBits#gloas + - PTCWindow#gloas + - PartialDataColumnPartsMetadata#gloas + - PayloadAttestations#gloas + - PendingAttestations#phase0 + - PendingConsolidations#electra + - PendingConsolidations#gloas + - PendingDeposits#electra + - PendingDeposits#gloas + - PendingPartialWithdrawals#electra + - PendingPartialWithdrawals#gloas + - Proofs#fulu + - ProposerIndices#fulu + - ProposerLookahead#fulu + - ProposerSlashings#gloas + - ProposerSlashings#phase0 + - RandaoMixes#phase0 + - SignedBeaconBlocks#deneb + - SignedBeaconBlocks#phase0 + - SignedExecutionPayloadEnvelopes#gloas + - SignedInclusionLists#heze + - Slashings#phase0 + - StateRoots#phase0 + - SyncCommitteeBits#altair + - SyncCommitteePubkeys#altair + - SyncSubcommitteeBits#altair + - Syncnets#altair + - Transaction#bellatrix + - Transaction#gloas + - Transactions#bellatrix + - Transactions#gloas + - Validators#gloas + - Validators#phase0 + - VoluntaryExits#gloas + - VoluntaryExits#phase0 + - WithdrawalRequests#electra + - WithdrawalRequests#gloas + - Withdrawals#capella + - Withdrawals#gloas dataclasses: # phase0 - FastConfirmationStore#phase0 @@ -181,60 +294,8 @@ exceptions: - PayloadAttributes#heze - Store#heze + - InclusionListEntry#heze functions: - # Functions implemented by KZG library for EIP-4844 - - bit_reversal_permutation#deneb - - blob_to_kzg_commitment#deneb - - blob_to_polynomial#deneb - - bls_field_to_bytes#deneb - - bytes_to_bls_field#deneb - - bytes_to_kzg_commitment#deneb - - bytes_to_kzg_proof#deneb - - compute_blob_kzg_proof#deneb - - compute_challenge#deneb - - compute_kzg_proof#deneb - - compute_kzg_proof_impl#deneb - - compute_powers#deneb - - compute_quotient_eval_within_domain#deneb - - compute_roots_of_unity#deneb - - evaluate_polynomial_in_evaluation_form#deneb - - g1_lincomb#deneb - - hash_to_bls_field#deneb - - is_power_of_two#deneb - - reverse_bits#deneb - - validate_kzg_g1#deneb - - verify_blob_kzg_proof#deneb - - verify_blob_kzg_proof_batch#deneb - - verify_kzg_proof#deneb - - verify_kzg_proof_batch#deneb - - verify_kzg_proof_impl#deneb - - # Functions implemented by KZG library for EIP-7594 - - _fft_field#fulu - - add_polynomialcoeff#fulu - - cell_to_coset_evals#fulu - - compute_cells#fulu - - compute_cells_and_kzg_proofs#fulu - - compute_cells_and_kzg_proofs_polynomialcoeff#fulu - - compute_kzg_proof_multi_impl#fulu - - compute_verify_cell_kzg_proof_batch_challenge#fulu - - construct_vanishing_polynomial#fulu - - coset_evals_to_cell#fulu - - coset_fft_field#fulu - - coset_for_cell#fulu - - coset_shift_for_cell#fulu - - divide_polynomialcoeff#fulu - - evaluate_polynomialcoeff#fulu - - fft_field#fulu - - interpolate_polynomialcoeff#fulu - - multiply_polynomialcoeff#fulu - - polynomial_eval_to_coeff#fulu - - recover_cells_and_kzg_proofs#fulu - - recover_polynomialcoeff#fulu - - vanishing_polynomialcoeff#fulu - - verify_cell_kzg_proof_batch#fulu - - verify_cell_kzg_proof_batch_impl#fulu - # phase0 - adjust_committee_weight_estimate_to_ensure_safety#phase0 - compute_adversarial_weight#phase0 @@ -253,7 +314,7 @@ exceptions: - get_current_balance_source#phase0 - get_current_target#phase0 - get_current_target_score#phase0 - - get_dependent_root#phase0 + - get_shuffling_dependent_root#phase0 - get_equivocation_score#phase0 - get_fast_confirmation_store#phase0 - get_latest_confirmed#phase0 @@ -277,7 +338,6 @@ exceptions: - compute_attestation_subnet_prefix_bits#phase0 - compute_min_epochs_for_block_requests#phase0 - compute_time_at_slot_ms#phase0 - - is_not_from_future_slot#phase0 - is_within_slot_range#phase0 - update_proposer_boost_root#phase0 - is_proposer_equivocation#phase0 @@ -390,7 +450,9 @@ exceptions: # deneb - compute_max_request_blob_sidecars#deneb - get_lc_execution_root#deneb + - is_current_or_previous_epoch#deneb - is_valid_light_client_header#deneb + - is_within_epoch#deneb - prepare_execution_payload#deneb - upgrade_lc_bootstrap_to_deneb#deneb - upgrade_lc_finality_update_to_deneb#deneb @@ -448,8 +510,10 @@ exceptions: # gloas - get_latest_message_epoch#gloas - get_payload_due_ms#gloas + - is_bid_compatible_with_head#gloas - is_gas_limit_target_compatible#gloas - is_payload_verified#gloas + - is_valid_dependent_root#gloas - on_execution_payload_envelope#gloas - payload_data_availability#gloas - payload_timeliness#gloas @@ -478,7 +542,7 @@ exceptions: - get_forkchoice_store#gloas - get_head#gloas - get_indexed_payload_attestation#gloas - - get_dependent_root#gloas + - get_shuffling_dependent_root#gloas - get_next_sync_committee_indices#gloas - get_node_children#gloas - get_node_for_root#gloas @@ -536,7 +600,7 @@ exceptions: - get_builder_withdrawals#gloas - get_builders_sweep_withdrawals#gloas - get_index_for_new_builder#gloas - - get_proposer_preferences_signature#gloas + - get_signed_proposer_preferences#gloas - get_upcoming_proposal_slots#gloas - is_active_builder#gloas - is_builder_index#gloas @@ -545,7 +609,6 @@ exceptions: - is_head_late#gloas - is_head_weak#gloas - is_parent_strong#gloas - - is_valid_proposal_slot#gloas - onboard_builders_from_pending_deposits#gloas - process_deposit_request#gloas - record_block_timeliness#gloas @@ -559,11 +622,13 @@ exceptions: - block_to_light_client_header#gloas - compute_exit_epoch_and_update_churn#gloas - compute_weak_subjectivity_period#gloas + - current_sync_committee_gindex_at_slot#gloas + - finalized_root_gindex_at_slot#gloas + - next_sync_committee_gindex_at_slot#gloas - get_activation_churn_limit#gloas - get_consolidation_churn_limit#gloas - get_exit_churn_limit#gloas - get_lc_execution_root#gloas - - get_proposer_dependent_root#gloas - is_valid_light_client_header#gloas - process_pending_deposits#gloas - upgrade_lc_bootstrap_to_gloas#gloas @@ -577,8 +642,10 @@ exceptions: - compute_fork_version#heze - get_forkchoice_store#heze - get_inclusion_list_committee_assignment#heze + - get_inclusion_list_bits#heze - get_inclusion_list_committee#heze - get_inclusion_list_signature#heze + - is_inclusion_list_bits_inclusive#heze - get_inclusion_list_store#heze - get_inclusion_list_transactions#heze - is_payload_inclusion_list_satisfied#heze @@ -599,16 +666,42 @@ exceptions: - process_builder_deposit_request#gloas - process_builder_exit_request#gloas # phase0 - - is_epoch_boundary#phase0 + - compute_shuffling_dependent_slot#phase0 + - get_custody_column_bits#gloas + - get_proposer_head#fulu + - get_scheduled_gas_limit#gloas + - get_set_bit_count#phase0 + - get_signed_inclusion_list#heze + - is_current_or_next_slot#gloas + - is_future_slot#phase0 + - is_past_slot#gloas + - is_shuffling_stable#phase0 + - validate_beacon_aggregate_and_proof_gossip#gloas + - validate_beacon_attestation_gossip#gloas + - validate_beacon_block_gossip#gloas + - validate_data_column_sidecar_gossip#gloas + - validate_execution_payload_bid_gossip#gloas + - validate_execution_payload_envelope_gossip#gloas + - validate_partial_data_column_sidecar_gossip#gloas + - validate_payload_attestation_message_gossip#gloas + - validate_proposer_preferences_gossip#gloas + - verify_attestation_payload_status#gloas + - verify_block_body_operation_limits#gloas + - verify_execution_requests_limits#gloas presets: # gloas - - BUILDER_PENDING_WITHDRAWALS_LIMIT#gloas - - BUILDER_REGISTRY_LIMIT#gloas + - MAX_ATTESTER_SLASHING_SIZE#gloas - MAX_BUILDERS_PER_WITHDRAWALS_SWEEP#gloas + - MAX_DATA_COLUMN_SIDECAR_SIZE#gloas + - MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE#gloas - MAX_PAYLOAD_ATTESTATIONS#gloas + - MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE#gloas + - MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE#gloas - PTC_SIZE#gloas # heze - INCLUSION_LIST_COMMITTEE_SIZE#heze + - MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE_HEZE#heze + - MAX_SIGNED_INCLUSION_LIST_SIZE#heze # gloas (EIP-8282) - MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD#gloas - MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD#gloas diff --git a/WORKSPACE b/WORKSPACE index db4d05ca208d..1e602877267b 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -282,16 +282,16 @@ filegroup( url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz", ) -consensus_spec_version = "v1.7.0-alpha.11" +consensus_spec_version = "v1.7.0-alpha.14" load("@prysm//tools:download_spectests.bzl", "consensus_spec_tests") consensus_spec_tests( name = "consensus_spec_tests", flavors = { - "general": "sha256-szDpBVO2Ebi8/bwbiWFpW6H4c5gxnpU3hAUS31AF02E=", - "minimal": "sha256-irUv63gOA03eGIFD23Ca3PsDq87ovrA/HVAvtSG6/0o=", - "mainnet": "sha256-lWzAX5uy50Xs0Etg+yu5FnnIDt6C6BtIm11HqdZetms=", + "general": "sha256-xPOV9x9gbCgJNQDjIGeZDkMMxzoid75vO/UJCtzOP2c=", + "minimal": "sha256-LKQtMBStfkASQA5CjVEiAx6ROHO6v+0xxew6pd5x88g=", + "mainnet": "sha256-+YvTL01ohnaRuRC6HGLj1V3U6LalenhbPf2Sl7+YAPc=", }, version = consensus_spec_version, ) @@ -307,11 +307,28 @@ filegroup( visibility = ["//visibility:public"], ) """, - integrity = "sha256-6XWl6m5tkPIlx5eh3DxrHAShRzWh3gz4LlLjIM78wJo=", + integrity = "sha256-us/WKo/xoYSNg7c9uv6MVYEYmGLc9v03c2XM3XXt6Gk=", strip_prefix = "consensus-specs-" + consensus_spec_version[1:], url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version, ) +cryptography_spec_tests_version = "v0.1.0" + +http_archive( + name = "cryptography_spec_tests", + build_file_content = """ +filegroup( + name = "test_data", + srcs = glob([ + "**/*.yaml", + ]), + visibility = ["//visibility:public"], +) + """, + integrity = "sha256-7rSJPrVE93CBDZSZAH67C5MZQx6kEr1Uc24cJ02j0Dc=", + url = "https://github.com/ethereum/cryptography-specs/releases/download/%s/tests.zip" % cryptography_spec_tests_version, +) + bls_test_version = "v0.1.1" http_archive( diff --git a/beacon-chain/core/altair/attestation.go b/beacon-chain/core/altair/attestation.go index ae200ff7ddf9..40dec8fe1d0e 100644 --- a/beacon-chain/core/altair/attestation.go +++ b/beacon-chain/core/altair/attestation.go @@ -22,10 +22,27 @@ import ( // ProcessAttestationsNoVerifySignature applies processing operations to a block's inner attestation // records. The only difference would be that the attestation signature would not be verified. +// +// Callers inside Gloas block processing must use ProcessAttestationsNoVerifySignatureWithParentSlot instead. func ProcessAttestationsNoVerifySignature( ctx context.Context, beaconState state.BeaconState, b interfaces.ReadOnlyBeaconBlock, +) (state.BeaconState, error) { + parentSlot, err := gloas.ParentSlotFromBid(beaconState) + if err != nil { + return nil, err + } + return ProcessAttestationsNoVerifySignatureWithParentSlot(ctx, beaconState, b, parentSlot) +} + +// ProcessAttestationsNoVerifySignatureWithParentSlot takes the parent block's slot explicitly, for +// Gloas block processing where the bid in state has already been replaced by the current block's. +func ProcessAttestationsNoVerifySignatureWithParentSlot( + ctx context.Context, + beaconState state.BeaconState, + b interfaces.ReadOnlyBeaconBlock, + parentSlot primitives.Slot, ) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "altair.ProcessAttestationsNoVerifySignature") defer span.End() @@ -42,7 +59,7 @@ func ProcessAttestationsNoVerifySignature( return nil, err } for idx, att := range body.Attestations() { - beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, att, totalBalance) + beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, att, totalBalance, parentSlot) if err != nil { return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx) } @@ -57,6 +74,7 @@ func ProcessAttestationNoVerifySignature( beaconState state.BeaconState, att ethpb.Att, totalBalance uint64, + parentSlot primitives.Slot, ) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "altair.ProcessAttestationNoVerifySignature") defer span.End() @@ -69,7 +87,7 @@ func ProcessAttestationNoVerifySignature( if err != nil { return nil, fmt.Errorf("att slot %d can't be greater than state slot %d", att.GetData().Slot, beaconState.Slot()) } - participatedFlags, err := AttestationParticipationFlagIndices(beaconState, att.GetData(), delay) + participatedFlags, err := AttestationParticipationFlagIndices(beaconState, att.GetData(), delay, parentSlot) if err != nil { return nil, err } @@ -280,7 +298,7 @@ func RewardProposer(ctx context.Context, beaconState state.BeaconState, proposer // participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) // // return participation_flag_indices -func AttestationParticipationFlagIndices(beaconState state.ReadOnlyBeaconState, data *ethpb.AttestationData, delay primitives.Slot) (map[uint8]bool, error) { +func AttestationParticipationFlagIndices(beaconState state.ReadOnlyBeaconState, data *ethpb.AttestationData, delay primitives.Slot, parentSlot primitives.Slot) (map[uint8]bool, error) { currEpoch := time.CurrentEpoch(beaconState) var justifiedCheckpt *ethpb.Checkpoint if data.Target.Epoch == currEpoch { @@ -319,6 +337,7 @@ func AttestationParticipationFlagIndices(beaconState state.ReadOnlyBeaconState, beaconState, beaconBlockRoot, data.Slot, + parentSlot, uint64(data.CommitteeIndex), ) if err != nil { diff --git a/beacon-chain/core/altair/attestation_test.go b/beacon-chain/core/altair/attestation_test.go index 95a2397e7574..fa81041a424f 100644 --- a/beacon-chain/core/altair/attestation_test.go +++ b/beacon-chain/core/altair/attestation_test.go @@ -315,7 +315,7 @@ func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) { b, err := helpers.TotalActiveBalance(t.Context(), beaconState) require.NoError(t, err) - beaconState, err = altair.ProcessAttestationNoVerifySignature(t.Context(), beaconState, att, b) + beaconState, err = altair.ProcessAttestationNoVerifySignature(t.Context(), beaconState, att, b, 0) require.NoError(t, err) p, err := beaconState.CurrentEpochParticipation() @@ -689,6 +689,7 @@ func TestAttestationParticipationFlagIndices(t *testing.T) { inputState state.BeaconState inputData *ethpb.AttestationData inputDelay primitives.Slot + inputParentSlot primitives.Slot participationIndices map[uint8]bool }{ { @@ -820,7 +821,36 @@ func TestAttestationParticipationFlagIndices(t *testing.T) { Root: bytes.Repeat([]byte{0xAA}, 32), }, }, - inputDelay: 1, + inputDelay: 1, + inputParentSlot: 3, + participationIndices: map[uint8]bool{ + sourceFlagIndex: true, + targetFlagIndex: true, + headFlagIndex: true, + }, + }, + { + name: "gloas skipped data slot uses parent slot availability", + inputState: func() state.BeaconState { + stateSlot := primitives.Slot(5) + slot := primitives.Slot(4) + targetRoot := bytes.Repeat([]byte{0xAA}, 32) + headRoot := bytes.Repeat([]byte{0xBB}, 32) + // Slot 4 was skipped so it inherits slot 3's root, and slot 3 is where the revealed payload is recorded. + return buildGloasStateForFlags(t, stateSlot, slot, targetRoot, headRoot, headRoot, 1, 3) + }(), + inputData: ðpb.AttestationData{ + Slot: 4, + CommitteeIndex: 1, + BeaconBlockRoot: bytes.Repeat([]byte{0xBB}, 32), + Source: ðpb.Checkpoint{Root: bytes.Repeat([]byte{0xDD}, 32)}, + Target: ðpb.Checkpoint{ + Epoch: 0, + Root: bytes.Repeat([]byte{0xAA}, 32), + }, + }, + inputDelay: 1, + inputParentSlot: 3, participationIndices: map[uint8]bool{ sourceFlagIndex: true, targetFlagIndex: true, @@ -829,7 +859,7 @@ func TestAttestationParticipationFlagIndices(t *testing.T) { }, } for _, test := range tests { - flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay) + flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay, test.inputParentSlot) if test.participationIndices == nil { require.ErrorContains(t, "committee index", err) continue diff --git a/beacon-chain/core/altair/upgrade.go b/beacon-chain/core/altair/upgrade.go index 39f64b099d05..5e3679624005 100644 --- a/beacon-chain/core/altair/upgrade.go +++ b/beacon-chain/core/altair/upgrade.go @@ -154,7 +154,8 @@ func TranslateParticipation(ctx context.Context, state state.BeaconState, atts [ } for _, att := range atts { - participatedFlags, err := AttestationParticipationFlagIndices(state, att.Data, att.InclusionDelay) + // The parent slot is unused, the phase0 state being upgraded has no payload availability. + participatedFlags, err := AttestationParticipationFlagIndices(state, att.Data, att.InclusionDelay, 0) if err != nil { return nil, err } diff --git a/beacon-chain/core/electra/BUILD.bazel b/beacon-chain/core/electra/BUILD.bazel index 86ddece76b3d..71d43d203172 100644 --- a/beacon-chain/core/electra/BUILD.bazel +++ b/beacon-chain/core/electra/BUILD.bazel @@ -21,6 +21,7 @@ go_library( "//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/epoch:go_default_library", "//beacon-chain/core/epoch/precompute:go_default_library", + "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/signing:go_default_library", "//beacon-chain/core/time:go_default_library", diff --git a/beacon-chain/core/electra/attestation.go b/beacon-chain/core/electra/attestation.go index d09baf7af3c1..9e37162c9189 100644 --- a/beacon-chain/core/electra/attestation.go +++ b/beacon-chain/core/electra/attestation.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair" + "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/time" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" @@ -33,7 +34,12 @@ func GetProposerRewardNumerator( return 0, fmt.Errorf("attestation slot %d exceeds state slot %d", data.Slot, st.Slot()) } - flags, err := altair.AttestationParticipationFlagIndices(st, data, delay) + parentSlot, err := gloas.ParentSlotFromBid(st) + if err != nil { + return 0, err + } + + flags, err := altair.AttestationParticipationFlagIndices(st, data, delay, parentSlot) if err != nil { return 0, err } diff --git a/beacon-chain/core/gloas/BUILD.bazel b/beacon-chain/core/gloas/BUILD.bazel index c0f8e93d99f6..3362eaecb8c2 100644 --- a/beacon-chain/core/gloas/BUILD.bazel +++ b/beacon-chain/core/gloas/BUILD.bazel @@ -58,6 +58,7 @@ go_test( "builder_deposit_request_test.go", "builder_exit_request_test.go", "deposit_request_test.go", + "parent_payload_test.go", "payload_attestation_test.go", "payload_test.go", "pending_payment_test.go", diff --git a/beacon-chain/core/gloas/attestation.go b/beacon-chain/core/gloas/attestation.go index ba83e105d856..3f3f0ae91ba3 100644 --- a/beacon-chain/core/gloas/attestation.go +++ b/beacon-chain/core/gloas/attestation.go @@ -20,20 +20,21 @@ import ( // assert data.index == 0 // payload_matches = True // else: -// slot_index = data.slot % SLOTS_PER_HISTORICAL_ROOT +// slot_index = parent_slot % SLOTS_PER_HISTORICAL_ROOT // payload_index = state.execution_payload_availability[slot_index] // payload_matches = data.index == payload_index func MatchingPayload( beaconState state.ReadOnlyBeaconState, beaconBlockRoot [32]byte, - slot primitives.Slot, + dataSlot primitives.Slot, + parentSlot primitives.Slot, committeeIndex uint64, ) (bool, error) { if beaconState.Version() < version.Gloas { return true, nil } - sameSlot, err := beaconState.IsAttestationSameSlot(beaconBlockRoot, slot) + sameSlot, err := beaconState.IsAttestationSameSlot(beaconBlockRoot, dataSlot) if err != nil { return false, errors.Wrap(err, "failed to get same slot attestation status") } @@ -44,9 +45,27 @@ func MatchingPayload( return true, nil } - executionPayloadAvail, err := beaconState.ExecutionPayloadAvailability(slot) + // The attested block is the parent whenever the head flag can apply, so its availability bit lives at parentSlot, not at a skipped dataSlot. + executionPayloadAvail, err := beaconState.ExecutionPayloadAvailability(parentSlot) if err != nil { return false, errors.Wrap(err, "failed to get execution payload availability status") } return executionPayloadAvail == committeeIndex, nil } + +// ParentSlotFromBid returns the parent block's slot from the bid cached in state. +// Not valid inside block processing, ProcessExecutionPayloadBid replaces the bid with the current block's. +func ParentSlotFromBid(beaconState state.ReadOnlyBeaconState) (primitives.Slot, error) { + if beaconState.Version() < version.Gloas { + return 0, nil + } + + bid, err := beaconState.LatestExecutionPayloadBid() + if err != nil { + return 0, errors.Wrap(err, "failed to get latest execution payload bid") + } + if bid == nil { + return 0, nil + } + return bid.Slot(), nil +} diff --git a/beacon-chain/core/gloas/attestation_test.go b/beacon-chain/core/gloas/attestation_test.go index c3d52480d444..08748e4ba06f 100644 --- a/beacon-chain/core/gloas/attestation_test.go +++ b/beacon-chain/core/gloas/attestation_test.go @@ -31,12 +31,43 @@ func buildStateWithBlockRoots(t *testing.T, stateSlot primitives.Slot, roots map return state.(*state_native.BeaconState) } +func buildStateWithAvailability(t *testing.T, stateSlot primitives.Slot, roots map[primitives.Slot][]byte, availableSlots ...primitives.Slot) *state_native.BeaconState { + t.Helper() + + cfg := params.BeaconConfig() + blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot) + for slot, root := range roots { + blockRoots[slot%cfg.SlotsPerHistoricalRoot] = root + } + + availability := make([]byte, cfg.SlotsPerHistoricalRoot/8) + for _, slot := range availableSlots { + idx := uint64(slot % cfg.SlotsPerHistoricalRoot) + availability[idx/8] |= byte(1 << (idx % 8)) + } + + stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{ + Slot: stateSlot, + BlockRoots: blockRoots, + ExecutionPayloadAvailability: availability, + Fork: ðpb.Fork{ + CurrentVersion: bytes.Repeat([]byte{0x66}, 4), + PreviousVersion: bytes.Repeat([]byte{0x66}, 4), + Epoch: 0, + }, + }) + require.NoError(t, err) + st := stIface.(*state_native.BeaconState) + require.Equal(t, version.Gloas, st.Version()) + return st +} + func TestMatchingPayload(t *testing.T) { t.Run("pre-gloas always true", func(t *testing.T) { stIface, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{}) require.NoError(t, err) - ok, err := MatchingPayload(stIface, [32]byte{}, 0, 123) + ok, err := MatchingPayload(stIface, [32]byte{}, 0, 0, 123) require.NoError(t, err) require.Equal(t, true, ok) }) @@ -51,7 +82,7 @@ func TestMatchingPayload(t *testing.T) { var rootArr [32]byte copy(rootArr[:], root) - ok, err := MatchingPayload(state, rootArr, 4, 1) + ok, err := MatchingPayload(state, rootArr, 4, 3, 1) require.ErrorContains(t, "committee index", err) require.Equal(t, false, ok) }) @@ -66,45 +97,71 @@ func TestMatchingPayload(t *testing.T) { var rootArr [32]byte copy(rootArr[:], root) - ok, err := MatchingPayload(state, rootArr, 4, 0) + ok, err := MatchingPayload(state, rootArr, 4, 3, 0) require.NoError(t, err) require.Equal(t, true, ok) }) - t.Run("non same slot checks payload availability", func(t *testing.T) { - cfg := params.BeaconConfig() - root := bytes.Repeat([]byte{0xAA}, 32) - blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot) - blockRoots[4%cfg.SlotsPerHistoricalRoot] = bytes.Repeat([]byte{0xCC}, 32) - blockRoots[3%cfg.SlotsPerHistoricalRoot] = bytes.Repeat([]byte{0xBB}, 32) - - availability := make([]byte, cfg.SlotsPerHistoricalRoot/8) - slotIndex := uint64(4) - availability[slotIndex/8] = byte(1 << (slotIndex % 8)) - - stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{ - Slot: 6, - BlockRoots: blockRoots, - ExecutionPayloadAvailability: availability, - Fork: ðpb.Fork{ - CurrentVersion: bytes.Repeat([]byte{0x66}, 4), - PreviousVersion: bytes.Repeat([]byte{0x66}, 4), - Epoch: 0, - }, - }) - require.NoError(t, err) - state := stIface.(*state_native.BeaconState) - require.Equal(t, version.Gloas, state.Version()) + roots := map[primitives.Slot][]byte{ + 4: bytes.Repeat([]byte{0xCC}, 32), + 3: bytes.Repeat([]byte{0xBB}, 32), + } + var attestedRoot [32]byte + copy(attestedRoot[:], bytes.Repeat([]byte{0xAA}, 32)) - var rootArr [32]byte - copy(rootArr[:], root) + t.Run("non same slot checks availability at the parent slot", func(t *testing.T) { + // Slot 4 was skipped, the attested block at slot 3 revealed its payload. + st := buildStateWithAvailability(t, 6, roots, 3) - ok, err := MatchingPayload(state, rootArr, 4, 1) + ok, err := MatchingPayload(st, attestedRoot, 4, 3, 1) require.NoError(t, err) require.Equal(t, true, ok) - ok, err = MatchingPayload(state, rootArr, 4, 0) + ok, err = MatchingPayload(st, attestedRoot, 4, 3, 0) require.NoError(t, err) require.Equal(t, false, ok) }) + + t.Run("non same slot ignores availability at the data slot", func(t *testing.T) { + // Only the skipped slot 4 is marked available, the attested block at slot 3 withheld its payload. + st := buildStateWithAvailability(t, 6, roots, 4) + + ok, err := MatchingPayload(st, attestedRoot, 4, 3, 1) + require.NoError(t, err) + require.Equal(t, false, ok) + + ok, err = MatchingPayload(st, attestedRoot, 4, 3, 0) + require.NoError(t, err) + require.Equal(t, true, ok) + }) +} + +func TestParentSlotFromBid(t *testing.T) { + t.Run("pre-gloas returns zero", func(t *testing.T) { + st, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{}) + require.NoError(t, err) + + parentSlot, err := ParentSlotFromBid(st) + require.NoError(t, err) + require.Equal(t, primitives.Slot(0), parentSlot) + }) + + t.Run("returns the cached bid slot", func(t *testing.T) { + st, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{ + Slot: 6, + LatestExecutionPayloadBid: ðpb.ExecutionPayloadBid{ + Slot: 3, + ParentBlockHash: make([]byte, 32), + ParentBlockRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + PrevRandao: make([]byte, 32), + FeeRecipient: make([]byte, 20), + }, + }) + require.NoError(t, err) + + parentSlot, err := ParentSlotFromBid(st) + require.NoError(t, err) + require.Equal(t, primitives.Slot(3), parentSlot) + }) } diff --git a/beacon-chain/core/gloas/bid.go b/beacon-chain/core/gloas/bid.go index f6ab3377ba33..2d1c94903937 100644 --- a/beacon-chain/core/gloas/bid.go +++ b/beacon-chain/core/gloas/bid.go @@ -18,10 +18,10 @@ import ( // ProcessExecutionPayloadBid processes a signed execution payload bid in the Gloas fork. // -// +// // def process_execution_payload_bid( // state: BeaconState, signed_bid: SignedExecutionPayloadBid -// ) -> None: +// ) -> Slot: // bid = signed_bid.message // builder_index = bid.builder_index // amount = bid.value @@ -69,8 +69,13 @@ import ( // pending_payment // ) // +// # Cache the parent block's slot before overwriting the bid +// parent_slot = state.latest_execution_payload_bid.slot +// // # Cache the signed execution payload bid // state.latest_execution_payload_bid = bid +// +// return parent_slot // func ProcessExecutionPayloadBid(st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) error { signedBid, err := block.Body().SignedExecutionPayloadBid() diff --git a/beacon-chain/core/gloas/builder_deposit_request.go b/beacon-chain/core/gloas/builder_deposit_request.go index 0c6f1cd13112..733f26b7c5c9 100644 --- a/beacon-chain/core/gloas/builder_deposit_request.go +++ b/beacon-chain/core/gloas/builder_deposit_request.go @@ -27,7 +27,7 @@ func ProcessBuilderDepositRequests(ctx context.Context, st state.BeaconState, re newDeposits := make([]*enginev1.BuilderDepositRequest, 0, len(requests)) newIdx := make([]int, 0, len(requests)) for i, request := range requests { - if request == nil { + if request == nil || !helpers.IsBuilderWithdrawalCredential(request.WithdrawalCredentials) { continue } if _, isBuilder := st.BuilderIndexByPubkey(bytesutil.ToBytes48(request.Pubkey)); !isBuilder { @@ -56,15 +56,19 @@ func ProcessBuilderDepositRequests(ctx context.Context, st state.BeaconState, re // processBuilderDepositRequest registers a new builder or tops up an existing one. // -// +// // def process_builder_deposit_request(state: BeaconState, request: BuilderDepositRequest) -> None: +// # Ignore deposits with unexpected withdrawal credential prefixes +// if not is_builder_withdrawal_credential(request.withdrawal_credentials): +// return +// // builder_pubkeys = [b.pubkey for b in state.builders] // if request.pubkey not in builder_pubkeys: // if is_valid_builder_deposit_signature(request): // add_builder_to_registry( // state, // request.pubkey, -// uint8(request.withdrawal_credentials[0]), +// PAYLOAD_BUILDER_VERSION, // ExecutionAddress(request.withdrawal_credentials[12:]), // request.amount, // state.slot, @@ -73,34 +77,43 @@ func ProcessBuilderDepositRequests(ctx context.Context, st state.BeaconState, re // builder_index = BuilderIndex(builder_pubkeys.index(request.pubkey)) // builder = state.builders[builder_index] // -// # Increase balance by deposit amount -// builder.balance += request.amount -// -// # If exited, reset the withdrawable epoch -// if builder.withdrawable_epoch != FAR_FUTURE_EPOCH: +// # If exited and swept, reset the withdrawable epoch +// if builder.withdrawable_epoch != FAR_FUTURE_EPOCH and builder.balance == 0: // epoch = get_current_epoch(state) // builder.withdrawable_epoch = epoch + MIN_BUILDER_WITHDRAWABILITY_DELAY +// +// # Increase balance by deposit amount +// builder.balance += request.amount // func processBuilderDepositRequest(ctx context.Context, st state.BeaconState, request *enginev1.BuilderDepositRequest, status sigStatus) error { if request == nil { return errors.New("nil builder deposit request") } + // Deposits without BUILDER_WITHDRAWAL_PREFIX are dropped and the funds are lost. + if !helpers.IsBuilderWithdrawalCredential(request.WithdrawalCredentials) { + return nil + } + pubkey := bytesutil.ToBytes48(request.Pubkey) if idx, isBuilder := st.BuilderIndexByPubkey(pubkey); isBuilder { - if err := st.IncreaseBuilderBalance(idx, request.Amount); err != nil { - return err - } builder, err := st.Builder(idx) if err != nil { return err } - if builder.WithdrawableEpoch != params.BeaconConfig().FarFutureEpoch { + if builder == nil { + return errors.Errorf("builder at index %d is nil", idx) + } + // Reset only when exited and fully swept, checked before the top-up is credited. + if builder.WithdrawableEpoch != params.BeaconConfig().FarFutureEpoch && builder.Balance == 0 { builder.WithdrawableEpoch = slots.ToEpoch(st.Slot()) + params.BeaconConfig().MinBuilderWithdrawabilityDelay if err := st.UpdateBuilderAtIndex(idx, builder); err != nil { return err } } + if err := st.IncreaseBuilderBalance(idx, request.Amount); err != nil { + return err + } builderDepositsProcessedTotal.Inc() return nil } diff --git a/beacon-chain/core/gloas/builder_deposit_request_test.go b/beacon-chain/core/gloas/builder_deposit_request_test.go index 25fd1d198b24..dddcea3655f8 100644 --- a/beacon-chain/core/gloas/builder_deposit_request_test.go +++ b/beacon-chain/core/gloas/builder_deposit_request_test.go @@ -11,6 +11,7 @@ import ( enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" "github.com/OffchainLabs/prysm/v7/testing/require" + "github.com/OffchainLabs/prysm/v7/time/slots" ) func signedBuilderDepositRequest(t *testing.T, sk bls.SecretKey, cred [32]byte, amount uint64) *enginev1.BuilderDepositRequest { @@ -46,7 +47,7 @@ func TestProcessBuilderDepositRequest_NewBuilderValidSignature(t *testing.T) { builder, err := st.Builder(idx) require.NoError(t, err) require.DeepEqual(t, req.Pubkey, builder.Pubkey) - require.DeepEqual(t, []byte{cred[0]}, builder.Version) + require.DeepEqual(t, []byte{params.BeaconConfig().PayloadBuilderVersion}, builder.Version) require.DeepEqual(t, cred[12:], builder.ExecutionAddress) require.Equal(t, uint64(1234), uint64(builder.Balance)) require.Equal(t, params.BeaconConfig().FarFutureEpoch, builder.WithdrawableEpoch) @@ -65,6 +66,50 @@ func TestProcessBuilderDepositRequest_NewBuilderInvalidSignatureIgnored(t *testi require.Equal(t, false, ok) } +func TestProcessBuilderDepositRequest_NewBuilderNonBuilderPrefixIgnored(t *testing.T) { + sk, err := bls.RandKey() + require.NoError(t, err) + cred := builderWithdrawalCredentials() + cred[0] = 0x01 + req := signedBuilderDepositRequest(t, sk, cred, 1234) + + st := newGloasState(t, nil, nil) + require.NoError(t, processBuilderDepositRequest(t.Context(), st, req, sigKnownValid)) + + _, ok := st.BuilderIndexByPubkey(toBytes48(req.Pubkey)) + require.Equal(t, false, ok) +} + +func TestProcessBuilderDepositRequest_TopUpNonBuilderPrefixIgnored(t *testing.T) { + sk, err := bls.RandKey() + require.NoError(t, err) + pubkey := sk.PublicKey().Marshal() + builders := []*ethpb.Builder{{ + Pubkey: pubkey, + Version: []byte{params.BeaconConfig().PayloadBuilderVersion}, + ExecutionAddress: bytes.Repeat([]byte{0x11}, 20), + Balance: 5, + WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, + }} + st := newGloasState(t, nil, builders) + + cred := builderWithdrawalCredentials() + cred[0] = 0x01 + req := &enginev1.BuilderDepositRequest{ + Pubkey: pubkey, + WithdrawalCredentials: cred[:], + Amount: 200, + Signature: make([]byte, 96), + } + require.NoError(t, processBuilderDepositRequest(t.Context(), st, req, sigKnownValid)) + + idx, ok := st.BuilderIndexByPubkey(toBytes48(pubkey)) + require.Equal(t, true, ok) + builder, err := st.Builder(idx) + require.NoError(t, err) + require.Equal(t, uint64(5), uint64(builder.Balance)) +} + func TestProcessBuilderDepositRequest_ExistingBuilderTopsUpNoSignatureCheck(t *testing.T) { sk, err := bls.RandKey() require.NoError(t, err) @@ -93,6 +138,68 @@ func TestProcessBuilderDepositRequest_ExistingBuilderTopsUpNoSignatureCheck(t *t require.Equal(t, uint64(205), uint64(builder.Balance)) } +func TestProcessBuilderDepositRequest_ExitedSweptBuilderTopUpResetsWithdrawableEpoch(t *testing.T) { + sk, err := bls.RandKey() + require.NoError(t, err) + pubkey := sk.PublicKey().Marshal() + builders := []*ethpb.Builder{{ + Pubkey: pubkey, + Version: []byte{params.BeaconConfig().BuilderWithdrawalPrefixByte}, + ExecutionAddress: bytes.Repeat([]byte{0x11}, 20), + Balance: 0, + WithdrawableEpoch: 0, + }} + st := newGloasState(t, nil, builders) + + cred := builderWithdrawalCredentials() + req := &enginev1.BuilderDepositRequest{ + Pubkey: pubkey, + WithdrawalCredentials: cred[:], + Amount: 200, + Signature: make([]byte, 96), + } + require.NoError(t, processBuilderDepositRequest(t.Context(), st, req, sigUnverified)) + + idx, ok := st.BuilderIndexByPubkey(toBytes48(pubkey)) + require.Equal(t, true, ok) + builder, err := st.Builder(idx) + require.NoError(t, err) + require.Equal(t, uint64(200), uint64(builder.Balance)) + expected := slots.ToEpoch(st.Slot()) + params.BeaconConfig().MinBuilderWithdrawabilityDelay + require.Equal(t, expected, builder.WithdrawableEpoch) +} + +func TestProcessBuilderDepositRequest_ExitedUnsweptBuilderTopUpKeepsWithdrawableEpoch(t *testing.T) { + sk, err := bls.RandKey() + require.NoError(t, err) + pubkey := sk.PublicKey().Marshal() + exitedEpoch := primitives.Epoch(1) + builders := []*ethpb.Builder{{ + Pubkey: pubkey, + Version: []byte{params.BeaconConfig().BuilderWithdrawalPrefixByte}, + ExecutionAddress: bytes.Repeat([]byte{0x11}, 20), + Balance: 5, + WithdrawableEpoch: exitedEpoch, + }} + st := newGloasState(t, nil, builders) + + cred := builderWithdrawalCredentials() + req := &enginev1.BuilderDepositRequest{ + Pubkey: pubkey, + WithdrawalCredentials: cred[:], + Amount: 200, + Signature: make([]byte, 96), + } + require.NoError(t, processBuilderDepositRequest(t.Context(), st, req, sigUnverified)) + + idx, ok := st.BuilderIndexByPubkey(toBytes48(pubkey)) + require.Equal(t, true, ok) + builder, err := st.Builder(idx) + require.NoError(t, err) + require.Equal(t, uint64(205), uint64(builder.Balance)) + require.Equal(t, exitedEpoch, builder.WithdrawableEpoch) +} + func TestProcessBuilderDepositRequests_BatchMixedValidInvalidAndTopUp(t *testing.T) { cred := builderWithdrawalCredentials() skValid, err := bls.RandKey() diff --git a/beacon-chain/core/gloas/parent_payload.go b/beacon-chain/core/gloas/parent_payload.go index 48c56d91795e..c96048f15bd3 100644 --- a/beacon-chain/core/gloas/parent_payload.go +++ b/beacon-chain/core/gloas/parent_payload.go @@ -6,6 +6,7 @@ import ( requests "github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" + "github.com/OffchainLabs/prysm/v7/config/params" "github.com/OffchainLabs/prysm/v7/consensus-types/interfaces" "github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" @@ -63,7 +64,11 @@ func ProcessParentExecutionPayload(ctx context.Context, st state.BeaconState, bl // and mutates st. Called by ProcessParentExecutionPayload and by the validator during // block production before computing withdrawals. // -// +// +// assert len(requests.withdrawals) <= MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD +// assert len(requests.consolidations) <= MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD +// assert len(requests.builder_deposits) <= MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD +// assert len(requests.builder_exits) <= MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD func ApplyParentExecutionPayload( ctx context.Context, st state.BeaconState, @@ -75,6 +80,10 @@ func ApplyParentExecutionPayload( } parentSlot := parentBid.Slot() + if err := validateExecutionRequestLengths(reqs); err != nil { + return err + } + if err := processExecutionRequests(ctx, st, reqs); err != nil { return errors.Wrap(err, "could not process parent execution requests") } @@ -95,6 +104,25 @@ func ApplyParentExecutionPayload( return nil } +// validateExecutionRequestLengths enforces the per-payload maxima that remain +// consensus-layer checks now that EIP-7688 uses ProgressiveList SSZ types. +func validateExecutionRequestLengths(reqs *enginev1.ExecutionRequestsGloas) error { + cfg := params.BeaconConfig() + if uint64(len(reqs.GetWithdrawals())) > cfg.MaxWithdrawalRequestsPerPayload { + return errors.Errorf("too many withdrawal requests: %d > %d", len(reqs.GetWithdrawals()), cfg.MaxWithdrawalRequestsPerPayload) + } + if uint64(len(reqs.GetConsolidations())) > cfg.MaxConsolidationsRequestsPerPayload { + return errors.Errorf("too many consolidation requests: %d > %d", len(reqs.GetConsolidations()), cfg.MaxConsolidationsRequestsPerPayload) + } + if uint64(len(reqs.GetBuilderDeposits())) > cfg.MaxBuilderDepositRequestsPerPayload { + return errors.Errorf("too many builder deposit requests: %d > %d", len(reqs.GetBuilderDeposits()), cfg.MaxBuilderDepositRequestsPerPayload) + } + if uint64(len(reqs.GetBuilderExits())) > cfg.MaxBuilderExitRequestsPerPayload { + return errors.Errorf("too many builder exit requests: %d > %d", len(reqs.GetBuilderExits()), cfg.MaxBuilderExitRequestsPerPayload) + } + return nil +} + func processExecutionRequests(ctx context.Context, st state.BeaconState, rqs *enginev1.ExecutionRequestsGloas) error { if err := ProcessDepositRequests(ctx, st, rqs.Deposits); err != nil { return errors.Wrap(err, "could not process deposit requests") diff --git a/beacon-chain/core/gloas/parent_payload_test.go b/beacon-chain/core/gloas/parent_payload_test.go new file mode 100644 index 000000000000..be8766457892 --- /dev/null +++ b/beacon-chain/core/gloas/parent_payload_test.go @@ -0,0 +1,27 @@ +package gloas + +import ( + "testing" + + "github.com/OffchainLabs/prysm/v7/config/params" + enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" + "github.com/OffchainLabs/prysm/v7/testing/require" +) + +func TestValidateExecutionRequestLengths_DepositsUnbounded(t *testing.T) { + cfg := params.BeaconConfig() + reqs := &enginev1.ExecutionRequestsGloas{ + Deposits: make([]*enginev1.DepositRequest, int(cfg.MaxDepositRequestsPerPayload)+1), + } + + require.NoError(t, validateExecutionRequestLengths(reqs)) +} + +func TestValidateExecutionRequestLengths_WithdrawalsBounded(t *testing.T) { + cfg := params.BeaconConfig() + reqs := &enginev1.ExecutionRequestsGloas{ + Withdrawals: make([]*enginev1.WithdrawalRequest, int(cfg.MaxWithdrawalRequestsPerPayload)+1), + } + + require.ErrorContains(t, "too many withdrawal requests", validateExecutionRequestLengths(reqs)) +} diff --git a/beacon-chain/core/gloas/payload_attestation.go b/beacon-chain/core/gloas/payload_attestation.go index bd086c8f27b2..3a035d56ac04 100644 --- a/beacon-chain/core/gloas/payload_attestation.go +++ b/beacon-chain/core/gloas/payload_attestation.go @@ -109,21 +109,23 @@ func indexedPayloadAttestation(ctx context.Context, st state.ReadOnlyBeaconState // computePTC computes the payload timeliness committee for a given slot. // -// -// def compute_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: +// +// def compute_ptc(state: BeaconState, slot: Slot) -> PTC: // """ // Get the payload timeliness committee, with possible duplicates, for the given ``slot``. // """ // epoch = compute_epoch_at_slot(slot) // seed = hash(get_seed(state, epoch, DOMAIN_PTC_ATTESTER) + uint_to_bytes(slot)) -// indices: List[ValidatorIndex] = [] +// indices: list[ValidatorIndex] = [] // # Concatenate all committees for this slot in order // committees_per_slot = get_committee_count_per_slot(state, epoch) // for i in range(committees_per_slot): // committee = get_beacon_committee(state, slot, CommitteeIndex(i)) // indices.extend(committee) -// return compute_balance_weighted_selection( -// state, indices, seed, size=PTC_SIZE, shuffle_indices=False +// return PTC( +// compute_balance_weighted_selection( +// state, indices, seed, size=PTC_SIZE, shuffle_indices=False +// ) // ) // func computePTC(ctx context.Context, st state.ReadOnlyBeaconState, slot primitives.Slot) ([]primitives.ValidatorIndex, error) { @@ -219,12 +221,12 @@ func ptcSeed(st state.ReadOnlyBeaconState, epoch primitives.Epoch, slot primitiv // selectByBalance selects a balance-weighted subset of input candidates. // -// +// // def compute_balance_weighted_selection( // state: BeaconState, // indices: Sequence[ValidatorIndex], // seed: Bytes32, -// size: uint64, +// size: Uint64, // shuffle_indices: bool, // ) -> Sequence[ValidatorIndex]: // """ @@ -234,11 +236,11 @@ func ptcSeed(st state.ReadOnlyBeaconState, epoch primitives.Epoch, slot primitiv // ``indices`` is traversed in order. The returned list can contain duplicates. // """ // MAX_RANDOM_VALUE = 2**16 - 1 -// total = uint64(len(indices)) +// total = Uint64(len(indices)) // assert total > 0 // effective_balances = [state.validators[index].effective_balance for index in indices] -// selected: List[ValidatorIndex] = [] -// i = uint64(0) +// selected: list[ValidatorIndex] = [] +// i = Uint64(0) // while len(selected) < size: // offset = i % 16 * 2 // if offset == 0: diff --git a/beacon-chain/core/gloas/payload_attestation_test.go b/beacon-chain/core/gloas/payload_attestation_test.go index 7929e400ffef..73924a26a583 100644 --- a/beacon-chain/core/gloas/payload_attestation_test.go +++ b/beacon-chain/core/gloas/payload_attestation_test.go @@ -329,7 +329,7 @@ func signAttestation(t *testing.T, st state.ReadOnlyBeaconState, data *eth.Paylo func TestProcessPTCWindow(t *testing.T) { fuluSt, _ := testutil.DeterministicGenesisStateFulu(t, 256) - st, err := gloas.UpgradeToGloas(fuluSt) + st, err := gloas.UpgradeToGloas(t.Context(), fuluSt) require.NoError(t, err) slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch @@ -376,7 +376,7 @@ func TestProcessPTCWindow(t *testing.T) { // state, guarding against unintended behavioral drift. func TestProcessPTCWindow_GoldenVector(t *testing.T) { fuluSt, _ := testutil.DeterministicGenesisStateFulu(t, 256) - st, err := gloas.UpgradeToGloas(fuluSt) + st, err := gloas.UpgradeToGloas(t.Context(), fuluSt) require.NoError(t, err) require.NoError(t, st.SetSlot(params.BeaconConfig().SlotsPerEpoch)) require.NoError(t, gloas.ProcessPTCWindow(t.Context(), st)) @@ -426,7 +426,7 @@ func (s *validatorLookupErrState) ValidatorAtIndexReadOnly(idx primitives.Valida // what's expected: we skipped SHA256 work, not memory traffic. func BenchmarkProcessPTCWindow(b *testing.B) { fuluSt, _ := testutil.DeterministicGenesisStateFulu(b, 2048) - st, err := gloas.UpgradeToGloas(fuluSt) + st, err := gloas.UpgradeToGloas(b.Context(), fuluSt) require.NoError(b, err) require.NoError(b, st.SetSlot(params.BeaconConfig().SlotsPerEpoch)) diff --git a/beacon-chain/core/gloas/pending_payment.go b/beacon-chain/core/gloas/pending_payment.go index e18d7e7ad30c..26084cb47488 100644 --- a/beacon-chain/core/gloas/pending_payment.go +++ b/beacon-chain/core/gloas/pending_payment.go @@ -13,7 +13,7 @@ import ( // ProcessBuilderPendingPayments processes the builder pending payments from the previous epoch. // -// +// // def process_builder_pending_payments(state: BeaconState) -> None: // """ // Processes the builder pending payments from the previous epoch. @@ -25,7 +25,7 @@ import ( // // old_payments = state.builder_pending_payments[SLOTS_PER_EPOCH:] // new_payments = [BuilderPendingPayment() for _ in range(SLOTS_PER_EPOCH)] -// state.builder_pending_payments = old_payments + new_payments +// state.builder_pending_payments = BuilderPendingPayments(old_payments + new_payments) // func ProcessBuilderPendingPayments(ctx context.Context, state state.BeaconState) error { quorum, err := builderQuorumThreshold(ctx, state) @@ -61,14 +61,14 @@ func ProcessBuilderPendingPayments(ctx context.Context, state state.BeaconState) // builderQuorumThreshold calculates the quorum threshold for builder payments. // -// -// def get_builder_payment_quorum_threshold(state: BeaconState) -> uint64: +// +// def get_builder_payment_quorum_threshold(state: BeaconState) -> Uint64: // """ // Calculate the quorum threshold for builder payments. // """ // per_slot_balance = get_total_active_balance(state) // SLOTS_PER_EPOCH // quorum = per_slot_balance * BUILDER_PAYMENT_THRESHOLD_NUMERATOR -// return uint64(quorum // BUILDER_PAYMENT_THRESHOLD_DENOMINATOR) +// return Uint64(quorum // BUILDER_PAYMENT_THRESHOLD_DENOMINATOR) // func builderQuorumThreshold(ctx context.Context, state state.ReadOnlyBeaconState) (primitives.Gwei, error) { activeBalance, err := helpers.TotalActiveBalance(ctx, state) diff --git a/beacon-chain/core/gloas/upgrade.go b/beacon-chain/core/gloas/upgrade.go index 4a51e562a693..b0f119fc6b5b 100644 --- a/beacon-chain/core/gloas/upgrade.go +++ b/beacon-chain/core/gloas/upgrade.go @@ -17,7 +17,7 @@ import ( // UpgradeToGloas updates inputs a generic state to return the version Gloas state. // -// +// // def upgrade_to_gloas(pre: fulu.BeaconState) -> BeaconState: // epoch = fulu.get_current_epoch(pre) // @@ -38,17 +38,22 @@ import ( // eth1_data=pre.eth1_data, // eth1_data_votes=pre.eth1_data_votes, // eth1_deposit_index=pre.eth1_deposit_index, -// validators=pre.validators, -// balances=pre.balances, +// # [Modified in Gloas:EIP7688] +// validators=Validators(list(pre.validators)), +// # [Modified in Gloas:EIP7688] +// balances=Balances(list(pre.balances)), // randao_mixes=pre.randao_mixes, // slashings=pre.slashings, -// previous_epoch_participation=pre.previous_epoch_participation, -// current_epoch_participation=pre.current_epoch_participation, +// # [Modified in Gloas:EIP7688] +// previous_epoch_participation=EpochParticipation(list(pre.previous_epoch_participation)), +// # [Modified in Gloas:EIP7688] +// current_epoch_participation=EpochParticipation(list(pre.current_epoch_participation)), // 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_scores=pre.inactivity_scores, +// # [Modified in Gloas:EIP7688] +// inactivity_scores=InactivityScores(list(pre.inactivity_scores)), // current_sync_committee=pre.current_sync_committee, // next_sync_committee=pre.next_sync_committee, // # [Modified in Gloas:EIP7732] @@ -64,28 +69,44 @@ import ( // earliest_exit_epoch=pre.earliest_exit_epoch, // consolidation_balance_to_consume=pre.consolidation_balance_to_consume, // earliest_consolidation_epoch=pre.earliest_consolidation_epoch, -// pending_deposits=pre.pending_deposits, -// pending_partial_withdrawals=pre.pending_partial_withdrawals, -// pending_consolidations=pre.pending_consolidations, +// # [Modified in Gloas:EIP7688] +// pending_deposits=PendingDeposits(list(pre.pending_deposits)), +// # [Modified in Gloas:EIP7688] +// pending_partial_withdrawals=PendingPartialWithdrawals( +// list(pre.pending_partial_withdrawals) +// ), +// # [Modified in Gloas:EIP7688] +// pending_consolidations=PendingConsolidations(list(pre.pending_consolidations)), // proposer_lookahead=pre.proposer_lookahead, // # [New in Gloas:EIP7732] -// builders=[], +// builders=Builders(), // # [New in Gloas:EIP7732] // next_withdrawal_builder_index=BuilderIndex(0), // # [New in Gloas:EIP7732] -// execution_payload_availability=[0b1 for _ in range(SLOTS_PER_HISTORICAL_ROOT)], +// execution_payload_availability=ExecutionPayloadAvailability([ +// 0b1 for _ in range(SLOTS_PER_HISTORICAL_ROOT) +// ]), // # [New in Gloas:EIP7732] -// builder_pending_payments=[BuilderPendingPayment() for _ in range(2 * SLOTS_PER_EPOCH)], +// builder_pending_payments=BuilderPendingPayments(), // # [New in Gloas:EIP7732] -// builder_pending_withdrawals=[], +// builder_pending_withdrawals=BuilderPendingWithdrawals(), // # [New in Gloas:EIP7732] // latest_execution_payload_bid=ExecutionPayloadBid( +// parent_block_hash=pre.latest_execution_payload_header.parent_hash, +// parent_block_root=pre.latest_block_header.parent_root, // block_hash=pre.latest_execution_payload_header.block_hash, +// prev_randao=pre.latest_execution_payload_header.prev_randao, +// fee_recipient=ExecutionAddress(), // gas_limit=pre.latest_execution_payload_header.gas_limit, +// builder_index=BUILDER_INDEX_SELF_BUILD, +// slot=pre.latest_block_header.slot, +// value=Gwei(0), +// execution_payment=Gwei(0), +// blob_kzg_commitments=BlobKZGCommitments(), // execution_requests_root=hash_tree_root(ExecutionRequests()), // ), // # [New in Gloas:EIP7732] -// payload_expected_withdrawals=[], +// payload_expected_withdrawals=Withdrawals(), // # [New in Gloas:EIP7732] // ptc_window=initialize_ptc_window(pre), // ) @@ -95,19 +116,19 @@ import ( // // return post // -func UpgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { +func UpgradeToGloas(ctx context.Context, beaconState state.BeaconState) (state.BeaconState, error) { s, err := upgradeToGloas(beaconState) if err != nil { return nil, errors.Wrap(err, "could not convert to gloas") } - ptcWindow, err := initializePTCWindow(context.Background(), s) + ptcWindow, err := initializePTCWindow(ctx, s) if err != nil { return nil, errors.Wrap(err, "failed to initialize ptc window") } if err := s.SetPTCWindow(ptcWindow); err != nil { return nil, errors.Wrap(err, "failed to set ptc window") } - if err := s.OnboardBuildersFromPendingDeposits(); err != nil { + if err := s.OnboardBuildersFromPendingDeposits(ctx); err != nil { return nil, errors.Wrap(err, "failed to onboard builders from pending deposits") } return s, nil @@ -115,17 +136,16 @@ func UpgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { // initializePTCWindow builds the initial PTC window for the Gloas fork upgrade. // -// +// // def initialize_ptc_window( // state: BeaconState, -// ) -> Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH]: +// ) -> PTCWindow: // """ // Return the cached PTC window starting from the current epoch. // Used to initialize the ``ptc_window`` field in the beacon state at genesis and after forks. // """ // empty_previous_epoch = [ -// Vector[ValidatorIndex, PTC_SIZE]([ValidatorIndex(0) for _ in range(PTC_SIZE)]) -// for _ in range(SLOTS_PER_EPOCH) +// PTC([ValidatorIndex(0) for _ in range(PTC_SIZE)]) for _ in range(SLOTS_PER_EPOCH) // ] // // ptcs = [] @@ -135,7 +155,7 @@ func UpgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { // start_slot = compute_start_slot_at_epoch(epoch) // ptcs += [compute_ptc(state, Slot(start_slot + i)) for i in range(SLOTS_PER_EPOCH)] // -// return empty_previous_epoch + ptcs +// return PTCWindow(empty_previous_epoch + ptcs) // func initializePTCWindow(ctx context.Context, st state.ReadOnlyBeaconState) ([]*ethpb.PTCs, error) { currentEpoch := slots.ToEpoch(st.Slot()) @@ -264,6 +284,8 @@ func upgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { return nil, errors.Wrap(err, "could not compute empty execution requests root") } + latestBlockHeader := beaconState.LatestBlockHeader() + s := ðpb.BeaconStateGloas{ GenesisTime: uint64(beaconState.GenesisTime().Unix()), GenesisValidatorsRoot: beaconState.GenesisValidatorsRoot(), @@ -273,7 +295,7 @@ func upgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { CurrentVersion: params.BeaconConfig().GloasForkVersion, Epoch: time.CurrentEpoch(beaconState), }, - LatestBlockHeader: beaconState.LatestBlockHeader(), + LatestBlockHeader: latestBlockHeader, BlockRoots: beaconState.BlockRoots(), StateRoots: beaconState.StateRoots(), HistoricalRoots: beaconState.HistoricalRoots(), @@ -294,12 +316,14 @@ func upgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { CurrentSyncCommittee: currentSyncCommittee, NextSyncCommittee: nextSyncCommittee, LatestExecutionPayloadBid: ðpb.ExecutionPayloadBid{ + ParentBlockHash: payloadHeader.ParentHash(), + ParentBlockRoot: latestBlockHeader.ParentRoot, BlockHash: payloadHeader.BlockHash(), - GasLimit: payloadHeader.GasLimit(), + PrevRandao: payloadHeader.PrevRandao(), FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), - ParentBlockHash: make([]byte, fieldparams.RootLength), - ParentBlockRoot: make([]byte, fieldparams.RootLength), - PrevRandao: make([]byte, fieldparams.RootLength), + GasLimit: payloadHeader.GasLimit(), + BuilderIndex: params.BeaconConfig().BuilderIndexSelfBuild, + Slot: latestBlockHeader.Slot, ExecutionRequestsRoot: emptyExecutionRequestsRoot[:], }, NextWithdrawalIndex: wi, diff --git a/beacon-chain/core/gloas/upgrade_test.go b/beacon-chain/core/gloas/upgrade_test.go index 193d41f9b102..c2890a26c95f 100644 --- a/beacon-chain/core/gloas/upgrade_test.go +++ b/beacon-chain/core/gloas/upgrade_test.go @@ -2,6 +2,7 @@ package gloas_test import ( "bytes" + "context" "testing" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" @@ -12,6 +13,7 @@ import ( consensusblocks "github.com/OffchainLabs/prysm/v7/consensus-types/blocks" "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" "github.com/OffchainLabs/prysm/v7/crypto/bls" + "github.com/OffchainLabs/prysm/v7/encoding/bytesutil" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" "github.com/OffchainLabs/prysm/v7/testing/require" @@ -19,6 +21,15 @@ import ( "github.com/OffchainLabs/prysm/v7/time/slots" ) +func TestUpgradeToGloas_ContextCancellation(t *testing.T) { + st, _ := util.DeterministicGenesisStateFulu(t, params.BeaconConfig().MaxValidatorsPerCommittee) + ctx, cancel := context.WithCancel(t.Context()) + cancel() + + _, err := gloas.UpgradeToGloas(ctx, st) + require.ErrorIs(t, err, context.Canceled) +} + func TestUpgradeToGloas_Basic(t *testing.T) { st, _ := util.DeterministicGenesisStateFulu(t, params.BeaconConfig().MaxValidatorsPerCommittee) @@ -35,13 +46,15 @@ func TestUpgradeToGloas_Basic(t *testing.T) { require.NoError(t, st.SetPendingConsolidations([]*ethpb.PendingConsolidation{{SourceIndex: 3, TargetIndex: 4}})) blockHash := bytes.Repeat([]byte{0xAB}, 32) - header := &enginev1.ExecutionPayloadHeaderDeneb{BlockHash: blockHash} + parentHash := bytes.Repeat([]byte{0xCD}, 32) + prevRandao := bytes.Repeat([]byte{0xEF}, 32) + header := &enginev1.ExecutionPayloadHeaderDeneb{BlockHash: blockHash, ParentHash: parentHash, PrevRandao: prevRandao} wrappedHeader, err := consensusblocks.WrappedExecutionPayloadHeaderDeneb(header) require.NoError(t, err) require.NoError(t, st.SetLatestExecutionPayloadHeader(wrappedHeader)) preForkState := st.Copy() - mSt, err := gloas.UpgradeToGloas(st) + mSt, err := gloas.UpgradeToGloas(t.Context(), st) require.NoError(t, err) require.Equal(t, preForkState.GenesisTime(), mSt.GenesisTime()) @@ -60,9 +73,11 @@ func TestUpgradeToGloas_Basic(t *testing.T) { copy(wantBlockHash[:], blockHash) require.DeepSSZEqual(t, wantBlockHash, bid.BlockHash()) require.DeepSSZEqual(t, [20]byte{}, bid.FeeRecipient()) - require.DeepSSZEqual(t, [32]byte{}, bid.ParentBlockHash()) - require.DeepSSZEqual(t, [32]byte{}, bid.ParentBlockRoot()) - require.DeepSSZEqual(t, [32]byte{}, bid.PrevRandao()) + require.DeepSSZEqual(t, bytesutil.ToBytes32(parentHash), bid.ParentBlockHash()) + require.DeepSSZEqual(t, bytesutil.ToBytes32(preForkState.LatestBlockHeader().ParentRoot), bid.ParentBlockRoot()) + require.DeepSSZEqual(t, bytesutil.ToBytes32(prevRandao), bid.PrevRandao()) + require.Equal(t, params.BeaconConfig().BuilderIndexSelfBuild, bid.BuilderIndex()) + require.Equal(t, preForkState.LatestBlockHeader().Slot, bid.Slot()) latestBlockHash, err := mSt.LatestBlockHash() require.NoError(t, err) @@ -114,7 +129,7 @@ func TestUpgradeToGloas_OnboardsBuilderDeposit(t *testing.T) { require.NoError(t, st.SetPendingDeposits([]*ethpb.PendingDeposit{deposit})) - mSt, err := gloas.UpgradeToGloas(st) + mSt, err := gloas.UpgradeToGloas(t.Context(), st) require.NoError(t, err) pbState, ok := mSt.ToProtoUnsafe().(*ethpb.BeaconStateGloas) diff --git a/beacon-chain/core/transition/gloas.go b/beacon-chain/core/transition/gloas.go index 675e8cba84cb..588ac4d7f8bc 100644 --- a/beacon-chain/core/transition/gloas.go +++ b/beacon-chain/core/transition/gloas.go @@ -3,6 +3,7 @@ package transition import ( "context" + "github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/epoch/precompute" @@ -20,19 +21,33 @@ import ( // // Spec definition: // -// -// def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: +// +// def process_operations( +// state: BeaconState, +// body: BeaconBlockBody, +// # [New in Gloas:EIP7732] +// parent_slot: Slot, +// ) -> None: // assert len(body.deposits) == 0 // -// def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: +// # [Modified in Gloas:EIP7732] +// def for_ops(operations: Sequence[Any], fn: Callable[..., None], *args: Any) -> None: // for operation in operations: -// fn(state, operation) +// fn(state, operation, *args) +// +// # [New in Gloas:EIP7688] +// assert len(body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS +// assert len(body.attester_slashings) <= MAX_ATTESTER_SLASHINGS_ELECTRA +// assert len(body.attestations) <= MAX_ATTESTATIONS_ELECTRA +// assert len(body.voluntary_exits) <= MAX_VOLUNTARY_EXITS +// assert len(body.bls_to_execution_changes) <= MAX_BLS_TO_EXECUTION_CHANGES +// assert len(body.payload_attestations) <= MAX_PAYLOAD_ATTESTATIONS // // # [Modified in Gloas:EIP7732] // for_ops(body.proposer_slashings, process_proposer_slashing) // for_ops(body.attester_slashings, process_attester_slashing) // # [Modified in Gloas:EIP7732] -// for_ops(body.attestations, process_attestation) +// for_ops(body.attestations, process_attestation, parent_slot) // for_ops(body.voluntary_exits, process_voluntary_exit) // for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) // # [Modified in Gloas:EIP7732] @@ -44,7 +59,7 @@ import ( // # [New in Gloas:EIP7732] // for_ops(body.payload_attestations, process_payload_attestation) // -func gloasOperations(ctx context.Context, st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error) { +func gloasOperations(ctx context.Context, st state.BeaconState, block interfaces.ReadOnlyBeaconBlock, parentSlot primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.gloasOperations") defer span.End() @@ -69,7 +84,7 @@ func gloasOperations(ctx context.Context, st state.BeaconState, block interfaces if err != nil { return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error()) } - st, err = electra.ProcessAttestationsNoVerifySignature(ctx, st, block) + st, err = altair.ProcessAttestationsNoVerifySignatureWithParentSlot(ctx, st, block, parentSlot) if err != nil { return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error()) } diff --git a/beacon-chain/core/transition/gloas_operations_test.go b/beacon-chain/core/transition/gloas_operations_test.go index bba5a2d8bb01..2c09b2583e28 100644 --- a/beacon-chain/core/transition/gloas_operations_test.go +++ b/beacon-chain/core/transition/gloas_operations_test.go @@ -33,7 +33,7 @@ func TestGloasOperations_HappyPath(t *testing.T) { // A plain Electra state is fine here because we exercise zero operations. blk := newGloasBlock(t, emptyGloasBody()) - _, err := transition.GloasOperations(context.Background(), st, blk) + _, err := transition.GloasOperations(context.Background(), st, blk, 0) require.NoError(t, err) } @@ -226,7 +226,7 @@ func TestGloasOperations_ProcessingErrors(t *testing.T) { gloasBlk := newGloasBlock(t, body) - _, err := transition.GloasOperations(ctx, st, gloasBlk) + _, err := transition.GloasOperations(ctx, st, gloasBlk, 0) require.NotNil(t, err, "expected an error but got nil") require.ErrorContains(t, tc.errSubstr, err) require.Equal(t, true, errors.Is(err, tc.errSentinel)) diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index bbb3d6bf97fe..22c59548e7e4 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -425,7 +425,7 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta } if time.CanUpgradeToGloas(slot) { - state, err = gloas.UpgradeToGloas(state) + state, err = gloas.UpgradeToGloas(ctx, state) if err != nil { tracing.AnnotateError(span, err) return nil, err diff --git a/beacon-chain/core/transition/transition_fuzz_test.go b/beacon-chain/core/transition/transition_fuzz_test.go index 652c90e01bb0..a6dbc42190a8 100644 --- a/beacon-chain/core/transition/transition_fuzz_test.go +++ b/beacon-chain/core/transition/transition_fuzz_test.go @@ -113,7 +113,7 @@ func TestFuzzprocessOperationsNoVerify_1000(t *testing.T) { } wb, err := blocks.NewBeaconBlock(bb) require.NoError(t, err) - s, err := ProcessOperationsNoVerifyAttsSigs(ctx, state, wb) + s, err := ProcessOperationsNoVerifyAttsSigs(ctx, state, wb, 0) if err != nil && s != nil { t.Fatalf("state should be nil on err. found: %v on error: %v for block body: %v", s, err, bb) } diff --git a/beacon-chain/core/transition/transition_no_verify_sig.go b/beacon-chain/core/transition/transition_no_verify_sig.go index 3597835fd41c..d0e37c146d53 100644 --- a/beacon-chain/core/transition/transition_no_verify_sig.go +++ b/beacon-chain/core/transition/transition_no_verify_sig.go @@ -14,6 +14,7 @@ import ( "github.com/OffchainLabs/prysm/v7/config/features" "github.com/OffchainLabs/prysm/v7/consensus-types/blocks" "github.com/OffchainLabs/prysm/v7/consensus-types/interfaces" + "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" "github.com/OffchainLabs/prysm/v7/crypto/bls" "github.com/OffchainLabs/prysm/v7/monitoring/tracing" "github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace" @@ -346,7 +347,8 @@ func ProcessBlockNoVerifyAnySig( func ProcessOperationsNoVerifyAttsSigs( ctx context.Context, state state.BeaconState, - beaconBlock interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error) { + beaconBlock interfaces.ReadOnlyBeaconBlock, + parentSlot primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.ProcessOperationsNoVerifyAttsSigs") defer span.End() if beaconBlock == nil || beaconBlock.IsNil() { @@ -359,7 +361,7 @@ func ProcessOperationsNoVerifyAttsSigs( blockVersion := beaconBlock.Version() if blockVersion >= version.Gloas { - state, err := gloasOperations(ctx, state, beaconBlock) + state, err := gloasOperations(ctx, state, beaconBlock, parentSlot) if err != nil { return nil, fmt.Errorf("gloas operations: %w", err) } @@ -437,8 +439,9 @@ func ProcessBlockForStateRoot( return nil, errors.Wrap(err, "could not process block header") } + var parentSlot primitives.Slot if state.Version() >= version.Gloas { - // + // // def process_block(state: BeaconState, block: BeaconBlock) -> None: // # [New in Gloas:EIP7732] // process_parent_execution_payload(state, block) @@ -448,16 +451,21 @@ func ProcessBlockForStateRoot( // # [Modified in Gloas:EIP7732] // # Removed `process_execution_payload` // # [New in Gloas:EIP7732] - // process_execution_payload_bid(state, block.body.signed_execution_payload_bid) + // parent_slot = process_execution_payload_bid(state, block.body.signed_execution_payload_bid) // process_randao(state, block.body) // process_eth1_data(state, block.body) // # [Modified in Gloas:EIP7732] - // process_operations(state, block.body) + // process_operations(state, block.body, parent_slot) // process_sync_aggregate(state, block.body.sync_aggregate) // if err := gloas.ProcessWithdrawals(state); err != nil { return nil, errors.Wrap(ErrProcessWithdrawalsFailed, err.Error()) } + // Read before the bid is replaced by this block's, process_attestation needs the parent's slot. + parentSlot, err = gloas.ParentSlotFromBid(state) + if err != nil { + return nil, errors.Wrap(err, "could not get parent slot from bid") + } if err := gloas.ProcessExecutionPayloadBid(state, blk); err != nil { return nil, errors.Wrap(err, "could not process execution payload bid") } @@ -496,7 +504,7 @@ func ProcessBlockForStateRoot( return nil, errors.Wrap(ErrProcessEth1DataFailed, err.Error()) } - state, err = ProcessOperationsNoVerifyAttsSigs(ctx, state, signed.Block()) + state, err = ProcessOperationsNoVerifyAttsSigs(ctx, state, signed.Block(), parentSlot) if err != nil { tracing.AnnotateError(span, err) return nil, errors.Wrap(err, "could not process block operation") diff --git a/beacon-chain/core/transition/transition_no_verify_sig_test.go b/beacon-chain/core/transition/transition_no_verify_sig_test.go index 7eeecc0690ae..0858456d4273 100644 --- a/beacon-chain/core/transition/transition_no_verify_sig_test.go +++ b/beacon-chain/core/transition/transition_no_verify_sig_test.go @@ -170,7 +170,7 @@ func TestProcessOperationsNoVerifyAttsSigs_OK(t *testing.T) { require.NoError(t, err) beaconState, err = transition.ProcessSlots(t.Context(), beaconState, wsb.Block().Slot()) require.NoError(t, err) - _, err = transition.ProcessOperationsNoVerifyAttsSigs(t.Context(), beaconState, wsb.Block()) + _, err = transition.ProcessOperationsNoVerifyAttsSigs(t.Context(), beaconState, wsb.Block(), 0) require.NoError(t, err) } @@ -180,7 +180,7 @@ func TestProcessOperationsNoVerifyAttsSigsBellatrix_OK(t *testing.T) { require.NoError(t, err) beaconState, err = transition.ProcessSlots(t.Context(), beaconState, wsb.Block().Slot()) require.NoError(t, err) - _, err = transition.ProcessOperationsNoVerifyAttsSigs(t.Context(), beaconState, wsb.Block()) + _, err = transition.ProcessOperationsNoVerifyAttsSigs(t.Context(), beaconState, wsb.Block(), 0) require.NoError(t, err) } @@ -190,7 +190,7 @@ func TestProcessOperationsNoVerifyAttsSigsCapella_OK(t *testing.T) { require.NoError(t, err) beaconState, err = transition.ProcessSlots(t.Context(), beaconState, wsb.Block().Slot()) require.NoError(t, err) - _, err = transition.ProcessOperationsNoVerifyAttsSigs(t.Context(), beaconState, wsb.Block()) + _, err = transition.ProcessOperationsNoVerifyAttsSigs(t.Context(), beaconState, wsb.Block(), 0) require.NoError(t, err) } diff --git a/beacon-chain/db/kv/state_diff_test.go b/beacon-chain/db/kv/state_diff_test.go index d33be67c04a0..de8fa028550b 100644 --- a/beacon-chain/db/kv/state_diff_test.go +++ b/beacon-chain/db/kv/state_diff_test.go @@ -746,7 +746,7 @@ func TestStateDiff_SaveAndReadDiffForkTransitionGloas(t *testing.T) { require.NoError(t, err) slot := primitives.Slot(math.PowerOf2(5)) - gloasSt, err := gloas.UpgradeToGloas(st.Copy()) + gloasSt, err := gloas.UpgradeToGloas(t.Context(), st.Copy()) require.NoError(t, err) require.NoError(t, gloasSt.SetSlot(slot)) diff --git a/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel b/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel index 333fdfb1c433..0a001e143cb2 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel +++ b/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel @@ -70,6 +70,7 @@ go_test( "//beacon-chain/forkchoice/types:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", diff --git a/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go b/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go index b4608f1c8ed9..18a82a8e6357 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go @@ -138,7 +138,9 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, ro if err != nil { return err } - f.RecordBlockForEquivocation(roblock.Block().Slot(), roblock.Block().ProposerIndex(), roblock.Root()) + if features.Get().TrackEquivocations { + f.RecordBlockForEquivocation(roblock.Block().Slot(), roblock.Block().ProposerIndex(), roblock.Root()) + } jc, fc = f.store.pullTips(state, pn.node, jc, fc) if err := f.updateCheckpoints(ctx, jc, fc); err != nil { _, remErr := f.store.removeNode(ctx, pn) diff --git a/beacon-chain/forkchoice/doubly-linked-tree/forkchoice_test.go b/beacon-chain/forkchoice/doubly-linked-tree/forkchoice_test.go index 8a8d3c3cfd18..a7809bb886a4 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/forkchoice_test.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/forkchoice_test.go @@ -9,6 +9,7 @@ import ( forkchoicetypes "github.com/OffchainLabs/prysm/v7/beacon-chain/forkchoice/types" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native" + "github.com/OffchainLabs/prysm/v7/config/features" "github.com/OffchainLabs/prysm/v7/config/params" "github.com/OffchainLabs/prysm/v7/consensus-types/blocks" "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" @@ -430,6 +431,8 @@ func TestForkChoice_RecordBlockForEquivocation_DedupesRoot(t *testing.T) { } func TestForkChoice_InsertNode_RecordsFirstSeen(t *testing.T) { + resetFn := features.InitWithReset(&features.Flags{TrackEquivocations: true}) + defer resetFn() f := setup(0, 0) blockRoot := indexToHash(1) st, roblock, err := prepareForkchoiceState(t.Context(), 1, blockRoot, params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0) diff --git a/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks.go b/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks.go index 689758c69192..465714e757d7 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks.go @@ -46,6 +46,12 @@ func (f *ForkChoice) ShouldOverrideFCU() (override bool) { return } + // is_shuffling_stable, removed in Fulu by EIP-7917 + proposalSlot := consensusHead.slot + 1 + if slots.ToEpoch(proposalSlot) < params.BeaconConfig().FuluForkEpoch && slots.IsEpochStart(proposalSlot) { + return + } + head := f.store.choosePayloadContent(consensusHead) // Only reorg blocks that arrive late early, err := head.arrivedEarly(f.store.genesisTime) @@ -112,6 +118,10 @@ func (f *ForkChoice) GetProposerHead() [32]byte { if consensusHead.slot+1 != currentSlot { return consensusHead.root } + // is_shuffling_stable, removed in Fulu by EIP-7917 + if slots.ToEpoch(currentSlot) < params.BeaconConfig().FuluForkEpoch && slots.IsEpochStart(currentSlot) { + return consensusHead.root + } // Only reorg blocks that arrive late head := f.store.choosePayloadContent(consensusHead) if slots.ToEpoch(consensusHead.slot) >= params.BeaconConfig().GloasForkEpoch { diff --git a/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks_test.go b/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks_test.go index 02844c0e511c..87b874057e8d 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks_test.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks_test.go @@ -186,6 +186,10 @@ func TestForkChoice_GetProposerHead(t *testing.T) { // Regression test: a weak, late head whose next slot lands on an epoch boundary // must still be reorgeable. Reorgs used to be skipped on epoch boundaries. func TestForkChoice_ShouldOverrideFCU_EpochBoundary(t *testing.T) { + params.SetupTestConfigCleanup(t) + cfg := params.BeaconConfig().Copy() + cfg.FuluForkEpoch = 0 + params.OverrideBeaconConfig(cfg) f := setup(0, 0) numValidators := uint64(640) f.justifiedBalances = make([]uint64, numValidators) @@ -223,6 +227,10 @@ func TestForkChoice_ShouldOverrideFCU_EpochBoundary(t *testing.T) { // Regression test: GetProposerHead must orphan a weak, late head even when the // proposing slot is an epoch boundary. func TestForkChoice_GetProposerHead_EpochBoundary(t *testing.T) { + params.SetupTestConfigCleanup(t) + cfg := params.BeaconConfig().Copy() + cfg.FuluForkEpoch = 0 + params.OverrideBeaconConfig(cfg) f := setup(0, 0) numValidators := uint64(640) f.justifiedBalances = make([]uint64, numValidators) diff --git a/beacon-chain/light-client/lightclient.go b/beacon-chain/light-client/lightclient.go index df91e3ac360a..277463a1a966 100644 --- a/beacon-chain/light-client/lightclient.go +++ b/beacon-chain/light-client/lightclient.go @@ -525,7 +525,7 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) { } func progressiveExecutionPayloadSSZEnabled(payload interfaces.ExecutionData) bool { - if payload == nil || !features.Get().EnableProgressiveSSZ { + if payload == nil || !features.ProgressiveSSZEnabled(version.Gloas) { return false } _, ok := payload.Proto().(*enginev1.ExecutionPayloadGloas) diff --git a/beacon-chain/light-client/progressive_ssz_test.go b/beacon-chain/light-client/progressive_ssz_test.go index 349b96d4f010..c2cd5039c1de 100644 --- a/beacon-chain/light-client/progressive_ssz_test.go +++ b/beacon-chain/light-client/progressive_ssz_test.go @@ -29,7 +29,7 @@ func TestProgressiveExecutionPayloadSSZEnabled(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: tt.enabled}) + reset := features.InitWithReset(&features.Flags{DisableProgressiveSSZ: !tt.enabled}) defer reset() require.Equal(t, tt.want, progressiveExecutionPayloadSSZEnabled(tt.payload)) diff --git a/beacon-chain/state/fieldtrie/progressive_test.go b/beacon-chain/state/fieldtrie/progressive_test.go index 5861c7f29274..e9307e0aaa0b 100644 --- a/beacon-chain/state/fieldtrie/progressive_test.go +++ b/beacon-chain/state/fieldtrie/progressive_test.go @@ -19,7 +19,7 @@ import ( // stateutil reference helpers return the progressive form. func progressiveRootsEnabled(t *testing.T) { t.Helper() - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) t.Cleanup(reset) } diff --git a/beacon-chain/state/interfaces_gloas.go b/beacon-chain/state/interfaces_gloas.go index ea39e3e3387a..6f4280d84076 100644 --- a/beacon-chain/state/interfaces_gloas.go +++ b/beacon-chain/state/interfaces_gloas.go @@ -1,6 +1,8 @@ package state import ( + "context" + fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams" "github.com/OffchainLabs/prysm/v7/consensus-types/interfaces" "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" @@ -45,7 +47,7 @@ type writeOnlyGloasFields interface { DecreaseWithdrawalBalances(withdrawals []*enginev1.Withdrawal) error DequeueBuilderPendingWithdrawals(num uint64) error SetNextWithdrawalBuilderIndex(idx primitives.BuilderIndex) error - OnboardBuildersFromPendingDeposits() error + OnboardBuildersFromPendingDeposits(context.Context) error } type readOnlyGloasFields interface { diff --git a/beacon-chain/state/state-native/getters_gloas.go b/beacon-chain/state/state-native/getters_gloas.go index bf781de1e6f8..03590a9b1739 100644 --- a/beacon-chain/state/state-native/getters_gloas.go +++ b/beacon-chain/state/state-native/getters_gloas.go @@ -375,10 +375,10 @@ func (b *BeaconState) builderIndexByPubkey(pubkey [fieldparams.BLSPubkeyLength]b // applied to the current state. It is also used by validators to check that the execution payload carried // the right number of withdrawals. // -// +// // def get_expected_withdrawals(state: BeaconState) -> ExpectedWithdrawals: // withdrawal_index = state.next_withdrawal_index -// withdrawals: List[Withdrawal] = [] +// withdrawals: list[Withdrawal] = [] // // # [New in Gloas:EIP7732] // # Get builder withdrawals @@ -459,19 +459,19 @@ func (b *BeaconState) ExpectedWithdrawalsGloas() (state.ExpectedWithdrawalsGloas // appendBuilderWithdrawals returns builder pending withdrawals, the updated withdrawal index, // and the processed count. // -// +// // def get_builder_withdrawals( // state: BeaconState, // withdrawal_index: WithdrawalIndex, // prior_withdrawals: Sequence[Withdrawal], -// ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: +// ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: // withdrawals_limit = MAX_WITHDRAWALS_PER_PAYLOAD - 1 // assert len(prior_withdrawals) <= withdrawals_limit // -// processed_count: uint64 = 0 -// withdrawals: List[Withdrawal] = [] +// processed_count: Uint64 = 0 +// withdrawals: list[Withdrawal] = [] // for withdrawal in state.builder_pending_withdrawals: -// all_withdrawals = prior_withdrawals + withdrawals +// all_withdrawals = list(prior_withdrawals) + withdrawals // has_reached_limit = len(all_withdrawals) >= withdrawals_limit // if has_reached_limit: // break @@ -521,22 +521,22 @@ func (b *BeaconState) appendBuilderWithdrawals(withdrawalIndex uint64, withdrawa // appendBuildersSweepWithdrawals returns builder sweep withdrawals, the updated withdrawal index, // and the processed count. // -// +// // def get_builders_sweep_withdrawals( // state: BeaconState, // withdrawal_index: WithdrawalIndex, // prior_withdrawals: Sequence[Withdrawal], -// ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: +// ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: // epoch = get_current_epoch(state) // builders_limit = min(len(state.builders), MAX_BUILDERS_PER_WITHDRAWALS_SWEEP) // withdrawals_limit = MAX_WITHDRAWALS_PER_PAYLOAD - 1 // assert len(prior_withdrawals) <= withdrawals_limit // -// processed_count: uint64 = 0 -// withdrawals: List[Withdrawal] = [] +// processed_count: Uint64 = 0 +// withdrawals: list[Withdrawal] = [] // builder_index = state.next_withdrawal_builder_index // for _ in range(builders_limit): -// all_withdrawals = prior_withdrawals + withdrawals +// all_withdrawals = list(prior_withdrawals) + withdrawals // has_reached_limit = len(all_withdrawals) >= withdrawals_limit // if has_reached_limit: // break @@ -693,8 +693,8 @@ func (b *BeaconState) NextWithdrawalBuilderIndex() (primitives.BuilderIndex, err // PayloadCommitteeReadOnly returns the payload timeliness committee for a given slot // by looking up the cached PTC window in state. // -// -// def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: +// +// def get_ptc(state: BeaconState, slot: Slot) -> PTC: // """ // Get the payload timeliness committee for the given ``slot``. // """ diff --git a/beacon-chain/state/state-native/progressive_ssz_test.go b/beacon-chain/state/state-native/progressive_ssz_test.go index d85a622706ff..b1b9d5118ce9 100644 --- a/beacon-chain/state/state-native/progressive_ssz_test.go +++ b/beacon-chain/state/state-native/progressive_ssz_test.go @@ -20,11 +20,11 @@ import ( ) func TestProgressiveSSZEnabled(t *testing.T) { - reset := features.InitWithReset(&features.Flags{}) + reset := features.InitWithReset(&features.Flags{DisableProgressiveSSZ: true}) defer reset() require.Equal(t, false, features.ProgressiveSSZEnabled(version.Gloas)) - reset = features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset = features.InitWithReset(&features.Flags{}) defer reset() require.Equal(t, true, features.ProgressiveSSZEnabled(version.Gloas)) require.Equal(t, false, features.ProgressiveSSZEnabled(version.Fulu)) @@ -43,7 +43,7 @@ func TestComputeFieldRootsWithHasher_ProgressiveSSZFields(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: tt.progressive}) + reset := features.InitWithReset(&features.Flags{DisableProgressiveSSZ: !tt.progressive}) defer reset() roots, err := ComputeFieldRootsWithHasher(context.Background(), st) @@ -116,7 +116,7 @@ func TestHashTreeRoot(t *testing.T) { t.Run("ProgressiveSSZGate", func(t *testing.T) { st := newGloasStateForProgressiveSSZTests(t) - reset := features.InitWithReset(&features.Flags{}) + reset := features.InitWithReset(&features.Flags{DisableProgressiveSSZ: true}) defer reset() legacyRoot, err := st.HashTreeRoot(context.Background()) @@ -128,7 +128,7 @@ func TestHashTreeRoot(t *testing.T) { expectedLegacyRoot := bytesutil.ToBytes32(legacyLayers[len(legacyLayers)-1][0]) require.Equal(t, expectedLegacyRoot, legacyRoot) - reset = features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset = features.InitWithReset(&features.Flags{DisableProgressiveSSZ: false}) defer reset() progressiveRoot, err := st.HashTreeRoot(context.Background()) @@ -157,9 +157,6 @@ func TestHashTreeRoot(t *testing.T) { }) t.Run("ProgressiveSSZIncremental", func(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) - defer reset() - st := newGloasStateForProgressiveSSZTests(t) initialRoot, err := st.HashTreeRoot(context.Background()) require.NoError(t, err) @@ -195,9 +192,6 @@ func TestHashTreeRoot(t *testing.T) { }) t.Run("ProgressiveSSZCopy", func(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) - defer reset() - st := newGloasStateForProgressiveSSZTests(t) originalRoot, err := st.HashTreeRoot(context.Background()) require.NoError(t, err) diff --git a/beacon-chain/state/state-native/setters_gloas.go b/beacon-chain/state/state-native/setters_gloas.go index b6cd146d12a4..140aae766f52 100644 --- a/beacon-chain/state/state-native/setters_gloas.go +++ b/beacon-chain/state/state-native/setters_gloas.go @@ -1,6 +1,7 @@ package state_native import ( + "context" "errors" "fmt" @@ -368,8 +369,7 @@ func (b *BeaconState) AddBuilderFromDeposit(pubkey [fieldparams.BLSPubkeyLength] b.lock.Lock() defer b.lock.Unlock() - // process_builder_deposit_request sets version to withdrawal_credentials[0]. - return b.addBuilderFromDepositAtEpoch(pubkey, withdrawalCredentials[0], withdrawalCredentials, amount, slots.ToEpoch(b.slot)) + return b.addBuilderFromDepositAtEpoch(pubkey, params.BeaconConfig().PayloadBuilderVersion, withdrawalCredentials, amount, slots.ToEpoch(b.slot)) } func (b *BeaconState) addBuilderFromDepositAtEpoch(pubkey [fieldparams.BLSPubkeyLength]byte, builderVersion byte, withdrawalCredentials [fieldparams.RootLength]byte, amount uint64, depositEpoch primitives.Epoch) error { @@ -682,10 +682,21 @@ func decreaseBalanceWithVal(currBalance, delta primitives.Gwei) primitives.Gwei return currBalance - delta } +type depositSignatureVerifier func(*ethpb.Deposit_Data) (bool, error) + +// pendingValidatorStatus caches signature checks for the already-processed prefix of pending +// deposits for one pubkey. A literal implementation of is_pending_validator rescans and +// reverifies that prefix for every builder deposit, which can require quadratic work. +type pendingValidatorStatus struct { + deposits []*ethpb.PendingDeposit + checked int + found bool +} + // OnboardBuildersFromPendingDeposits applies any pending builder deposits at the fork. // It mutates the state and prunes pending deposits accordingly. // -// +// // def onboard_builders_from_pending_deposits(state: BeaconState) -> None: // """ // Applies any pending deposit for builders, effectively @@ -693,7 +704,7 @@ func decreaseBalanceWithVal(currBalance, delta primitives.Gwei) primitives.Gwei // """ // validator_pubkeys = [v.pubkey for v in state.validators] // -// pending_deposits = [] +// pending_deposits = PendingDeposits() // for deposit in state.pending_deposits: // # Deposits for existing validators stay in the pending queue // if deposit.pubkey in validator_pubkeys: @@ -737,18 +748,31 @@ func decreaseBalanceWithVal(currBalance, delta primitives.Gwei) primitives.Gwei // // state.pending_deposits = pending_deposits // -func (b *BeaconState) OnboardBuildersFromPendingDeposits() error { +func (b *BeaconState) OnboardBuildersFromPendingDeposits(ctx context.Context) error { + return b.onboardBuildersFromPendingDeposits(ctx, helpers.IsValidDepositSignature) +} + +func (b *BeaconState) onboardBuildersFromPendingDeposits(ctx context.Context, verify depositSignatureVerifier) error { if b.version < version.Gloas { return errNotSupported("OnboardBuildersFromPendingDeposits", b.version) } + if err := ctx.Err(); err != nil { + return err + } b.lock.Lock() defer b.lock.Unlock() pendingDeposits := b.pendingDeposits newPendingDeposits := make([]*ethpb.PendingDeposit, 0, len(pendingDeposits)) + // For every pubkey in this map, found is true exactly when the already-built + // newPendingDeposits prefix contains a valid deposit for that pubkey. + pendingValidators := make(map[[fieldparams.BLSPubkeyLength]byte]*pendingValidatorStatus) for _, deposit := range pendingDeposits { + if err := ctx.Err(); err != nil { + return err + } pubkey := bytesutil.ToBytes48(deposit.PublicKey) if _, ok := b.validatorIndexByPubkey(pubkey); ok { newPendingDeposits = append(newPendingDeposits, deposit) @@ -765,21 +789,54 @@ func (b *BeaconState) OnboardBuildersFromPendingDeposits() error { if !helpers.IsBuilderWithdrawalCredential(deposit.WithdrawalCredentials) { newPendingDeposits = append(newPendingDeposits, deposit) + status := pendingValidators[pubkey] + if status == nil { + status = &pendingValidatorStatus{} + pendingValidators[pubkey] = status + } + if !status.found { + status.deposits = append(status.deposits, deposit) + } continue } - isPending, err := helpers.IsPendingValidator(newPendingDeposits, deposit.PublicKey) - if err != nil { - return err + + status := pendingValidators[pubkey] + if status != nil { + // Verify only deposits appended since the previous builder candidate. Invalid + // deposits remain in the pending queue but never need to be verified again here. + for !status.found && status.checked < len(status.deposits) { + if err := ctx.Err(); err != nil { + return err + } + pendingDeposit := status.deposits[status.checked] + status.checked++ + valid, err := verify(ðpb.Deposit_Data{ + PublicKey: pendingDeposit.PublicKey, + WithdrawalCredentials: pendingDeposit.WithdrawalCredentials, + Amount: pendingDeposit.Amount, + Signature: pendingDeposit.Signature, + }) + if err != nil { + log.WithField("pubkey", fmt.Sprintf("%x", pendingDeposit.PublicKey)).WithError(err).Warn("Could not verify pending deposit signature") + continue + } + if valid { + status.found = true + } + } } - if isPending { + if status != nil && status.found { newPendingDeposits = append(newPendingDeposits, deposit) continue } - if err := b.applyDepositForNewBuilder(deposit); err != nil { + if err := b.applyDepositForNewBuilder(ctx, deposit, verify); err != nil { return err } } + if err := ctx.Err(); err != nil { + return err + } b.sharedFieldReferences[types.PendingDeposits].MinusRef() b.sharedFieldReferences[types.PendingDeposits] = stateutil.NewRef(1) @@ -790,8 +847,11 @@ func (b *BeaconState) OnboardBuildersFromPendingDeposits() error { } // applyDepositForNewBuilder onboards a single pending deposit as a new builder, used by onboard_builders_from_pending_deposits. -func (b *BeaconState) applyDepositForNewBuilder(deposit *ethpb.PendingDeposit) error { - valid, err := helpers.IsValidDepositSignature(ðpb.Deposit_Data{ +func (b *BeaconState) applyDepositForNewBuilder(ctx context.Context, deposit *ethpb.PendingDeposit, verify depositSignatureVerifier) error { + if err := ctx.Err(); err != nil { + return err + } + valid, err := verify(ðpb.Deposit_Data{ PublicKey: deposit.PublicKey, WithdrawalCredentials: deposit.WithdrawalCredentials, Amount: deposit.Amount, @@ -805,6 +865,9 @@ func (b *BeaconState) applyDepositForNewBuilder(deposit *ethpb.PendingDeposit) e log.WithField("pubkey", fmt.Sprintf("%x", deposit.PublicKey)).Debug("Skipping builder deposit with invalid signature") return nil } + if err := ctx.Err(); err != nil { + return err + } pubkey := bytesutil.ToBytes48(deposit.PublicKey) depositEpoch := slots.ToEpoch(deposit.Slot) if err := b.addBuilderFromDepositAtEpoch(pubkey, params.BeaconConfig().PayloadBuilderVersion, bytesutil.ToBytes32(deposit.WithdrawalCredentials), deposit.Amount, depositEpoch); err != nil { diff --git a/beacon-chain/state/state-native/setters_gloas_test.go b/beacon-chain/state/state-native/setters_gloas_test.go index f480635b35ef..2d59d6ff9797 100644 --- a/beacon-chain/state/state-native/setters_gloas_test.go +++ b/beacon-chain/state/state-native/setters_gloas_test.go @@ -2,6 +2,7 @@ package state_native import ( "bytes" + "context" "testing" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing" @@ -910,7 +911,7 @@ func TestAddBuilderFromDeposit(t *testing.T) { copy(pubkey[:], bytes.Repeat([]byte{0xAA}, 48)) var wc [32]byte copy(wc[:], bytes.Repeat([]byte{0xBB}, 32)) - wc[0] = 0x42 // version byte + wc[0] = 0x42 // registered version must ignore the credential prefix st := &BeaconState{ version: version.Gloas, @@ -933,7 +934,7 @@ func TestAddBuilderFromDeposit(t *testing.T) { got := st.builders[0] require.NotNil(t, got) require.DeepEqual(t, pubkey[:], got.Pubkey) - require.DeepEqual(t, []byte{0x42}, got.Version) + require.DeepEqual(t, []byte{params.BeaconConfig().PayloadBuilderVersion}, got.Version) require.DeepEqual(t, wc[12:], got.ExecutionAddress) require.Equal(t, primitives.Gwei(123), got.Balance) require.Equal(t, primitives.Epoch(0), got.DepositEpoch) @@ -1004,7 +1005,7 @@ func TestAddBuilderFromDeposit_CopyOnWrite(t *testing.T) { func TestOnboardBuildersFromPendingDeposits(t *testing.T) { t.Run("returns error before gloas", func(t *testing.T) { st := &BeaconState{version: version.Fulu} - err := st.OnboardBuildersFromPendingDeposits() + err := st.OnboardBuildersFromPendingDeposits(t.Context()) require.ErrorContains(t, "OnboardBuildersFromPendingDeposits", err) }) @@ -1023,7 +1024,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { } st := newGloasState(t, []*ethpb.Validator{validator}, nil, []*ethpb.PendingDeposit{deposit}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 1, len(st.pendingDeposits)) require.Equal(t, 0, len(st.builders)) }) @@ -1037,7 +1038,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { deposit := newPendingDeposit(t, sk, builderCreds, amount, depSlot, true) st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{deposit}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 0, len(st.pendingDeposits)) require.Equal(t, 1, len(st.builders)) @@ -1061,7 +1062,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { deposit := newPendingDeposit(t, sk, nonBuilderCreds, 5, 0, false) st := newGloasState(t, nil, []*ethpb.Builder{builder}, []*ethpb.PendingDeposit{deposit}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 0, len(st.pendingDeposits)) require.Equal(t, 1, len(st.builders)) require.Equal(t, primitives.Gwei(15), st.builders[0].Balance) @@ -1074,7 +1075,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { deposit := newPendingDeposit(t, sk, builderCreds, 10, 0, false) st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{deposit}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 0, len(st.pendingDeposits)) require.Equal(t, 0, len(st.builders)) }) @@ -1089,11 +1090,27 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { depositBuilder := newPendingDeposit(t, sk, builderCreds, 7, 0, true) st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{depositValidator, depositBuilder}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 2, len(st.pendingDeposits)) require.Equal(t, 0, len(st.builders)) }) + t.Run("builder deposit before validator deposit creates builder", func(t *testing.T) { + sk, err := bls.RandKey() + require.NoError(t, err) + builderCreds := builderWithdrawalCredentials(0xEF) + validatorCreds := nonBuilderWithdrawalCredentials() + + depositBuilder := newPendingDeposit(t, sk, builderCreds, 7, 0, true) + depositValidator := newPendingDeposit(t, sk, validatorCreds, 5, 0, true) + + st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{depositBuilder, depositValidator}, 0) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) + require.Equal(t, 0, len(st.pendingDeposits)) + require.Equal(t, 1, len(st.builders)) + require.Equal(t, primitives.Gwei(12), st.builders[0].Balance) + }) + t.Run("keeps invalid non-builder deposit in pending queue", func(t *testing.T) { sk, err := bls.RandKey() require.NoError(t, err) @@ -1101,7 +1118,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { deposit := newPendingDeposit(t, sk, validatorCreds, 5, 0, false) st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{deposit}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 1, len(st.pendingDeposits)) require.Equal(t, 0, len(st.builders)) }) @@ -1115,7 +1132,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { depositTopUp := newPendingDeposit(t, sk, builderCreds, 5, depSlot, true) st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{depositCreate, depositTopUp}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 0, len(st.pendingDeposits)) require.Equal(t, 1, len(st.builders)) require.Equal(t, primitives.Gwei(15), st.builders[0].Balance) @@ -1131,7 +1148,7 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { depositBuilder := newPendingDeposit(t, sk, builderCreds, 7, 0, true) st := newGloasState(t, nil, nil, []*ethpb.PendingDeposit{depositInvalidValidator, depositBuilder}, 0) - require.NoError(t, st.OnboardBuildersFromPendingDeposits()) + require.NoError(t, st.OnboardBuildersFromPendingDeposits(t.Context())) require.Equal(t, 1, len(st.pendingDeposits)) require.DeepEqual(t, depositInvalidValidator, st.pendingDeposits[0]) require.Equal(t, 1, len(st.builders)) @@ -1139,6 +1156,154 @@ func TestOnboardBuildersFromPendingDeposits(t *testing.T) { }) } +func TestOnboardBuildersFromPendingDeposits_VerificationWorkIsLinear(t *testing.T) { + t.Run("invalid pending deposits are checked once", func(t *testing.T) { + const ( + pendingCount = 100 + builderCount = 50 + ) + pubkey := bytes.Repeat([]byte{0x42}, fieldparams.BLSPubkeyLength) + pendingDeposits := make([]*ethpb.PendingDeposit, 0, pendingCount+builderCount) + for i := range pendingCount { + pendingDeposits = append(pendingDeposits, ðpb.PendingDeposit{ + PublicKey: pubkey, + WithdrawalCredentials: nonBuilderWithdrawalCredentials(), + Amount: uint64(i + 1), + Signature: make([]byte, fieldparams.BLSSignatureLength), + }) + } + for i := range builderCount { + pendingDeposits = append(pendingDeposits, ðpb.PendingDeposit{ + PublicKey: pubkey, + WithdrawalCredentials: builderWithdrawalCredentials(byte(i)), + Amount: uint64(pendingCount + i + 1), + Signature: make([]byte, fieldparams.BLSSignatureLength), + }) + } + + st := newGloasState(t, nil, nil, pendingDeposits, 0) + verificationCount := 0 + err := st.onboardBuildersFromPendingDeposits(t.Context(), func(*ethpb.Deposit_Data) (bool, error) { + verificationCount++ + return false, nil + }) + require.NoError(t, err) + + // Each retained pending deposit and each builder candidate is verified at most once. + // The previous implementation performed pendingCount*builderCount+builderCount checks. + require.Equal(t, pendingCount+builderCount, verificationCount) + require.Equal(t, pendingCount, len(st.pendingDeposits)) + require.Equal(t, 0, len(st.builders)) + }) + + t.Run("valid pending validator result is reused", func(t *testing.T) { + const builderCount = 50 + pubkey := bytes.Repeat([]byte{0x43}, fieldparams.BLSPubkeyLength) + pendingDeposits := []*ethpb.PendingDeposit{ + { + PublicKey: pubkey, + WithdrawalCredentials: nonBuilderWithdrawalCredentials(), + Amount: 1, + }, + { + PublicKey: pubkey, + WithdrawalCredentials: nonBuilderWithdrawalCredentials(), + Amount: 2, + }, + } + for i := range builderCount { + pendingDeposits = append(pendingDeposits, ðpb.PendingDeposit{ + PublicKey: pubkey, + WithdrawalCredentials: builderWithdrawalCredentials(byte(i)), + Amount: uint64(i + 3), + }) + } + + st := newGloasState(t, nil, nil, pendingDeposits, 0) + verificationCount := 0 + err := st.onboardBuildersFromPendingDeposits(t.Context(), func(data *ethpb.Deposit_Data) (bool, error) { + verificationCount++ + return data.Amount == 2, nil + }) + require.NoError(t, err) + + require.Equal(t, 2, verificationCount) + require.Equal(t, len(pendingDeposits), len(st.pendingDeposits)) + require.Equal(t, 0, len(st.builders)) + }) + + t.Run("only newly appended pending deposits are checked", func(t *testing.T) { + pubkey := bytes.Repeat([]byte{0x45}, fieldparams.BLSPubkeyLength) + pendingDeposits := []*ethpb.PendingDeposit{ + { + PublicKey: pubkey, + WithdrawalCredentials: nonBuilderWithdrawalCredentials(), + Amount: 1, + }, + { + PublicKey: pubkey, + WithdrawalCredentials: builderWithdrawalCredentials(0xA1), + Amount: 2, + }, + { + PublicKey: pubkey, + WithdrawalCredentials: nonBuilderWithdrawalCredentials(), + Amount: 3, + }, + { + PublicKey: pubkey, + WithdrawalCredentials: builderWithdrawalCredentials(0xA2), + Amount: 4, + }, + { + PublicKey: pubkey, + WithdrawalCredentials: builderWithdrawalCredentials(0xA3), + Amount: 5, + }, + } + + st := newGloasState(t, nil, nil, pendingDeposits, 0) + verifiedAmounts := make([]uint64, 0, len(pendingDeposits)) + err := st.onboardBuildersFromPendingDeposits(t.Context(), func(data *ethpb.Deposit_Data) (bool, error) { + verifiedAmounts = append(verifiedAmounts, data.Amount) + return false, nil + }) + require.NoError(t, err) + + require.DeepEqual(t, []uint64{1, 2, 3, 4, 5}, verifiedAmounts) + require.Equal(t, 2, len(st.pendingDeposits)) + require.Equal(t, 0, len(st.builders)) + }) +} + +func TestOnboardBuildersFromPendingDeposits_ContextCancellation(t *testing.T) { + pubkey := bytes.Repeat([]byte{0x44}, fieldparams.BLSPubkeyLength) + pendingDeposits := []*ethpb.PendingDeposit{ + { + PublicKey: pubkey, + WithdrawalCredentials: nonBuilderWithdrawalCredentials(), + Amount: 1, + }, + { + PublicKey: pubkey, + WithdrawalCredentials: builderWithdrawalCredentials(0xAA), + Amount: 2, + }, + } + st := newGloasState(t, nil, nil, pendingDeposits, 0) + ctx, cancel := context.WithCancel(t.Context()) + verificationCount := 0 + err := st.onboardBuildersFromPendingDeposits(ctx, func(*ethpb.Deposit_Data) (bool, error) { + verificationCount++ + cancel() + return false, nil + }) + require.ErrorIs(t, err, context.Canceled) + require.Equal(t, 1, verificationCount) + require.Equal(t, len(pendingDeposits), len(st.pendingDeposits)) + require.Equal(t, 0, len(st.builders)) +} + func newGloasState( t *testing.T, validators []*ethpb.Validator, diff --git a/beacon-chain/state/stateutil/progressive_root_test.go b/beacon-chain/state/stateutil/progressive_root_test.go index 4c388f341d22..33e7a7ead1fd 100644 --- a/beacon-chain/state/stateutil/progressive_root_test.go +++ b/beacon-chain/state/stateutil/progressive_root_test.go @@ -14,7 +14,7 @@ import ( ) func TestValidatorRegistryRootProgressive(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) defer reset() pubkey := make([]byte, fieldparams.BLSPubkeyLength) @@ -49,7 +49,7 @@ func TestValidatorRegistryRootProgressive(t *testing.T) { } func TestUint64ListRootProgressive(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) defer reset() vals := []uint64{1, 2, 3, 4, 5, 6, 7} @@ -67,7 +67,7 @@ func TestUint64ListRootProgressive(t *testing.T) { } func TestParticipationBitsRootProgressive(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) defer reset() bits := []byte{0x01, 0x02, 0x03, 0x04} @@ -81,7 +81,7 @@ func TestParticipationBitsRootProgressive(t *testing.T) { } func TestBuildersRootProgressive(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) defer reset() builders := []*ethpb.Builder{{ @@ -101,7 +101,7 @@ func TestBuildersRootProgressive(t *testing.T) { } func TestPendingRootsProgressive(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) defer reset() pendingDeposits := []*ethpb.PendingDeposit{{ @@ -131,7 +131,7 @@ func TestPendingRootsProgressive(t *testing.T) { } func TestBuilderPendingWithdrawalsRootProgressive(t *testing.T) { - reset := features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset := features.InitWithReset(&features.Flags{}) defer reset() withdrawals := []*ethpb.BuilderPendingWithdrawal{{ diff --git a/beacon-chain/verification/execution_payload_bid.go b/beacon-chain/verification/execution_payload_bid.go index 972db12a9a39..a9a109ab4081 100644 --- a/beacon-chain/verification/execution_payload_bid.go +++ b/beacon-chain/verification/execution_payload_bid.go @@ -232,9 +232,9 @@ func (v *BidVerifier) VerifyGasLimitTargetCompatible(parentGasLimit, targetGasLi // isGasLimitTargetCompatible reports whether gasLimit is compatible with // targetGasLimit under the EIP-1559 transition rule from parentGasLimit. // -// +// // def is_gas_limit_target_compatible( -// parent_gas_limit: uint64, gas_limit: uint64, target_gas_limit: uint64 +// parent_gas_limit: Uint64, gas_limit: Uint64, target_gas_limit: Uint64 // ) -> bool: // """ // Check if ``gas_limit`` is compatible with ``target_gas_limit`` under the @@ -244,11 +244,11 @@ func (v *BidVerifier) VerifyGasLimitTargetCompatible(parentGasLimit, targetGasLi // min_gas_limit = parent_gas_limit - max_gas_limit_difference // max_gas_limit = parent_gas_limit + max_gas_limit_difference // -// if target_gas_limit >= min_gas_limit and target_gas_limit <= max_gas_limit: -// return gas_limit == target_gas_limit +// if target_gas_limit < min_gas_limit: +// return gas_limit == min_gas_limit // if target_gas_limit > max_gas_limit: // return gas_limit == max_gas_limit -// return gas_limit == min_gas_limit +// return gas_limit == target_gas_limit // func isGasLimitTargetCompatible(parentGasLimit, gasLimit, targetGasLimit uint64) bool { maxDiff := max(parentGasLimit/1024, 1) - 1 diff --git a/build/bazel/testdata_fetch.go b/build/bazel/testdata_fetch.go index 74621923cc72..df881956966a 100644 --- a/build/bazel/testdata_fetch.go +++ b/build/bazel/testdata_fetch.go @@ -35,9 +35,9 @@ func archiveForPath(path string) (string, bool) { switch first { case "tests": - // Consensus spec tests: tests/{general,minimal,mainnet}/... + // Spec tests: tests/{general,minimal,mainnet,kzg}/... category, _, _ := strings.Cut(rest, "/") - if name, ok := consensusSpecTestArchives[category]; ok { + if name, ok := specTestArchives[category]; ok { return name, true } return "", false @@ -60,11 +60,12 @@ func archiveForPath(path string) (string, bool) { return "", false } -// consensusSpecTestArchives maps a consensus-spec test category. -var consensusSpecTestArchives = map[string]string{ +// specTestArchives maps a top-level spec test category to its archive. +var specTestArchives = map[string]string{ "general": externaldata.ConsensusSpecTestsGeneral, "minimal": externaldata.ConsensusSpecTestsMinimal, "mainnet": externaldata.ConsensusSpecTestsMainnet, + "kzg": externaldata.CryptographySpecTests, } // blsCategories are the top-level directories the bls12-381 test archive unpacks diff --git a/build/bazel/testdata_fetch_test.go b/build/bazel/testdata_fetch_test.go index fca9cf7b6a42..b0cdadf80d2c 100644 --- a/build/bazel/testdata_fetch_test.go +++ b/build/bazel/testdata_fetch_test.go @@ -23,6 +23,7 @@ func TestArchiveForPath(t *testing.T) { {"consensus general", "tests/general/phase0/foo.ssz", externaldata.ConsensusSpecTestsGeneral, true}, {"consensus minimal", "tests/minimal/altair/bar.yaml", externaldata.ConsensusSpecTestsMinimal, true}, {"consensus mainnet", "tests/mainnet/capella/baz.yaml", externaldata.ConsensusSpecTestsMainnet, true}, + {"cryptography kzg", "tests/kzg/compute_cells", externaldata.CryptographySpecTests, true}, {"consensus unknown category", "tests/devnet/foo.yaml", "", false}, {"consensus bare", "tests", "", false}, {"external repo", "external/my_repo/file.txt", "my_repo", true}, diff --git a/build/externaldata/bazelsource.go b/build/externaldata/bazelsource.go index 8b101862c131..b44c8afa3098 100644 --- a/build/externaldata/bazelsource.go +++ b/build/externaldata/bazelsource.go @@ -18,9 +18,12 @@ var ( workspaceContent = sync.OnceValue(func() string { return readBazelFile(workspaceFile) }) e2eDepsContent = sync.OnceValue(func() string { return readBazelFile(e2eDepsFile) }) - consensusSpecVersion = sync.OnceValue(func() string { return bazelVar(workspaceContent(), workspaceFile, "consensus_spec_version") }) - blsVersion = sync.OnceValue(func() string { return bazelVar(workspaceContent(), workspaceFile, "bls_test_version") }) - lighthouseVersion = sync.OnceValue(func() string { return bazelVar(e2eDepsContent(), e2eDepsFile, "lighthouse_version") }) + consensusSpecVersion = sync.OnceValue(func() string { return bazelVar(workspaceContent(), workspaceFile, "consensus_spec_version") }) + cryptographySpecTestsVersion = sync.OnceValue(func() string { + return bazelVar(workspaceContent(), workspaceFile, "cryptography_spec_tests_version") + }) + blsVersion = sync.OnceValue(func() string { return bazelVar(workspaceContent(), workspaceFile, "bls_test_version") }) + lighthouseVersion = sync.OnceValue(func() string { return bazelVar(e2eDepsContent(), e2eDepsFile, "lighthouse_version") }) ) // readBazelFile reads a Bazel build file relative to the module root. diff --git a/build/externaldata/externaldata.go b/build/externaldata/externaldata.go index ce23adfe0768..4bb37a2a188f 100644 --- a/build/externaldata/externaldata.go +++ b/build/externaldata/externaldata.go @@ -2,6 +2,7 @@ package externaldata import ( "archive/tar" + "archive/zip" "bytes" "compress/gzip" "crypto/sha256" @@ -33,6 +34,7 @@ const ( ConsensusSpecTestsMinimal = "consensus_spec_tests_minimal" ConsensusSpecTestsMainnet = "consensus_spec_tests_mainnet" ConsensusSpec = "consensus_spec" + CryptographySpecTests = "cryptography_spec_tests" Mainnet = "mainnet" HoleskyTestnet = "holesky_testnet" SepoliaTestnet = "sepolia_testnet" @@ -70,6 +72,7 @@ func buildManifest() []archive { {HoleskyTestnet, archiveURL(workspaceContent(), workspaceFile, HoleskyTestnet), archiveHash(workspaceContent(), workspaceFile, HoleskyTestnet), "external/holesky_testnet", 1, ""}, {SepoliaTestnet, archiveURL(workspaceContent(), workspaceFile, SepoliaTestnet), archiveHash(workspaceContent(), workspaceFile, SepoliaTestnet), "external/sepolia_testnet", 1, ""}, {HoodiTestnet, archiveURL(workspaceContent(), workspaceFile, HoodiTestnet), archiveHash(workspaceContent(), workspaceFile, HoodiTestnet), "external/hoodi_testnet", 1, ""}, + {CryptographySpecTests, "https://github.com/ethereum/cryptography-specs/releases/download/" + cryptographySpecTestsVersion() + "/tests.zip", archiveHash(workspaceContent(), workspaceFile, CryptographySpecTests), ".", 0, ""}, {BLSSpecTests, "https://github.com/ethereum/bls12-381-tests/releases/download/" + blsVersion() + "/bls_tests_yaml.tar.gz", archiveHash(workspaceContent(), workspaceFile, BLSSpecTests), ".", 0, ""}, {EIP3076SpecTests, archiveURL(workspaceContent(), workspaceFile, EIP3076SpecTests), archiveHash(workspaceContent(), workspaceFile, EIP3076SpecTests), "external/eip3076_spec_tests", 1, ""}, {EIP4881SpecTests, archiveURL(workspaceContent(), workspaceFile, EIP4881SpecTests), archiveHash(workspaceContent(), workspaceFile, EIP4881SpecTests), "external/eip4881_spec_tests", 1, "*/assets/eip-4881/*"}, @@ -354,15 +357,23 @@ func download(url string) ([]byte, error) { return nil, lastErr } -// extract unpacks a gzip'd tar into target, stripping `strip` leading path -// components and, if include != "", only entries whose (pre-strip) name matches -// that glob. -func extract(targz []byte, target string, strip int, include string) error { +// extract unpacks a gzip'd tar or a zip into target, stripping `strip` leading +// path components and, if include != "", only entries whose (pre-strip) name +// matches that glob. +func extract(data []byte, target string, strip int, include string) error { var includeRe *regexp.Regexp if include != "" { includeRe = globToRegexp(include) } + if bytes.HasPrefix(data, []byte("PK\x03\x04")) { + return extractZip(data, target, strip, includeRe) + } + + return extractTarGz(data, target, strip, includeRe) +} + +func extractTarGz(targz []byte, target string, strip int, includeRe *regexp.Regexp) error { gz, err := gzip.NewReader(bytes.NewReader(targz)) if err != nil { return fmt.Errorf("gzip new reader: %w", err) @@ -380,49 +391,22 @@ func extract(targz []byte, target string, strip int, include string) error { return fmt.Errorf("tar next: %w", err) } - if includeRe != nil && !includeRe.MatchString(hdr.Name) { - continue + dst, ok, err := entryDest(target, hdr.Name, strip, includeRe) + if err != nil { + return err } - - rel := stripComponents(hdr.Name, strip) - if rel == "" { + if !ok { continue } - cleanTarget := filepath.Clean(target) - dst := filepath.Join(cleanTarget, filepath.FromSlash(rel)) - if dst == cleanTarget { - continue - } - - if !strings.HasPrefix(dst, cleanTarget+string(os.PathSeparator)) { - return fmt.Errorf("externaldata: unsafe path %q in archive", hdr.Name) - } - switch hdr.Typeflag { case tar.TypeDir: if err := os.MkdirAll(dst, 0o750); err != nil { return fmt.Errorf("mkdir all: %w", err) } case tar.TypeReg: - if err := os.MkdirAll(filepath.Dir(dst), 0o750); err != nil { - return fmt.Errorf("mkdir all: %w", err) - } - - // #nosec G304 -- dst is verified above to stay within the target dir (HasPrefix check) - f, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(hdr.Mode)&0o777|0o600) - if err != nil { - return fmt.Errorf("open file: %w", err) - } - - // #nosec G110 -- archive bytes are sha256-verified against a pinned hash before extraction - if _, err := io.Copy(f, tr); err != nil { - _ = f.Close() - return fmt.Errorf("copy file: %w", err) - } - - if err := f.Close(); err != nil { - return fmt.Errorf("close file: %w", err) + if err := writeEntry(dst, tr, os.FileMode(hdr.Mode)); err != nil { + return err } case tar.TypeSymlink: @@ -437,6 +421,95 @@ func extract(targz []byte, target string, strip int, include string) error { return nil } +func extractZip(data []byte, target string, strip int, includeRe *regexp.Regexp) error { + zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + return fmt.Errorf("zip new reader: %w", err) + } + + for _, f := range zr.File { + dst, ok, err := entryDest(target, f.Name, strip, includeRe) + if err != nil { + return err + } + if !ok { + continue + } + + if f.FileInfo().IsDir() { + if err := os.MkdirAll(dst, 0o750); err != nil { + return fmt.Errorf("mkdir all: %w", err) + } + continue + } + + rc, err := f.Open() + if err != nil { + return fmt.Errorf("open zip entry: %w", err) + } + + if err := writeEntry(dst, rc, f.Mode()); err != nil { + _ = rc.Close() + return err + } + + if err := rc.Close(); err != nil { + return fmt.Errorf("close zip entry: %w", err) + } + } + + return nil +} + +// entryDest resolves an archive entry to its destination path, reporting ok=false +// when the entry is filtered out or stripped away entirely. +func entryDest(target, name string, strip int, includeRe *regexp.Regexp) (string, bool, error) { + if includeRe != nil && !includeRe.MatchString(name) { + return "", false, nil + } + + rel := stripComponents(name, strip) + if rel == "" { + return "", false, nil + } + + cleanTarget := filepath.Clean(target) + dst := filepath.Join(cleanTarget, filepath.FromSlash(rel)) + if dst == cleanTarget { + return "", false, nil + } + + if !strings.HasPrefix(dst, cleanTarget+string(os.PathSeparator)) { + return "", false, fmt.Errorf("externaldata: unsafe path %q in archive", name) + } + + return dst, true, nil +} + +func writeEntry(dst string, r io.Reader, mode os.FileMode) error { + if err := os.MkdirAll(filepath.Dir(dst), 0o750); err != nil { + return fmt.Errorf("mkdir all: %w", err) + } + + // #nosec G304 -- dst is verified by entryDest to stay within the target dir + f, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode&0o777|0o600) + if err != nil { + return fmt.Errorf("open file: %w", err) + } + + // #nosec G110 -- archive bytes are sha256-verified against a pinned hash before extraction + if _, err := io.Copy(f, r); err != nil { + _ = f.Close() + return fmt.Errorf("copy file: %w", err) + } + + if err := f.Close(); err != nil { + return fmt.Errorf("close file: %w", err) + } + + return nil +} + func stripComponents(name string, n int) string { parts := strings.Split(strings.TrimPrefix(name, "./"), "/") if len(parts) <= n { diff --git a/build/gen/ssz.go b/build/gen/ssz.go index bf0513a1286a..2430dd517ae6 100644 --- a/build/gen/ssz.go +++ b/build/gen/ssz.go @@ -32,14 +32,18 @@ func genSSZ() error { return fmt.Errorf("load methodical targets: %w", err) } - // Progressive merkleization is gated OFF by default so that generated - // hash_tree_root values match the current (non-progressive) spectest - // fixtures. This mirrors the //tools:disable_progressive_merkleization - // default set in .bazelrc. Set SSZ_PROGRESSIVE=1 to generate the - // progressive form once upstream fixtures move to it. - progressive, _ := strconv.ParseBool(os.Getenv("SSZ_PROGRESSIVE")) - if progressive { - fmt.Println("SSZ_PROGRESSIVE=1: generating with progressive merkleization ON") + // Progressive merkleization is ON by default: gloas (EIP-7688) mandates it + // and the consensus-spec fixtures expect the progressive hash_tree_root + // values. This mirrors the //tools:disable_progressive_merkleization + // default in .bazelrc. Set SSZ_PROGRESSIVE=0 to generate the bounded form. + progressive := true + if v, ok := os.LookupEnv("SSZ_PROGRESSIVE"); ok { + if parsed, err := strconv.ParseBool(v); err == nil { + progressive = parsed + } + } + if !progressive { + fmt.Println("SSZ_PROGRESSIVE=0: generating with progressive merkleization OFF") } for _, t := range targets { diff --git a/changelog/syjn99_fix-builder-withdrawal-prefix.md b/changelog/syjn99_fix-builder-withdrawal-prefix.md new file mode 100644 index 000000000000..fa473e0b0d91 --- /dev/null +++ b/changelog/syjn99_fix-builder-withdrawal-prefix.md @@ -0,0 +1,3 @@ +### Fixed + +- Set `BUILDER_WITHDRAWAL_PREFIX` to `0xB0`. diff --git a/changelog/terence_alpha14.md b/changelog/terence_alpha14.md new file mode 100644 index 000000000000..674d8779a165 --- /dev/null +++ b/changelog/terence_alpha14.md @@ -0,0 +1,3 @@ +### Changed + +- Bump consensus spec to v1.7.0-alpha.14. diff --git a/changelog/terence_att-payload-availability-parent-slot.md b/changelog/terence_att-payload-availability-parent-slot.md new file mode 100644 index 000000000000..ffb6ba8b2d43 --- /dev/null +++ b/changelog/terence_att-payload-availability-parent-slot.md @@ -0,0 +1,3 @@ +### Fixed + +- Gloas: look up payload availability at the parent block's slot so attestations to skipped slots can earn the timely head flag. diff --git a/changelog/terence_builder-deposit-prefix.md b/changelog/terence_builder-deposit-prefix.md new file mode 100644 index 000000000000..ba9b5111657a --- /dev/null +++ b/changelog/terence_builder-deposit-prefix.md @@ -0,0 +1,3 @@ +### Changed + +- Ignore builder deposit requests without `BUILDER_WITHDRAWAL_PREFIX` and register new builders with `PAYLOAD_BUILDER_VERSION`. diff --git a/changelog/terence_builder-topup-swept-reset.md b/changelog/terence_builder-topup-swept-reset.md new file mode 100644 index 000000000000..d13a35b50952 --- /dev/null +++ b/changelog/terence_builder-topup-swept-reset.md @@ -0,0 +1,3 @@ +### Changed + +- Reset an exited builder's withdrawable epoch on top-up only when its balance has been swept. diff --git a/changelog/terence_builder-withdrawability-delay-64.md b/changelog/terence_builder-withdrawability-delay-64.md new file mode 100644 index 000000000000..5f58ef1d7cb2 --- /dev/null +++ b/changelog/terence_builder-withdrawability-delay-64.md @@ -0,0 +1,3 @@ +### Changed + +- Reduce `MIN_BUILDER_WITHDRAWABILITY_DELAY` to 64 epochs. diff --git a/changelog/terence_gloas-fork-bid-fields.md b/changelog/terence_gloas-fork-bid-fields.md new file mode 100644 index 000000000000..aea729dc4ccd --- /dev/null +++ b/changelog/terence_gloas-fork-bid-fields.md @@ -0,0 +1,3 @@ +### Changed + +- Explicitly set execution payload bid fields when upgrading to Gloas per consensus-specs#5553. diff --git a/changelog/terence_gloas-remove-deposit-limit.md b/changelog/terence_gloas-remove-deposit-limit.md new file mode 100644 index 000000000000..c18a6dd59c46 --- /dev/null +++ b/changelog/terence_gloas-remove-deposit-limit.md @@ -0,0 +1,3 @@ +### Changed + +- Remove the `MAX_DEPOSIT_REQUESTS_PER_PAYLOAD` bound on Gloas execution request decoding. diff --git a/changelog/terence_payload-due-bps-5000.md b/changelog/terence_payload-due-bps-5000.md new file mode 100644 index 000000000000..ee7fc3b4dc7f --- /dev/null +++ b/changelog/terence_payload-due-bps-5000.md @@ -0,0 +1,3 @@ +### Changed + +- Set `PAYLOAD_DUE_BPS` to 5000. diff --git a/config/features/config.go b/config/features/config.go index 1e87c0623774..70382796a0d7 100644 --- a/config/features/config.go +++ b/config/features/config.go @@ -50,7 +50,7 @@ type Flags struct { DisableDutiesV2 bool // DisableDutiesV2 sets validator client to use the get Duties endpoint EnableWeb bool // EnableWeb enables the webui on the validator client EnableStateDiff bool // EnableStateDiff enables the experimental state diff feature for the beacon node. - EnableProgressiveSSZ bool // EnableProgressiveSSZ enables experimental progressive SSZ merkleization for converted consensus types. + DisableProgressiveSSZ bool // DisableProgressiveSSZ turns off progressive SSZ merkleization for Gloas consensus types. ReorgLatePayloads bool // ReorgLatePayloads enables reorging late payloads in the beacon node. // Logging related toggles. @@ -113,7 +113,7 @@ func Get() *Flags { // ProgressiveSSZEnabled reports whether progressive SSZ is enabled for the // supplied state version. func ProgressiveSSZEnabled(stateVersion int) bool { - return stateVersion >= version.Gloas && Get().EnableProgressiveSSZ + return stateVersion >= version.Gloas && !Get().DisableProgressiveSSZ } // Init sets the global config equal to the config that is passed in. @@ -291,10 +291,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error { logEnabled(ignoreUnviableAttestations) cfg.IgnoreUnviableAttestations = true } - cfg.TrackEquivocations = false - if ctx.IsSet(trackEquivocations.Name) && ctx.Bool(trackEquivocations.Name) { - logEnabled(trackEquivocations) - cfg.TrackEquivocations = true + cfg.TrackEquivocations = true + if ctx.IsSet(disableTrackEquivocations.Name) && ctx.Bool(disableTrackEquivocations.Name) { + logDisabled(disableTrackEquivocations) + cfg.TrackEquivocations = false } if ctx.IsSet(EnableStateDiff.Name) { logEnabled(EnableStateDiff) @@ -305,9 +305,9 @@ func ConfigureBeaconChain(ctx *cli.Context) error { cfg.EnableHistoricalSpaceRepresentation = false } } - if ctx.IsSet(EnableProgressiveSSZ.Name) { - logEnabled(EnableProgressiveSSZ) - cfg.EnableProgressiveSSZ = true + if ctx.IsSet(DisableProgressiveSSZ.Name) { + logDisabled(DisableProgressiveSSZ) + cfg.DisableProgressiveSSZ = true } if ctx.Bool(reorgLatePayloads.Name) { logEnabled(reorgLatePayloads) diff --git a/config/features/config_test.go b/config/features/config_test.go index 7cbcbc7d2980..cf862edd447d 100644 --- a/config/features/config_test.go +++ b/config/features/config_test.go @@ -70,16 +70,14 @@ func TestConfigureBeaconConfig(t *testing.T) { assert.Equal(t, true, c.SaveInvalidBlock) } -func TestConfigureBeaconConfig_EnableProgressiveSSZ(t *testing.T) { - defer Init(&Flags{}) - +func TestConfigureBeaconConfig_DisableProgressiveSSZ(t *testing.T) { app := cli.App{} set := flag.NewFlagSet("test", 0) - set.Bool(EnableProgressiveSSZ.Name, false, "test") - require.NoError(t, set.Set(EnableProgressiveSSZ.Name, "true")) - context := cli.NewContext(&app, set, nil) - require.NoError(t, ConfigureBeaconChain(context)) - assert.Equal(t, true, Get().EnableProgressiveSSZ) + ctx := cli.NewContext(&app, set, nil) + set.Bool(DisableProgressiveSSZ.Name, false, "test") + require.NoError(t, set.Set(DisableProgressiveSSZ.Name, "true")) + require.NoError(t, ConfigureBeaconChain(ctx)) + assert.Equal(t, true, Get().DisableProgressiveSSZ) } func TestConfigureBeaconConfig_ReorgLatePayloads(t *testing.T) { diff --git a/config/features/deprecated_flags.go b/config/features/deprecated_flags.go index 9399ca2b8dc2..5a0f0a4122fc 100644 --- a/config/features/deprecated_flags.go +++ b/config/features/deprecated_flags.go @@ -60,6 +60,11 @@ var ( Usage: deprecatedUsage, Hidden: true, } + deprecatedTrackEquivocations = &cli.BoolFlag{ + Name: "track-equivocations", + Usage: deprecatedUsage, + Hidden: true, + } ) // Deprecated flags for both the beacon node and validator client. @@ -72,6 +77,7 @@ var deprecatedFlags = []cli.Flag{ deprecatedInteropStartIndex, deprecatedInteropEth1DataVotes, deprecatedInteropWriteSSZStateTransitions, + deprecatedTrackEquivocations, } var upcomingDeprecation = []cli.Flag{ diff --git a/config/features/flags.go b/config/features/flags.go index c90ffd2b5d13..e4cb2279e246 100644 --- a/config/features/flags.go +++ b/config/features/flags.go @@ -182,9 +182,9 @@ var ( Name: "enable-state-diff", Usage: "Enables the experimental state diff feature.", } - EnableProgressiveSSZ = &cli.BoolFlag{ - Name: "enable-progressive-ssz", - Usage: "Enables experimental progressive SSZ merkleization for converted consensus types.", + DisableProgressiveSSZ = &cli.BoolFlag{ + Name: "disable-progressive-ssz", + Usage: "Disables progressive SSZ merkleization for Gloas consensus types. Gloas (EIP-7688) mandates it, so this is an escape hatch for debugging only.", Hidden: true, } reorgLatePayloads = &cli.BoolFlag{ @@ -228,9 +228,9 @@ var ( Name: "ignore-unviable-attestations", Usage: "Ignores attestations whose target state is not viable with respect to the current head (avoid expensive state replay from lagging attesters).", } - trackEquivocations = &cli.BoolFlag{ - Name: "track-equivocations", - Usage: "Records proposer equivocations observed on gossip and marks the slot in forkchoice if the equivocation arrives before the configured early deadline.", + disableTrackEquivocations = &cli.BoolFlag{ + Name: "disable-track-equivocations", + Usage: "Disables recording proposer equivocations observed on gossip into forkchoice.", } ) @@ -277,7 +277,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{ SaveFullExecutionPayloads, enableStartupOptimistic, ignoreUnviableAttestations, - trackEquivocations, + disableTrackEquivocations, enableFullSSZDataLogging, disableVerboseSigVerification, enableProposerPreprocessing, @@ -293,7 +293,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{ EnableDiscoveryReboot, enableExperimentalAttestationPool, EnableStateDiff, - EnableProgressiveSSZ, + DisableProgressiveSSZ, reorgLatePayloads, forceHeadFlag, blacklistRoots, diff --git a/config/params/loader_test.go b/config/params/loader_test.go index 327a95df6903..c6fa7fcb0909 100644 --- a/config/params/loader_test.go +++ b/config/params/loader_test.go @@ -38,6 +38,8 @@ var placeholderFields = []string{ "EIP7928_FORK_VERSION", "EIP8025_FORK_EPOCH", "EIP8025_FORK_VERSION", + "EIP8321_FORK_EPOCH", + "EIP8321_FORK_VERSION", "EPOCHS_PER_SHUFFLING_PHASE", "FIELD_ELEMENTS_PER_CELL", // Configured as a constant in config/fieldparams/mainnet.go "FIELD_ELEMENTS_PER_EXT_BLOB", // Configured in proto/ssz_proto_library.bzl @@ -47,8 +49,9 @@ var placeholderFields = []string{ "INCLUSION_LIST_DUE_BPS", "INCLUSION_LIST_SUBMISSION_DEADLINE", "KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH", // Configured in proto/ssz_proto_library.bzl - "MAX_BYTES_PER_INCLUSION_LIST", "MAX_REQUEST_INCLUSION_LIST", + "MAX_TRANSACTIONS_BYTES_PER_INCLUSION_LIST", + "MIN_SLOTS_FOR_INCLUSION_LISTS_REQUESTS", "NUMBER_OF_COLUMNS", // Configured as a constant in config/fieldparams/mainnet.go "TARGET_NUMBER_OF_PEERS", "UPDATE_TIMEOUT", @@ -428,7 +431,10 @@ func assertYamlFieldsMatch(t *testing.T, name string, fields []string, c1, c2 *p v1 := reflect.ValueOf(*c1).Field(i).Interface() v2 := reflect.ValueOf(*c2).Field(i).Interface() if reflect.ValueOf(v1).Kind() == reflect.Slice { - assert.DeepEqual(t, v1, v2, "%s: %s", name, field) + // A nil slice and an empty yaml list are equivalent configs. + if reflect.ValueOf(v1).Len() != 0 || reflect.ValueOf(v2).Len() != 0 { + assert.DeepEqual(t, v1, v2, "%s: %s", name, field) + } } else { assert.Equal(t, v1, v2, "%s: %s", name, field) } diff --git a/config/params/mainnet_config.go b/config/params/mainnet_config.go index 9f7f5414e688..ec0e26fd2046 100644 --- a/config/params/mainnet_config.go +++ b/config/params/mainnet_config.go @@ -96,7 +96,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ BLSWithdrawalPrefixByte: byte(0), ETH1AddressWithdrawalPrefixByte: byte(1), CompoundingWithdrawalPrefixByte: byte(2), - BuilderWithdrawalPrefixByte: byte(3), + BuilderWithdrawalPrefixByte: byte(0xB0), PayloadBuilderVersion: byte(0), BuilderIndexSelfBuild: primitives.BuilderIndex(math.MaxUint64), ZeroHash: [32]byte{}, @@ -112,7 +112,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ EpochsPerEth1VotingPeriod: 64, SlotsPerHistoricalRoot: 8192, MinValidatorWithdrawabilityDelay: 256, - MinBuilderWithdrawabilityDelay: 8192, + MinBuilderWithdrawabilityDelay: 64, ShardCommitteePeriod: 256, MinEpochsToInactivityPenalty: 4, Eth1FollowDistance: 2048, @@ -135,7 +135,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ SyncMessageDueBPSGloas: primitives.BP(2500), ContributionDueBPSGloas: primitives.BP(5000), PayloadAttestationDueBPS: primitives.BP(7500), - PayloadDueBPS: primitives.BP(7500), + PayloadDueBPS: primitives.BP(5000), EquivocationEarlyDueBPS: primitives.BP(7500), // Ethereum PoW parameters. @@ -369,8 +369,8 @@ var mainnetBeaconConfig = &BeaconChainConfig{ ChurnLimitQuotientGloas: 32_768, ConsolidationChurnLimitQuotient: 65_536, MaxPerEpochActivationChurnLimitGloas: 256_000_000_000, - MaxBuilderDepositRequestsPerPayload: 256, // 2**8 (= 256) - MaxBuilderExitRequestsPerPayload: 16, // 2**4 (= 16) + MaxBuilderDepositRequestsPerPayload: 64, // 2**6 (= 64) + MaxBuilderExitRequestsPerPayload: 16, // 2**4 (= 16) // Values related to networking parameters. MaxPayloadSize: 10 * 1 << 20, // 10 MiB diff --git a/config/params/minimal_config.go b/config/params/minimal_config.go index 70dff04339d9..308ec46711ae 100644 --- a/config/params/minimal_config.go +++ b/config/params/minimal_config.go @@ -31,7 +31,7 @@ func MinimalSpecConfig() *BeaconChainConfig { // Initial values minimalConfig.BLSWithdrawalPrefixByte = byte(0) minimalConfig.ETH1AddressWithdrawalPrefixByte = byte(1) - minimalConfig.BuilderWithdrawalPrefixByte = byte(3) + minimalConfig.BuilderWithdrawalPrefixByte = byte(0xB0) // Time parameters minimalConfig.SecondsPerSlot = 6 @@ -41,7 +41,7 @@ func MinimalSpecConfig() *BeaconChainConfig { minimalConfig.SyncMessageDueBPSGloas = 2500 minimalConfig.ContributionDueBPSGloas = 5000 minimalConfig.PayloadAttestationDueBPS = 7500 - minimalConfig.PayloadDueBPS = 7500 + minimalConfig.PayloadDueBPS = 5000 minimalConfig.EquivocationEarlyDueBPS = 7500 minimalConfig.MinAttestationInclusionDelay = 1 minimalConfig.SlotsPerEpoch = 8 diff --git a/consensus-types/blocks/proofs_test.go b/consensus-types/blocks/proofs_test.go index d6d751cfaf10..6a1a56ba955f 100644 --- a/consensus-types/blocks/proofs_test.go +++ b/consensus-types/blocks/proofs_test.go @@ -156,7 +156,7 @@ func TestComputeBlockBodyFieldRoots_Gloas_ProgressiveSSZGate(t *testing.T) { b, ok := i.(*BeaconBlockBody) require.Equal(t, true, ok) - reset := features.InitWithReset(&features.Flags{}) + reset := features.InitWithReset(&features.Flags{DisableProgressiveSSZ: true}) defer reset() legacyRoots, err := ComputeBlockBodyFieldRoots(t.Context(), b) @@ -169,7 +169,7 @@ func TestComputeBlockBodyFieldRoots_Gloas_ProgressiveSSZGate(t *testing.T) { require.NoError(t, err) require.DeepEqual(t, expectedLegacyPayloadAttestationsRoot[:], legacyRoots[11]) - reset = features.InitWithReset(&features.Flags{EnableProgressiveSSZ: true}) + reset = features.InitWithReset(&features.Flags{}) defer reset() progressiveRoots, err := ComputeBlockBodyFieldRoots(t.Context(), b) diff --git a/consensus-types/hdiff/state_diff.go b/consensus-types/hdiff/state_diff.go index c5a354dd964e..fae4c786278b 100644 --- a/consensus-types/hdiff/state_diff.go +++ b/consensus-types/hdiff/state_diff.go @@ -2211,7 +2211,7 @@ func updateToVersion(ctx context.Context, source state.BeaconState, target int) case version.Electra: ret, err = fulu.ConvertToFulu(source) case version.Fulu: - ret, err = gloas.UpgradeToGloas(source) + ret, err = gloas.UpgradeToGloas(ctx, source) default: return nil, errors.Errorf("unsupported version %s", version.String(source.Version())) } diff --git a/consensus-types/hdiff/state_diff_gloas_test.go b/consensus-types/hdiff/state_diff_gloas_test.go index 6932701ac91f..7dbffec00821 100644 --- a/consensus-types/hdiff/state_diff_gloas_test.go +++ b/consensus-types/hdiff/state_diff_gloas_test.go @@ -19,7 +19,7 @@ import ( func gloasState(t testing.TB, numValidators uint64) (state.BeaconState, error) { fuluState, _ := util.DeterministicGenesisStateFulu(t, numValidators) - return gloas.UpgradeToGloas(fuluState) + return gloas.UpgradeToGloas(t.Context(), fuluState) } func requireEqualState(t testing.TB, expected, actual state.BeaconState) { @@ -244,7 +244,7 @@ func TestGloasCrossForkDiff(t *testing.T) { // Test Fulu → Gloas cross-fork diff via updateToVersion. fuluSource, _ := util.DeterministicGenesisStateFulu(t, 64) - gloasTarget, err := gloas.UpgradeToGloas(fuluSource.Copy()) + gloasTarget, err := gloas.UpgradeToGloas(t.Context(), fuluSource.Copy()) require.NoError(t, err) require.NoError(t, gloasTarget.SetSlot(fuluSource.Slot()+1)) @@ -280,7 +280,7 @@ func TestGloasCrossForkDiffOnboardsBuilderDeposit(t *testing.T) { Slot: 0, }})) - gloasTarget, err := gloas.UpgradeToGloas(fuluSource.Copy()) + gloasTarget, err := gloas.UpgradeToGloas(t.Context(), fuluSource.Copy()) require.NoError(t, err) require.NoError(t, gloasTarget.SetSlot(fuluSource.Slot()+1)) diff --git a/proto/engine/v1/electra.go b/proto/engine/v1/electra.go index 5b57ef86026d..2ec557b6c268 100644 --- a/proto/engine/v1/electra.go +++ b/proto/engine/v1/electra.go @@ -2,6 +2,7 @@ package enginev1 import ( "fmt" + "math" "sync" "github.com/ethereum/go-ethereum/common/hexutil" @@ -93,6 +94,8 @@ func decodeExecutionRequestList(raw [][]byte, limits ExecutionRequestLimits) (*E // decodeExecutionRequestListGloas decodes the EIP-7685 flat request list into a // gloas ExecutionRequests, including builder deposit/exit requests (EIP-8282). func decodeExecutionRequestListGloas(raw [][]byte, limits ExecutionRequestLimits) (*ExecutionRequestsGloas, error) { + // Gloas removes MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, the EL bounds deposit requests via the gas limit. + limits.Deposits = math.MaxUint64 / uint64(drSize) requests := &ExecutionRequestsGloas{} var prevTypeNum *uint8 for i := range raw { diff --git a/proto/engine/v1/electra_test.go b/proto/engine/v1/electra_test.go index 3f1e43254835..d0e124d3495a 100644 --- a/proto/engine/v1/electra_test.go +++ b/proto/engine/v1/electra_test.go @@ -276,3 +276,23 @@ func TestEmptyExecutionRequestsHashTreeRoot(t *testing.T) { require.NoError(t, err) require.Equal(t, want, got) } + +func TestEmptyExecutionRequestsGloasHashTreeRoot(t *testing.T) { + want, err := (&enginev1.ExecutionRequestsGloas{}).HashTreeRoot() + require.NoError(t, err) + got, err := enginev1.EmptyExecutionRequestsHashTreeRoot() + require.NoError(t, err) + require.Equal(t, want, got) +} + +func TestGetDecodedExecutionRequestsGloas_NoDepositLimit(t *testing.T) { + cfg := params.BeaconConfig() + count := int(cfg.MaxDepositRequestsPerPayload) + 1 + depositRequestBytes := make([]byte, count*(&enginev1.DepositRequest{}).SizeSSZ()) + ebg := &enginev1.ExecutionBundleGloas{ + ExecutionRequests: [][]byte{append([]byte{uint8(enginev1.DepositRequestType)}, depositRequestBytes...)}, + } + requests, err := ebg.GetDecodedExecutionRequests(cfg.ExecutionRequestLimits()) + require.NoError(t, err) + require.Equal(t, count, len(requests.Deposits)) +} diff --git a/proto/engine/v1/engine.minimal.ssz.go b/proto/engine/v1/engine.minimal.ssz.go index fdecf76a4d6d..14f77f2687f2 100644 --- a/proto/engine/v1/engine.minimal.ssz.go +++ b/proto/engine/v1/engine.minimal.ssz.go @@ -2088,9 +2088,6 @@ func (c *ExecutionPayloadGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.ExtraData...) // Field 13: Transactions - if len(c.Transactions) > 1048576 { - return nil, ssz.ErrListTooBig - } { offset = 4 * len(c.Transactions) for _, o := range c.Transactions { @@ -2099,16 +2096,10 @@ func (c *ExecutionPayloadGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } } for _, o := range c.Transactions { - if len(o) > 1073741824 { - return nil, ssz.ErrListTooBig - } dst = append(dst, o...) } // Field 14: Withdrawals - if len(c.Withdrawals) > 4 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Withdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Withdrawals: %w", err) @@ -2116,9 +2107,6 @@ func (c *ExecutionPayloadGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 17: BlockAccessList - if len(c.BlockAccessList) > 1073741824 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.BlockAccessList...) return dst, err } @@ -2230,9 +2218,6 @@ func (c *ExecutionPayloadGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned list bytes: when decoding c.Transactions, end-of-list offset is %d, which is not a multiple of 4 (offset size)", startOffset) } listLen := startOffset / 4 - if listLen > 1048576 { - return fmt.Errorf("ssz-max exceeded: c.Transactions has %d elements, ssz-max is 1048576: %w", listLen, ssz.ErrListTooBig) - } totalVarBytes := uint64(len(sszSlice13)) if totalVarBytes < startOffset { return fmt.Errorf("list bytes too short to contain an offset when decoding c.Transactions") @@ -2271,9 +2256,6 @@ func (c *ExecutionPayloadGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Withdrawals length is %d, which is not a multiple of 44: %w", len(sszSlice14), ssz.ErrIncorrectListSize) } numElem := len(sszSlice14) / 44 - if numElem > 4 { - return fmt.Errorf("ssz-max exceeded: c.Withdrawals has %d elements, ssz-max is 4: %w", numElem, ssz.ErrListTooBig) - } c.Withdrawals = make([]*Withdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *Withdrawal @@ -2303,8 +2285,18 @@ func (c *ExecutionPayloadGloas) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionPayloadGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionPayloadGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionPayloadGloas = []byte{0b11111111, 0b11111111, 0b00000111} + +func (c *ExecutionPayloadGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -2313,7 +2305,7 @@ func (c *ExecutionPayloadGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionPayloadGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionPayloadGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: ParentHash if len(c.ParentHash) != 32 { @@ -2377,59 +2369,41 @@ func (c *ExecutionPayloadGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutBytes(c.BlockHash) // Field 13: Transactions { - if len(c.Transactions) > 1048576 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Transactions { - { - if len(o) > 1073741824 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(o) - numItems := uint64(len(o)) - hh.MerkleizeWithMixin(subIndx, numItems, (1073741824*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(o))) } - } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Transactions)), 1048576) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Transactions))) } // Field 14: Withdrawals { - if len(c.Withdrawals) > 4 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Withdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Withdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Withdrawals)), 4) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Withdrawals))) } // Field 15: BlobGasUsed hh.PutUint64(c.BlobGasUsed) // Field 16: ExcessBlobGas hh.PutUint64(c.ExcessBlobGas) // Field 17: BlockAccessList - { - if len(c.BlockAccessList) > 1073741824 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(c.BlockAccessList) - numItems := uint64(len(c.BlockAccessList)) - hh.MerkleizeWithMixin(subIndx, numItems, (1073741824*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BlockAccessList))) } - // Field 18: SlotNumber if err := c.SlotNumber.HashTreeRootWith(hh); err != nil { return fmt.Errorf("SlotNumber: %w", err) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionPayloadGloas) return nil } @@ -3721,9 +3695,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { offset += len(c.BuilderExits) * 68 // Field 0: Deposits - if len(c.Deposits) > 8192 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Deposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Deposits: %w", err) @@ -3731,9 +3702,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 1: Withdrawals - if len(c.Withdrawals) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Withdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Withdrawals: %w", err) @@ -3741,9 +3709,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 2: Consolidations - if len(c.Consolidations) > 2 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Consolidations { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Consolidations: %w", err) @@ -3751,9 +3716,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 3: BuilderDeposits - if len(c.BuilderDeposits) > 256 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BuilderDeposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BuilderDeposits: %w", err) @@ -3761,9 +3723,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 4: BuilderExits - if len(c.BuilderExits) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BuilderExits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BuilderExits: %w", err) @@ -3814,9 +3773,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Deposits length is %d, which is not a multiple of 192: %w", len(sszSlice0), ssz.ErrIncorrectListSize) } numElem := len(sszSlice0) / 192 - if numElem > 8192 { - return fmt.Errorf("ssz-max exceeded: c.Deposits has %d elements, ssz-max is 8192: %w", numElem, ssz.ErrListTooBig) - } c.Deposits = make([]*DepositRequest, numElem) for i := 0; i < numElem; i++ { var tmp *DepositRequest @@ -3835,9 +3791,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Withdrawals length is %d, which is not a multiple of 76: %w", len(sszSlice1), ssz.ErrIncorrectListSize) } numElem := len(sszSlice1) / 76 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.Withdrawals has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.Withdrawals = make([]*WithdrawalRequest, numElem) for i := 0; i < numElem; i++ { var tmp *WithdrawalRequest @@ -3856,9 +3809,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Consolidations length is %d, which is not a multiple of 116: %w", len(sszSlice2), ssz.ErrIncorrectListSize) } numElem := len(sszSlice2) / 116 - if numElem > 2 { - return fmt.Errorf("ssz-max exceeded: c.Consolidations has %d elements, ssz-max is 2: %w", numElem, ssz.ErrListTooBig) - } c.Consolidations = make([]*ConsolidationRequest, numElem) for i := 0; i < numElem; i++ { var tmp *ConsolidationRequest @@ -3877,9 +3827,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BuilderDeposits length is %d, which is not a multiple of 184: %w", len(sszSlice3), ssz.ErrIncorrectListSize) } numElem := len(sszSlice3) / 184 - if numElem > 256 { - return fmt.Errorf("ssz-max exceeded: c.BuilderDeposits has %d elements, ssz-max is 256: %w", numElem, ssz.ErrListTooBig) - } c.BuilderDeposits = make([]*BuilderDepositRequest, numElem) for i := 0; i < numElem; i++ { var tmp *BuilderDepositRequest @@ -3898,9 +3845,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BuilderExits length is %d, which is not a multiple of 68: %w", len(sszSlice4), ssz.ErrIncorrectListSize) } numElem := len(sszSlice4) / 68 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.BuilderExits has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.BuilderExits = make([]*BuilderExitRequest, numElem) for i := 0; i < numElem; i++ { var tmp *BuilderExitRequest @@ -3916,8 +3860,18 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionRequestsGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionRequestsGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionRequestsGloas = []byte{0b00011111} + +func (c *ExecutionRequestsGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -3926,74 +3880,59 @@ func (c *ExecutionRequestsGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionRequestsGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionRequestsGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: Deposits { - if len(c.Deposits) > 8192 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Deposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Deposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Deposits)), 8192) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Deposits))) } // Field 1: Withdrawals { - if len(c.Withdrawals) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Withdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Withdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Withdrawals)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Withdrawals))) } // Field 2: Consolidations { - if len(c.Consolidations) > 2 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Consolidations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Consolidations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Consolidations)), 2) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Consolidations))) } // Field 3: BuilderDeposits { - if len(c.BuilderDeposits) > 256 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BuilderDeposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BuilderDeposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BuilderDeposits)), 256) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BuilderDeposits))) } // Field 4: BuilderExits { - if len(c.BuilderExits) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BuilderExits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BuilderExits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BuilderExits)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BuilderExits))) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionRequestsGloas) return nil } diff --git a/proto/engine/v1/engine.ssz.go b/proto/engine/v1/engine.ssz.go index e4d601fda6a8..f0a158b3c4e6 100644 --- a/proto/engine/v1/engine.ssz.go +++ b/proto/engine/v1/engine.ssz.go @@ -2088,9 +2088,6 @@ func (c *ExecutionPayloadGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.ExtraData...) // Field 13: Transactions - if len(c.Transactions) > 1048576 { - return nil, ssz.ErrListTooBig - } { offset = 4 * len(c.Transactions) for _, o := range c.Transactions { @@ -2099,16 +2096,10 @@ func (c *ExecutionPayloadGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } } for _, o := range c.Transactions { - if len(o) > 1073741824 { - return nil, ssz.ErrListTooBig - } dst = append(dst, o...) } // Field 14: Withdrawals - if len(c.Withdrawals) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Withdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Withdrawals: %w", err) @@ -2116,9 +2107,6 @@ func (c *ExecutionPayloadGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 17: BlockAccessList - if len(c.BlockAccessList) > 1073741824 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.BlockAccessList...) return dst, err } @@ -2230,9 +2218,6 @@ func (c *ExecutionPayloadGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned list bytes: when decoding c.Transactions, end-of-list offset is %d, which is not a multiple of 4 (offset size)", startOffset) } listLen := startOffset / 4 - if listLen > 1048576 { - return fmt.Errorf("ssz-max exceeded: c.Transactions has %d elements, ssz-max is 1048576: %w", listLen, ssz.ErrListTooBig) - } totalVarBytes := uint64(len(sszSlice13)) if totalVarBytes < startOffset { return fmt.Errorf("list bytes too short to contain an offset when decoding c.Transactions") @@ -2271,9 +2256,6 @@ func (c *ExecutionPayloadGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Withdrawals length is %d, which is not a multiple of 44: %w", len(sszSlice14), ssz.ErrIncorrectListSize) } numElem := len(sszSlice14) / 44 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.Withdrawals has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.Withdrawals = make([]*Withdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *Withdrawal @@ -2303,8 +2285,18 @@ func (c *ExecutionPayloadGloas) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionPayloadGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionPayloadGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionPayloadGloas = []byte{0b11111111, 0b11111111, 0b00000111} + +func (c *ExecutionPayloadGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -2313,7 +2305,7 @@ func (c *ExecutionPayloadGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionPayloadGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionPayloadGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: ParentHash if len(c.ParentHash) != 32 { @@ -2377,59 +2369,41 @@ func (c *ExecutionPayloadGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutBytes(c.BlockHash) // Field 13: Transactions { - if len(c.Transactions) > 1048576 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Transactions { - { - if len(o) > 1073741824 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(o) - numItems := uint64(len(o)) - hh.MerkleizeWithMixin(subIndx, numItems, (1073741824*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(o))) } - } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Transactions)), 1048576) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Transactions))) } // Field 14: Withdrawals { - if len(c.Withdrawals) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Withdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Withdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Withdrawals)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Withdrawals))) } // Field 15: BlobGasUsed hh.PutUint64(c.BlobGasUsed) // Field 16: ExcessBlobGas hh.PutUint64(c.ExcessBlobGas) // Field 17: BlockAccessList - { - if len(c.BlockAccessList) > 1073741824 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(c.BlockAccessList) - numItems := uint64(len(c.BlockAccessList)) - hh.MerkleizeWithMixin(subIndx, numItems, (1073741824*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BlockAccessList))) } - // Field 18: SlotNumber if err := c.SlotNumber.HashTreeRootWith(hh); err != nil { return fmt.Errorf("SlotNumber: %w", err) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionPayloadGloas) return nil } @@ -3721,9 +3695,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { offset += len(c.BuilderExits) * 68 // Field 0: Deposits - if len(c.Deposits) > 8192 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Deposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Deposits: %w", err) @@ -3731,9 +3702,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 1: Withdrawals - if len(c.Withdrawals) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Withdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Withdrawals: %w", err) @@ -3741,9 +3709,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 2: Consolidations - if len(c.Consolidations) > 2 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Consolidations { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Consolidations: %w", err) @@ -3751,9 +3716,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 3: BuilderDeposits - if len(c.BuilderDeposits) > 256 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BuilderDeposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BuilderDeposits: %w", err) @@ -3761,9 +3723,6 @@ func (c *ExecutionRequestsGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 4: BuilderExits - if len(c.BuilderExits) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BuilderExits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BuilderExits: %w", err) @@ -3814,9 +3773,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Deposits length is %d, which is not a multiple of 192: %w", len(sszSlice0), ssz.ErrIncorrectListSize) } numElem := len(sszSlice0) / 192 - if numElem > 8192 { - return fmt.Errorf("ssz-max exceeded: c.Deposits has %d elements, ssz-max is 8192: %w", numElem, ssz.ErrListTooBig) - } c.Deposits = make([]*DepositRequest, numElem) for i := 0; i < numElem; i++ { var tmp *DepositRequest @@ -3835,9 +3791,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Withdrawals length is %d, which is not a multiple of 76: %w", len(sszSlice1), ssz.ErrIncorrectListSize) } numElem := len(sszSlice1) / 76 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.Withdrawals has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.Withdrawals = make([]*WithdrawalRequest, numElem) for i := 0; i < numElem; i++ { var tmp *WithdrawalRequest @@ -3856,9 +3809,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Consolidations length is %d, which is not a multiple of 116: %w", len(sszSlice2), ssz.ErrIncorrectListSize) } numElem := len(sszSlice2) / 116 - if numElem > 2 { - return fmt.Errorf("ssz-max exceeded: c.Consolidations has %d elements, ssz-max is 2: %w", numElem, ssz.ErrListTooBig) - } c.Consolidations = make([]*ConsolidationRequest, numElem) for i := 0; i < numElem; i++ { var tmp *ConsolidationRequest @@ -3877,9 +3827,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BuilderDeposits length is %d, which is not a multiple of 184: %w", len(sszSlice3), ssz.ErrIncorrectListSize) } numElem := len(sszSlice3) / 184 - if numElem > 256 { - return fmt.Errorf("ssz-max exceeded: c.BuilderDeposits has %d elements, ssz-max is 256: %w", numElem, ssz.ErrListTooBig) - } c.BuilderDeposits = make([]*BuilderDepositRequest, numElem) for i := 0; i < numElem; i++ { var tmp *BuilderDepositRequest @@ -3898,9 +3845,6 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BuilderExits length is %d, which is not a multiple of 68: %w", len(sszSlice4), ssz.ErrIncorrectListSize) } numElem := len(sszSlice4) / 68 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.BuilderExits has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.BuilderExits = make([]*BuilderExitRequest, numElem) for i := 0; i < numElem; i++ { var tmp *BuilderExitRequest @@ -3916,8 +3860,18 @@ func (c *ExecutionRequestsGloas) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionRequestsGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionRequestsGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionRequestsGloas = []byte{0b00011111} + +func (c *ExecutionRequestsGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -3926,74 +3880,59 @@ func (c *ExecutionRequestsGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionRequestsGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionRequestsGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: Deposits { - if len(c.Deposits) > 8192 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Deposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Deposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Deposits)), 8192) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Deposits))) } // Field 1: Withdrawals { - if len(c.Withdrawals) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Withdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Withdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Withdrawals)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Withdrawals))) } // Field 2: Consolidations { - if len(c.Consolidations) > 2 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Consolidations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Consolidations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Consolidations)), 2) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Consolidations))) } // Field 3: BuilderDeposits { - if len(c.BuilderDeposits) > 256 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BuilderDeposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BuilderDeposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BuilderDeposits)), 256) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BuilderDeposits))) } // Field 4: BuilderExits { - if len(c.BuilderExits) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BuilderExits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BuilderExits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BuilderExits)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BuilderExits))) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionRequestsGloas) return nil } diff --git a/proto/engine/v1/engine.yaml b/proto/engine/v1/engine.yaml index 10406a3433dc..28f72d362000 100644 --- a/proto/engine/v1/engine.yaml +++ b/proto/engine/v1/engine.yaml @@ -10,12 +10,29 @@ types: - name: "ExecutionPayloadCapella" - name: "ExecutionPayloadDeneb" - name: "ExecutionPayloadGloas" + progressive: {} + fields: + Transactions: {type: "ProgressiveList", element: {type: "ProgressiveByteList"}} + Withdrawals: {type: "ProgressiveList"} + BlockAccessList: {type: "ProgressiveList"} - name: "ExecutionPayloadDenebAndBlobsBundle" - name: "ExecutionPayloadDenebAndBlobsBundleV2" - name: "ExecutionPayloadHeader" - name: "ExecutionPayloadHeaderCapella" - name: "ExecutionPayloadHeaderDeneb" + # Base ExecutionRequests is the electra/fulu (pre-gloas) type: bounded lists, + # NOT progressive. Progressive merkleization is introduced only at gloas + # (EIP-7688), and gloas uses the distinct ExecutionRequestsGloas message + # below. Annotating this base type progressive leaks into electra/fulu and + # breaks pre-gloas containment. - name: "ExecutionRequests" - name: "ExecutionRequestsGloas" + progressive: {} + fields: + Deposits: {type: "ProgressiveList"} + Withdrawals: {type: "ProgressiveList"} + Consolidations: {type: "ProgressiveList"} + BuilderDeposits: {type: "ProgressiveList"} + BuilderExits: {type: "ProgressiveList"} - name: "Withdrawal" - name: "WithdrawalRequest" diff --git a/proto/prysm/v1alpha1/gloas.minimal.ssz.go b/proto/prysm/v1alpha1/gloas.minimal.ssz.go index bf90aff351e5..5ecf78d38816 100644 --- a/proto/prysm/v1alpha1/gloas.minimal.ssz.go +++ b/proto/prysm/v1alpha1/gloas.minimal.ssz.go @@ -51,9 +51,6 @@ func (c *AttestationGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, []byte(c.CommitteeBits)...) // Field 0: AggregationBits - if len(c.AggregationBits) > 8192 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.AggregationBits...) return dst, err } @@ -79,7 +76,7 @@ func (c *AttestationGloas) UnmarshalSSZ(buf []byte) error { sszSlice0 := buf[sszVarOffset0:] // c.AggregationBits // Field 0: AggregationBits - if err = ssz.ValidateBitlist(sszSlice0, 8192); err != nil { + if err = ssz.ValidateProgressiveBitlist(sszSlice0); err != nil { return fmt.Errorf("AggregationBits: %w", err) } c.AggregationBits = append([]byte{}, go_bitfield.Bitlist(sszSlice0)...) @@ -101,8 +98,18 @@ func (c *AttestationGloas) UnmarshalSSZ(buf []byte) error { } func (c *AttestationGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *AttestationGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsAttestationGloas = []byte{0b00001111} + +func (c *AttestationGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -111,13 +118,13 @@ func (c *AttestationGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *AttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *AttestationGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: AggregationBits if len(c.AggregationBits) == 0 { return ssz.ErrEmptyBitlist } - hh.PutBitlist(c.AggregationBits, 8192) + hh.PutProgressiveBitlist(c.AggregationBits) // Field 1: Data if err := c.Data.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Data: %w", err) @@ -132,7 +139,7 @@ func (c *AttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { return ssz.ErrBytesLength } hh.PutBytes([]byte(c.CommitteeBits)) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsAttestationGloas) return nil } @@ -559,9 +566,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { offset += c.ParentExecutionRequests.SizeSSZ() // Field 3: ProposerSlashings - if len(c.ProposerSlashings) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.ProposerSlashings { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("ProposerSlashings: %w", err) @@ -569,9 +573,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 4: AttesterSlashings - if len(c.AttesterSlashings) > 1 { - return nil, ssz.ErrListTooBig - } { offset = 4 * len(c.AttesterSlashings) for _, o := range c.AttesterSlashings { @@ -586,9 +587,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 5: Attestations - if len(c.Attestations) > 8 { - return nil, ssz.ErrListTooBig - } { offset = 4 * len(c.Attestations) for _, o := range c.Attestations { @@ -603,9 +601,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 6: Deposits - if len(c.Deposits) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Deposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Deposits: %w", err) @@ -613,9 +608,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 7: VoluntaryExits - if len(c.VoluntaryExits) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.VoluntaryExits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("VoluntaryExits: %w", err) @@ -623,9 +615,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 9: BlsToExecutionChanges - if len(c.BlsToExecutionChanges) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BlsToExecutionChanges { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BlsToExecutionChanges: %w", err) @@ -638,9 +627,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 11: PayloadAttestations - if len(c.PayloadAttestations) > 4 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PayloadAttestations { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PayloadAttestations: %w", err) @@ -735,9 +721,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.ProposerSlashings length is %d, which is not a multiple of 416: %w", len(sszSlice3), ssz.ErrIncorrectListSize) } numElem := len(sszSlice3) / 416 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.ProposerSlashings has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.ProposerSlashings = make([]*ProposerSlashing, numElem) for i := 0; i < numElem; i++ { var tmp *ProposerSlashing @@ -763,9 +746,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned list bytes: when decoding c.AttesterSlashings, end-of-list offset is %d, which is not a multiple of 4 (offset size)", startOffset) } listLen := startOffset / 4 - if listLen > 1 { - return fmt.Errorf("ssz-max exceeded: c.AttesterSlashings has %d elements, ssz-max is 1: %w", listLen, ssz.ErrListTooBig) - } totalVarBytes := uint64(len(sszSlice4)) if totalVarBytes < startOffset { return fmt.Errorf("list bytes too short to contain an offset when decoding c.AttesterSlashings") @@ -813,9 +793,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned list bytes: when decoding c.Attestations, end-of-list offset is %d, which is not a multiple of 4 (offset size)", startOffset) } listLen := startOffset / 4 - if listLen > 8 { - return fmt.Errorf("ssz-max exceeded: c.Attestations has %d elements, ssz-max is 8: %w", listLen, ssz.ErrListTooBig) - } totalVarBytes := uint64(len(sszSlice5)) if totalVarBytes < startOffset { return fmt.Errorf("list bytes too short to contain an offset when decoding c.Attestations") @@ -856,9 +833,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Deposits length is %d, which is not a multiple of 1240: %w", len(sszSlice6), ssz.ErrIncorrectListSize) } numElem := len(sszSlice6) / 1240 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.Deposits has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.Deposits = make([]*Deposit, numElem) for i := 0; i < numElem; i++ { var tmp *Deposit @@ -877,9 +851,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.VoluntaryExits length is %d, which is not a multiple of 112: %w", len(sszSlice7), ssz.ErrIncorrectListSize) } numElem := len(sszSlice7) / 112 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.VoluntaryExits has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.VoluntaryExits = make([]*SignedVoluntaryExit, numElem) for i := 0; i < numElem; i++ { var tmp *SignedVoluntaryExit @@ -904,9 +875,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BlsToExecutionChanges length is %d, which is not a multiple of 172: %w", len(sszSlice9), ssz.ErrIncorrectListSize) } numElem := len(sszSlice9) / 172 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.BlsToExecutionChanges has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.BlsToExecutionChanges = make([]*SignedBLSToExecutionChange, numElem) for i := 0; i < numElem; i++ { var tmp *SignedBLSToExecutionChange @@ -931,9 +899,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PayloadAttestations length is %d, which is not a multiple of 140: %w", len(sszSlice11), ssz.ErrIncorrectListSize) } numElem := len(sszSlice11) / 140 - if numElem > 4 { - return fmt.Errorf("ssz-max exceeded: c.PayloadAttestations has %d elements, ssz-max is 4: %w", numElem, ssz.ErrListTooBig) - } c.PayloadAttestations = make([]*PayloadAttestation, numElem) for i := 0; i < numElem; i++ { var tmp *PayloadAttestation @@ -955,8 +920,18 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { } func (c *BeaconBlockBodyGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsBeaconBlockBodyGloas = []byte{0b11111111, 0b00011111} + +func (c *BeaconBlockBodyGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -965,7 +940,7 @@ func (c *BeaconBlockBodyGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *BeaconBlockBodyGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: RandaoReveal if len(c.RandaoReveal) != 96 { @@ -983,68 +958,53 @@ func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutBytes(c.Graffiti) // Field 3: ProposerSlashings { - if len(c.ProposerSlashings) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.ProposerSlashings { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("ProposerSlashings: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.ProposerSlashings)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.ProposerSlashings))) } // Field 4: AttesterSlashings { - if len(c.AttesterSlashings) > 1 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.AttesterSlashings { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("AttesterSlashings: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.AttesterSlashings)), 1) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.AttesterSlashings))) } // Field 5: Attestations { - if len(c.Attestations) > 8 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Attestations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Attestations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Attestations)), 8) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Attestations))) } // Field 6: Deposits { - if len(c.Deposits) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Deposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Deposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Deposits)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Deposits))) } // Field 7: VoluntaryExits { - if len(c.VoluntaryExits) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.VoluntaryExits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("VoluntaryExits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.VoluntaryExits)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.VoluntaryExits))) } // Field 8: SyncAggregate if err := c.SyncAggregate.HashTreeRootWith(hh); err != nil { @@ -1052,16 +1012,13 @@ func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 9: BlsToExecutionChanges { - if len(c.BlsToExecutionChanges) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BlsToExecutionChanges { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BlsToExecutionChanges: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BlsToExecutionChanges)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BlsToExecutionChanges))) } // Field 10: SignedExecutionPayloadBid if err := c.SignedExecutionPayloadBid.HashTreeRootWith(hh); err != nil { @@ -1069,22 +1026,19 @@ func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 11: PayloadAttestations { - if len(c.PayloadAttestations) > 4 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PayloadAttestations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PayloadAttestations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PayloadAttestations)), 4) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PayloadAttestations))) } // Field 12: ParentExecutionRequests if err := c.ParentExecutionRequests.HashTreeRootWith(hh); err != nil { return fmt.Errorf("ParentExecutionRequests: %w", err) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsBeaconBlockBodyGloas) return nil } @@ -1774,9 +1728,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 11: Validators - if len(c.Validators) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Validators { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Validators: %w", err) @@ -1784,29 +1735,17 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 12: Balances - if len(c.Balances) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Balances { dst = binary.LittleEndian.AppendUint64(dst, o) } // Field 15: PreviousEpochParticipation - if len(c.PreviousEpochParticipation) > 1099511627776 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.PreviousEpochParticipation...) // Field 16: CurrentEpochParticipation - if len(c.CurrentEpochParticipation) > 1099511627776 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.CurrentEpochParticipation...) // Field 21: InactivityScores - if len(c.InactivityScores) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.InactivityScores { dst = binary.LittleEndian.AppendUint64(dst, o) } @@ -1822,9 +1761,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 34: PendingDeposits - if len(c.PendingDeposits) > 134217728 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PendingDeposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PendingDeposits: %w", err) @@ -1832,9 +1768,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 35: PendingPartialWithdrawals - if len(c.PendingPartialWithdrawals) > 64 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PendingPartialWithdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PendingPartialWithdrawals: %w", err) @@ -1842,9 +1775,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 36: PendingConsolidations - if len(c.PendingConsolidations) > 64 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PendingConsolidations { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PendingConsolidations: %w", err) @@ -1852,9 +1782,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 38: Builders - if len(c.Builders) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Builders { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Builders: %w", err) @@ -1862,9 +1789,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 42: BuilderPendingWithdrawals - if len(c.BuilderPendingWithdrawals) > 1048576 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BuilderPendingWithdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BuilderPendingWithdrawals: %w", err) @@ -1877,9 +1801,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 44: PayloadExpectedWithdrawals - if len(c.PayloadExpectedWithdrawals) > 4 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PayloadExpectedWithdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PayloadExpectedWithdrawals: %w", err) @@ -2112,9 +2033,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Validators length is %d, which is not a multiple of 121: %w", len(sszSlice11), ssz.ErrIncorrectListSize) } numElem := len(sszSlice11) / 121 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.Validators has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.Validators = make([]*Validator, numElem) for i := 0; i < numElem; i++ { var tmp *Validator @@ -2133,9 +2051,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Balances length is %d, which is not a multiple of 8: %w", len(sszSlice12), ssz.ErrIncorrectListSize) } numElem := len(sszSlice12) / 8 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.Balances has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.Balances = make([]uint64, numElem) for i := 0; i < numElem; i++ { var tmp uint64 @@ -2205,9 +2120,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.InactivityScores length is %d, which is not a multiple of 8: %w", len(sszSlice21), ssz.ErrIncorrectListSize) } numElem := len(sszSlice21) / 8 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.InactivityScores has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.InactivityScores = make([]uint64, numElem) for i := 0; i < numElem; i++ { var tmp uint64 @@ -2297,9 +2209,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PendingDeposits length is %d, which is not a multiple of 192: %w", len(sszSlice34), ssz.ErrIncorrectListSize) } numElem := len(sszSlice34) / 192 - if numElem > 134217728 { - return fmt.Errorf("ssz-max exceeded: c.PendingDeposits has %d elements, ssz-max is 134217728: %w", numElem, ssz.ErrListTooBig) - } c.PendingDeposits = make([]*PendingDeposit, numElem) for i := 0; i < numElem; i++ { var tmp *PendingDeposit @@ -2318,9 +2227,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PendingPartialWithdrawals length is %d, which is not a multiple of 24: %w", len(sszSlice35), ssz.ErrIncorrectListSize) } numElem := len(sszSlice35) / 24 - if numElem > 64 { - return fmt.Errorf("ssz-max exceeded: c.PendingPartialWithdrawals has %d elements, ssz-max is 64: %w", numElem, ssz.ErrListTooBig) - } c.PendingPartialWithdrawals = make([]*PendingPartialWithdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *PendingPartialWithdrawal @@ -2339,9 +2245,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PendingConsolidations length is %d, which is not a multiple of 16: %w", len(sszSlice36), ssz.ErrIncorrectListSize) } numElem := len(sszSlice36) / 16 - if numElem > 64 { - return fmt.Errorf("ssz-max exceeded: c.PendingConsolidations has %d elements, ssz-max is 64: %w", numElem, ssz.ErrListTooBig) - } c.PendingConsolidations = make([]*PendingConsolidation, numElem) for i := 0; i < numElem; i++ { var tmp *PendingConsolidation @@ -2374,9 +2277,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Builders length is %d, which is not a multiple of 93: %w", len(sszSlice38), ssz.ErrIncorrectListSize) } numElem := len(sszSlice38) / 93 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.Builders has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.Builders = make([]*Builder, numElem) for i := 0; i < numElem; i++ { var tmp *Builder @@ -2418,9 +2318,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BuilderPendingWithdrawals length is %d, which is not a multiple of 36: %w", len(sszSlice42), ssz.ErrIncorrectListSize) } numElem := len(sszSlice42) / 36 - if numElem > 1048576 { - return fmt.Errorf("ssz-max exceeded: c.BuilderPendingWithdrawals has %d elements, ssz-max is 1048576: %w", numElem, ssz.ErrListTooBig) - } c.BuilderPendingWithdrawals = make([]*BuilderPendingWithdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *BuilderPendingWithdrawal @@ -2445,9 +2342,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PayloadExpectedWithdrawals length is %d, which is not a multiple of 44: %w", len(sszSlice44), ssz.ErrIncorrectListSize) } numElem := len(sszSlice44) / 44 - if numElem > 4 { - return fmt.Errorf("ssz-max exceeded: c.PayloadExpectedWithdrawals has %d elements, ssz-max is 4: %w", numElem, ssz.ErrListTooBig) - } c.PayloadExpectedWithdrawals = make([]*v1.Withdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *v1.Withdrawal @@ -2477,8 +2371,18 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { } func (c *BeaconStateGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsBeaconStateGloas = []byte{0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00111111} + +func (c *BeaconStateGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -2487,7 +2391,7 @@ func (c *BeaconStateGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *BeaconStateGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: GenesisTime hh.PutUint64(c.GenesisTime) @@ -2571,29 +2475,22 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutUint64(c.Eth1DepositIndex) // Field 11: Validators { - if len(c.Validators) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Validators { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Validators: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Validators)), 1099511627776) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Validators))) } // Field 12: Balances { - if len(c.Balances) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Balances { hh.AppendUint64(o) } hh.FillUpTo32() - numItems := uint64(len(c.Balances)) - hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(1099511627776, numItems, 8)) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Balances))) } // Field 13: RandaoMixes { @@ -2621,29 +2518,17 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.Merkleize(subIndx) } // Field 15: PreviousEpochParticipation - { - if len(c.PreviousEpochParticipation) > 1099511627776 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(c.PreviousEpochParticipation) - numItems := uint64(len(c.PreviousEpochParticipation)) - hh.MerkleizeWithMixin(subIndx, numItems, (1099511627776*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PreviousEpochParticipation))) } - // Field 16: CurrentEpochParticipation - { - if len(c.CurrentEpochParticipation) > 1099511627776 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(c.CurrentEpochParticipation) - numItems := uint64(len(c.CurrentEpochParticipation)) - hh.MerkleizeWithMixin(subIndx, numItems, (1099511627776*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.CurrentEpochParticipation))) } - // Field 17: JustificationBits if len([]byte(c.JustificationBits)) != 1 { return ssz.ErrBytesLength @@ -2663,16 +2548,12 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 21: InactivityScores { - if len(c.InactivityScores) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.InactivityScores { hh.AppendUint64(o) } hh.FillUpTo32() - numItems := uint64(len(c.InactivityScores)) - hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(1099511627776, numItems, 8)) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.InactivityScores))) } // Field 22: CurrentSyncCommittee if err := c.CurrentSyncCommittee.HashTreeRootWith(hh); err != nil { @@ -2730,42 +2611,33 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 34: PendingDeposits { - if len(c.PendingDeposits) > 134217728 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PendingDeposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PendingDeposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PendingDeposits)), 134217728) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PendingDeposits))) } // Field 35: PendingPartialWithdrawals { - if len(c.PendingPartialWithdrawals) > 64 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PendingPartialWithdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PendingPartialWithdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PendingPartialWithdrawals)), 64) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PendingPartialWithdrawals))) } // Field 36: PendingConsolidations { - if len(c.PendingConsolidations) > 64 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PendingConsolidations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PendingConsolidations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PendingConsolidations)), 64) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PendingConsolidations))) } // Field 37: ProposerLookahead { @@ -2780,16 +2652,13 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 38: Builders { - if len(c.Builders) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Builders { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Builders: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Builders)), 1099511627776) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Builders))) } // Field 39: NextWithdrawalBuilderIndex if err := c.NextWithdrawalBuilderIndex.HashTreeRootWith(hh); err != nil { @@ -2815,16 +2684,13 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 42: BuilderPendingWithdrawals { - if len(c.BuilderPendingWithdrawals) > 1048576 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BuilderPendingWithdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BuilderPendingWithdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BuilderPendingWithdrawals)), 1048576) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BuilderPendingWithdrawals))) } // Field 43: LatestExecutionPayloadBid if err := c.LatestExecutionPayloadBid.HashTreeRootWith(hh); err != nil { @@ -2832,16 +2698,13 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 44: PayloadExpectedWithdrawals { - if len(c.PayloadExpectedWithdrawals) > 4 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PayloadExpectedWithdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PayloadExpectedWithdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PayloadExpectedWithdrawals)), 4) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PayloadExpectedWithdrawals))) } // Field 45: PtcWindow { @@ -2856,7 +2719,7 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.Merkleize(subIndx) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsBeaconStateGloas) return nil } @@ -3547,9 +3410,6 @@ func (c *DataColumnSidecarGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.BeaconBlockRoot...) // Field 1: Column - if len(c.Column) > 4096 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Column { if len(o) != 2048 { return nil, ssz.ErrBytesLength @@ -3558,9 +3418,6 @@ func (c *DataColumnSidecarGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 2: KzgProofs - if len(c.KzgProofs) > 4096 { - return nil, ssz.ErrListTooBig - } for _, o := range c.KzgProofs { if len(o) != 48 { return nil, ssz.ErrBytesLength @@ -3604,9 +3461,6 @@ func (c *DataColumnSidecarGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Column length is %d, which is not a multiple of 2048: %w", len(sszSlice1), ssz.ErrIncorrectListSize) } numElem := len(sszSlice1) / 2048 - if numElem > 4096 { - return fmt.Errorf("ssz-max exceeded: c.Column has %d elements, ssz-max is 4096: %w", numElem, ssz.ErrListTooBig) - } c.Column = make([][]byte, numElem) for i := 0; i < numElem; i++ { var tmp []byte @@ -3624,9 +3478,6 @@ func (c *DataColumnSidecarGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.KzgProofs length is %d, which is not a multiple of 48: %w", len(sszSlice2), ssz.ErrIncorrectListSize) } numElem := len(sszSlice2) / 48 - if numElem > 4096 { - return fmt.Errorf("ssz-max exceeded: c.KzgProofs has %d elements, ssz-max is 4096: %w", numElem, ssz.ErrListTooBig) - } c.KzgProofs = make([][]byte, numElem) for i := 0; i < numElem; i++ { var tmp []byte @@ -3666,9 +3517,6 @@ func (c *DataColumnSidecarGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutUint64(c.Index) // Field 1: Column { - if len(c.Column) > 4096 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Column { if len(o) != 2048 { @@ -3676,13 +3524,10 @@ func (c *DataColumnSidecarGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.PutBytes(o) } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Column)), 4096) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Column))) } // Field 2: KzgProofs { - if len(c.KzgProofs) > 4096 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.KzgProofs { if len(o) != 48 { @@ -3690,7 +3535,7 @@ func (c *DataColumnSidecarGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.PutBytes(o) } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.KzgProofs)), 4096) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.KzgProofs))) } // Field 3: Slot if err := c.Slot.HashTreeRootWith(hh); err != nil { @@ -3784,9 +3629,6 @@ func (c *ExecutionPayloadBid) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.ExecutionRequestsRoot...) // Field 10: BlobKzgCommitments - if len(c.BlobKzgCommitments) > 4096 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BlobKzgCommitments { if len(o) != 48 { return nil, ssz.ErrBytesLength @@ -3873,9 +3715,6 @@ func (c *ExecutionPayloadBid) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BlobKzgCommitments length is %d, which is not a multiple of 48: %w", len(sszSlice10), ssz.ErrIncorrectListSize) } numElem := len(sszSlice10) / 48 - if numElem > 4096 { - return fmt.Errorf("ssz-max exceeded: c.BlobKzgCommitments has %d elements, ssz-max is 4096: %w", numElem, ssz.ErrListTooBig) - } c.BlobKzgCommitments = make([][]byte, numElem) for i := 0; i < numElem; i++ { var tmp []byte @@ -3894,8 +3733,18 @@ func (c *ExecutionPayloadBid) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionPayloadBid) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionPayloadBid = []byte{0b11111111, 0b00001111} + +func (c *ExecutionPayloadBid) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -3904,7 +3753,7 @@ func (c *ExecutionPayloadBid) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionPayloadBid) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: ParentBlockHash if len(c.ParentBlockHash) != 32 { @@ -3951,9 +3800,6 @@ func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 10: BlobKzgCommitments { - if len(c.BlobKzgCommitments) > 4096 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BlobKzgCommitments { if len(o) != 48 { @@ -3961,14 +3807,14 @@ func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.PutBytes(o) } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BlobKzgCommitments)), 4096) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BlobKzgCommitments))) } // Field 11: ExecutionRequestsRoot if len(c.ExecutionRequestsRoot) != 32 { return ssz.ErrBytesLength } hh.PutBytes(c.ExecutionRequestsRoot) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionPayloadBid) return nil } @@ -4090,8 +3936,18 @@ func (c *ExecutionPayloadEnvelope) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionPayloadEnvelope) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionPayloadEnvelope = []byte{0b00011111} + +func (c *ExecutionPayloadEnvelope) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -4100,7 +3956,7 @@ func (c *ExecutionPayloadEnvelope) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionPayloadEnvelope) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: Payload if err := c.Payload.HashTreeRootWith(hh); err != nil { @@ -4124,7 +3980,7 @@ func (c *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) (err error) return ssz.ErrBytesLength } hh.PutBytes(c.ParentBeaconBlockRoot) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionPayloadEnvelope) return nil } @@ -4162,9 +4018,6 @@ func (c *IndexedAttestationGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.Signature...) // Field 0: AttestingIndices - if len(c.AttestingIndices) > 8192 { - return nil, ssz.ErrListTooBig - } for _, o := range c.AttestingIndices { dst = binary.LittleEndian.AppendUint64(dst, o) } @@ -4196,9 +4049,6 @@ func (c *IndexedAttestationGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.AttestingIndices length is %d, which is not a multiple of 8: %w", len(sszSlice0), ssz.ErrIncorrectListSize) } numElem := len(sszSlice0) / 8 - if numElem > 8192 { - return fmt.Errorf("ssz-max exceeded: c.AttestingIndices has %d elements, ssz-max is 8192: %w", numElem, ssz.ErrListTooBig) - } c.AttestingIndices = make([]uint64, numElem) for i := 0; i < numElem; i++ { var tmp uint64 @@ -4222,8 +4072,18 @@ func (c *IndexedAttestationGloas) UnmarshalSSZ(buf []byte) error { } func (c *IndexedAttestationGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *IndexedAttestationGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsIndexedAttestationGloas = []byte{0b00000111} + +func (c *IndexedAttestationGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -4232,20 +4092,16 @@ func (c *IndexedAttestationGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *IndexedAttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *IndexedAttestationGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: AttestingIndices { - if len(c.AttestingIndices) > 8192 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.AttestingIndices { hh.AppendUint64(o) } hh.FillUpTo32() - numItems := uint64(len(c.AttestingIndices)) - hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(8192, numItems, 8)) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.AttestingIndices))) } // Field 1: Data if err := c.Data.HashTreeRootWith(hh); err != nil { @@ -4256,7 +4112,7 @@ func (c *IndexedAttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { return ssz.ErrBytesLength } hh.PutBytes(c.Signature) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsIndexedAttestationGloas) return nil } @@ -4325,8 +4181,18 @@ func (c *PayloadAttestation) UnmarshalSSZ(buf []byte) error { } func (c *PayloadAttestation) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *PayloadAttestation) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsPayloadAttestation = []byte{0b00000111} + +func (c *PayloadAttestation) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -4335,7 +4201,7 @@ func (c *PayloadAttestation) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *PayloadAttestation) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *PayloadAttestation) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: AggregationBits if len([]byte(c.AggregationBits)) != 2 { @@ -4351,7 +4217,7 @@ func (c *PayloadAttestation) HashTreeRootWith(hh *ssz.Hasher) (err error) { return ssz.ErrBytesLength } hh.PutBytes(c.Signature) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsPayloadAttestation) return nil } diff --git a/proto/prysm/v1alpha1/gloas.ssz.go b/proto/prysm/v1alpha1/gloas.ssz.go index 86f53777b99c..d8250648d20f 100644 --- a/proto/prysm/v1alpha1/gloas.ssz.go +++ b/proto/prysm/v1alpha1/gloas.ssz.go @@ -51,9 +51,6 @@ func (c *AttestationGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, []byte(c.CommitteeBits)...) // Field 0: AggregationBits - if len(c.AggregationBits) > 131072 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.AggregationBits...) return dst, err } @@ -79,7 +76,7 @@ func (c *AttestationGloas) UnmarshalSSZ(buf []byte) error { sszSlice0 := buf[sszVarOffset0:] // c.AggregationBits // Field 0: AggregationBits - if err = ssz.ValidateBitlist(sszSlice0, 131072); err != nil { + if err = ssz.ValidateProgressiveBitlist(sszSlice0); err != nil { return fmt.Errorf("AggregationBits: %w", err) } c.AggregationBits = append([]byte{}, go_bitfield.Bitlist(sszSlice0)...) @@ -101,8 +98,18 @@ func (c *AttestationGloas) UnmarshalSSZ(buf []byte) error { } func (c *AttestationGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *AttestationGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsAttestationGloas = []byte{0b00001111} + +func (c *AttestationGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -111,13 +118,13 @@ func (c *AttestationGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *AttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *AttestationGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: AggregationBits if len(c.AggregationBits) == 0 { return ssz.ErrEmptyBitlist } - hh.PutBitlist(c.AggregationBits, 131072) + hh.PutProgressiveBitlist(c.AggregationBits) // Field 1: Data if err := c.Data.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Data: %w", err) @@ -132,7 +139,7 @@ func (c *AttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { return ssz.ErrBytesLength } hh.PutBytes([]byte(c.CommitteeBits)) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsAttestationGloas) return nil } @@ -559,9 +566,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { offset += c.ParentExecutionRequests.SizeSSZ() // Field 3: ProposerSlashings - if len(c.ProposerSlashings) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.ProposerSlashings { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("ProposerSlashings: %w", err) @@ -569,9 +573,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 4: AttesterSlashings - if len(c.AttesterSlashings) > 1 { - return nil, ssz.ErrListTooBig - } { offset = 4 * len(c.AttesterSlashings) for _, o := range c.AttesterSlashings { @@ -586,9 +587,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 5: Attestations - if len(c.Attestations) > 8 { - return nil, ssz.ErrListTooBig - } { offset = 4 * len(c.Attestations) for _, o := range c.Attestations { @@ -603,9 +601,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 6: Deposits - if len(c.Deposits) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Deposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Deposits: %w", err) @@ -613,9 +608,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 7: VoluntaryExits - if len(c.VoluntaryExits) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.VoluntaryExits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("VoluntaryExits: %w", err) @@ -623,9 +615,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 9: BlsToExecutionChanges - if len(c.BlsToExecutionChanges) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BlsToExecutionChanges { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BlsToExecutionChanges: %w", err) @@ -638,9 +627,6 @@ func (c *BeaconBlockBodyGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 11: PayloadAttestations - if len(c.PayloadAttestations) > 4 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PayloadAttestations { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PayloadAttestations: %w", err) @@ -735,9 +721,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.ProposerSlashings length is %d, which is not a multiple of 416: %w", len(sszSlice3), ssz.ErrIncorrectListSize) } numElem := len(sszSlice3) / 416 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.ProposerSlashings has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.ProposerSlashings = make([]*ProposerSlashing, numElem) for i := 0; i < numElem; i++ { var tmp *ProposerSlashing @@ -763,9 +746,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned list bytes: when decoding c.AttesterSlashings, end-of-list offset is %d, which is not a multiple of 4 (offset size)", startOffset) } listLen := startOffset / 4 - if listLen > 1 { - return fmt.Errorf("ssz-max exceeded: c.AttesterSlashings has %d elements, ssz-max is 1: %w", listLen, ssz.ErrListTooBig) - } totalVarBytes := uint64(len(sszSlice4)) if totalVarBytes < startOffset { return fmt.Errorf("list bytes too short to contain an offset when decoding c.AttesterSlashings") @@ -813,9 +793,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned list bytes: when decoding c.Attestations, end-of-list offset is %d, which is not a multiple of 4 (offset size)", startOffset) } listLen := startOffset / 4 - if listLen > 8 { - return fmt.Errorf("ssz-max exceeded: c.Attestations has %d elements, ssz-max is 8: %w", listLen, ssz.ErrListTooBig) - } totalVarBytes := uint64(len(sszSlice5)) if totalVarBytes < startOffset { return fmt.Errorf("list bytes too short to contain an offset when decoding c.Attestations") @@ -856,9 +833,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Deposits length is %d, which is not a multiple of 1240: %w", len(sszSlice6), ssz.ErrIncorrectListSize) } numElem := len(sszSlice6) / 1240 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.Deposits has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.Deposits = make([]*Deposit, numElem) for i := 0; i < numElem; i++ { var tmp *Deposit @@ -877,9 +851,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.VoluntaryExits length is %d, which is not a multiple of 112: %w", len(sszSlice7), ssz.ErrIncorrectListSize) } numElem := len(sszSlice7) / 112 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.VoluntaryExits has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.VoluntaryExits = make([]*SignedVoluntaryExit, numElem) for i := 0; i < numElem; i++ { var tmp *SignedVoluntaryExit @@ -904,9 +875,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BlsToExecutionChanges length is %d, which is not a multiple of 172: %w", len(sszSlice9), ssz.ErrIncorrectListSize) } numElem := len(sszSlice9) / 172 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.BlsToExecutionChanges has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.BlsToExecutionChanges = make([]*SignedBLSToExecutionChange, numElem) for i := 0; i < numElem; i++ { var tmp *SignedBLSToExecutionChange @@ -931,9 +899,6 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PayloadAttestations length is %d, which is not a multiple of 202: %w", len(sszSlice11), ssz.ErrIncorrectListSize) } numElem := len(sszSlice11) / 202 - if numElem > 4 { - return fmt.Errorf("ssz-max exceeded: c.PayloadAttestations has %d elements, ssz-max is 4: %w", numElem, ssz.ErrListTooBig) - } c.PayloadAttestations = make([]*PayloadAttestation, numElem) for i := 0; i < numElem; i++ { var tmp *PayloadAttestation @@ -955,8 +920,18 @@ func (c *BeaconBlockBodyGloas) UnmarshalSSZ(buf []byte) error { } func (c *BeaconBlockBodyGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsBeaconBlockBodyGloas = []byte{0b11111111, 0b00011111} + +func (c *BeaconBlockBodyGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -965,7 +940,7 @@ func (c *BeaconBlockBodyGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *BeaconBlockBodyGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: RandaoReveal if len(c.RandaoReveal) != 96 { @@ -983,68 +958,53 @@ func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutBytes(c.Graffiti) // Field 3: ProposerSlashings { - if len(c.ProposerSlashings) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.ProposerSlashings { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("ProposerSlashings: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.ProposerSlashings)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.ProposerSlashings))) } // Field 4: AttesterSlashings { - if len(c.AttesterSlashings) > 1 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.AttesterSlashings { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("AttesterSlashings: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.AttesterSlashings)), 1) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.AttesterSlashings))) } // Field 5: Attestations { - if len(c.Attestations) > 8 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Attestations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Attestations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Attestations)), 8) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Attestations))) } // Field 6: Deposits { - if len(c.Deposits) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Deposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Deposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Deposits)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Deposits))) } // Field 7: VoluntaryExits { - if len(c.VoluntaryExits) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.VoluntaryExits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("VoluntaryExits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.VoluntaryExits)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.VoluntaryExits))) } // Field 8: SyncAggregate if err := c.SyncAggregate.HashTreeRootWith(hh); err != nil { @@ -1052,16 +1012,13 @@ func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 9: BlsToExecutionChanges { - if len(c.BlsToExecutionChanges) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BlsToExecutionChanges { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BlsToExecutionChanges: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BlsToExecutionChanges)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BlsToExecutionChanges))) } // Field 10: SignedExecutionPayloadBid if err := c.SignedExecutionPayloadBid.HashTreeRootWith(hh); err != nil { @@ -1069,22 +1026,19 @@ func (c *BeaconBlockBodyGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 11: PayloadAttestations { - if len(c.PayloadAttestations) > 4 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PayloadAttestations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PayloadAttestations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PayloadAttestations)), 4) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PayloadAttestations))) } // Field 12: ParentExecutionRequests if err := c.ParentExecutionRequests.HashTreeRootWith(hh); err != nil { return fmt.Errorf("ParentExecutionRequests: %w", err) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsBeaconBlockBodyGloas) return nil } @@ -1774,9 +1728,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 11: Validators - if len(c.Validators) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Validators { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Validators: %w", err) @@ -1784,29 +1735,17 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 12: Balances - if len(c.Balances) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Balances { dst = binary.LittleEndian.AppendUint64(dst, o) } // Field 15: PreviousEpochParticipation - if len(c.PreviousEpochParticipation) > 1099511627776 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.PreviousEpochParticipation...) // Field 16: CurrentEpochParticipation - if len(c.CurrentEpochParticipation) > 1099511627776 { - return nil, ssz.ErrListTooBig - } dst = append(dst, c.CurrentEpochParticipation...) // Field 21: InactivityScores - if len(c.InactivityScores) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.InactivityScores { dst = binary.LittleEndian.AppendUint64(dst, o) } @@ -1822,9 +1761,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 34: PendingDeposits - if len(c.PendingDeposits) > 134217728 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PendingDeposits { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PendingDeposits: %w", err) @@ -1832,9 +1768,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 35: PendingPartialWithdrawals - if len(c.PendingPartialWithdrawals) > 134217728 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PendingPartialWithdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PendingPartialWithdrawals: %w", err) @@ -1842,9 +1775,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 36: PendingConsolidations - if len(c.PendingConsolidations) > 262144 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PendingConsolidations { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PendingConsolidations: %w", err) @@ -1852,9 +1782,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 38: Builders - if len(c.Builders) > 1099511627776 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Builders { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("Builders: %w", err) @@ -1862,9 +1789,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 42: BuilderPendingWithdrawals - if len(c.BuilderPendingWithdrawals) > 1048576 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BuilderPendingWithdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("BuilderPendingWithdrawals: %w", err) @@ -1877,9 +1801,6 @@ func (c *BeaconStateGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 44: PayloadExpectedWithdrawals - if len(c.PayloadExpectedWithdrawals) > 16 { - return nil, ssz.ErrListTooBig - } for _, o := range c.PayloadExpectedWithdrawals { if dst, err = o.MarshalSSZTo(dst); err != nil { return nil, fmt.Errorf("PayloadExpectedWithdrawals: %w", err) @@ -2112,9 +2033,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Validators length is %d, which is not a multiple of 121: %w", len(sszSlice11), ssz.ErrIncorrectListSize) } numElem := len(sszSlice11) / 121 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.Validators has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.Validators = make([]*Validator, numElem) for i := 0; i < numElem; i++ { var tmp *Validator @@ -2133,9 +2051,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Balances length is %d, which is not a multiple of 8: %w", len(sszSlice12), ssz.ErrIncorrectListSize) } numElem := len(sszSlice12) / 8 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.Balances has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.Balances = make([]uint64, numElem) for i := 0; i < numElem; i++ { var tmp uint64 @@ -2205,9 +2120,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.InactivityScores length is %d, which is not a multiple of 8: %w", len(sszSlice21), ssz.ErrIncorrectListSize) } numElem := len(sszSlice21) / 8 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.InactivityScores has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.InactivityScores = make([]uint64, numElem) for i := 0; i < numElem; i++ { var tmp uint64 @@ -2297,9 +2209,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PendingDeposits length is %d, which is not a multiple of 192: %w", len(sszSlice34), ssz.ErrIncorrectListSize) } numElem := len(sszSlice34) / 192 - if numElem > 134217728 { - return fmt.Errorf("ssz-max exceeded: c.PendingDeposits has %d elements, ssz-max is 134217728: %w", numElem, ssz.ErrListTooBig) - } c.PendingDeposits = make([]*PendingDeposit, numElem) for i := 0; i < numElem; i++ { var tmp *PendingDeposit @@ -2318,9 +2227,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PendingPartialWithdrawals length is %d, which is not a multiple of 24: %w", len(sszSlice35), ssz.ErrIncorrectListSize) } numElem := len(sszSlice35) / 24 - if numElem > 134217728 { - return fmt.Errorf("ssz-max exceeded: c.PendingPartialWithdrawals has %d elements, ssz-max is 134217728: %w", numElem, ssz.ErrListTooBig) - } c.PendingPartialWithdrawals = make([]*PendingPartialWithdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *PendingPartialWithdrawal @@ -2339,9 +2245,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PendingConsolidations length is %d, which is not a multiple of 16: %w", len(sszSlice36), ssz.ErrIncorrectListSize) } numElem := len(sszSlice36) / 16 - if numElem > 262144 { - return fmt.Errorf("ssz-max exceeded: c.PendingConsolidations has %d elements, ssz-max is 262144: %w", numElem, ssz.ErrListTooBig) - } c.PendingConsolidations = make([]*PendingConsolidation, numElem) for i := 0; i < numElem; i++ { var tmp *PendingConsolidation @@ -2374,9 +2277,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Builders length is %d, which is not a multiple of 93: %w", len(sszSlice38), ssz.ErrIncorrectListSize) } numElem := len(sszSlice38) / 93 - if numElem > 1099511627776 { - return fmt.Errorf("ssz-max exceeded: c.Builders has %d elements, ssz-max is 1099511627776: %w", numElem, ssz.ErrListTooBig) - } c.Builders = make([]*Builder, numElem) for i := 0; i < numElem; i++ { var tmp *Builder @@ -2418,9 +2318,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BuilderPendingWithdrawals length is %d, which is not a multiple of 36: %w", len(sszSlice42), ssz.ErrIncorrectListSize) } numElem := len(sszSlice42) / 36 - if numElem > 1048576 { - return fmt.Errorf("ssz-max exceeded: c.BuilderPendingWithdrawals has %d elements, ssz-max is 1048576: %w", numElem, ssz.ErrListTooBig) - } c.BuilderPendingWithdrawals = make([]*BuilderPendingWithdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *BuilderPendingWithdrawal @@ -2445,9 +2342,6 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.PayloadExpectedWithdrawals length is %d, which is not a multiple of 44: %w", len(sszSlice44), ssz.ErrIncorrectListSize) } numElem := len(sszSlice44) / 44 - if numElem > 16 { - return fmt.Errorf("ssz-max exceeded: c.PayloadExpectedWithdrawals has %d elements, ssz-max is 16: %w", numElem, ssz.ErrListTooBig) - } c.PayloadExpectedWithdrawals = make([]*v1.Withdrawal, numElem) for i := 0; i < numElem; i++ { var tmp *v1.Withdrawal @@ -2477,8 +2371,18 @@ func (c *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { } func (c *BeaconStateGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsBeaconStateGloas = []byte{0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00111111} + +func (c *BeaconStateGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -2487,7 +2391,7 @@ func (c *BeaconStateGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *BeaconStateGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: GenesisTime hh.PutUint64(c.GenesisTime) @@ -2571,29 +2475,22 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutUint64(c.Eth1DepositIndex) // Field 11: Validators { - if len(c.Validators) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Validators { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Validators: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Validators)), 1099511627776) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Validators))) } // Field 12: Balances { - if len(c.Balances) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Balances { hh.AppendUint64(o) } hh.FillUpTo32() - numItems := uint64(len(c.Balances)) - hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(1099511627776, numItems, 8)) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Balances))) } // Field 13: RandaoMixes { @@ -2621,29 +2518,17 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.Merkleize(subIndx) } // Field 15: PreviousEpochParticipation - { - if len(c.PreviousEpochParticipation) > 1099511627776 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(c.PreviousEpochParticipation) - numItems := uint64(len(c.PreviousEpochParticipation)) - hh.MerkleizeWithMixin(subIndx, numItems, (1099511627776*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PreviousEpochParticipation))) } - // Field 16: CurrentEpochParticipation - { - if len(c.CurrentEpochParticipation) > 1099511627776 { - return ssz.ErrBytesLength - } subIndx := hh.Index() hh.AppendBytes32(c.CurrentEpochParticipation) - numItems := uint64(len(c.CurrentEpochParticipation)) - hh.MerkleizeWithMixin(subIndx, numItems, (1099511627776*1+31)/32) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.CurrentEpochParticipation))) } - // Field 17: JustificationBits if len([]byte(c.JustificationBits)) != 1 { return ssz.ErrBytesLength @@ -2663,16 +2548,12 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 21: InactivityScores { - if len(c.InactivityScores) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.InactivityScores { hh.AppendUint64(o) } hh.FillUpTo32() - numItems := uint64(len(c.InactivityScores)) - hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(1099511627776, numItems, 8)) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.InactivityScores))) } // Field 22: CurrentSyncCommittee if err := c.CurrentSyncCommittee.HashTreeRootWith(hh); err != nil { @@ -2730,42 +2611,33 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 34: PendingDeposits { - if len(c.PendingDeposits) > 134217728 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PendingDeposits { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PendingDeposits: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PendingDeposits)), 134217728) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PendingDeposits))) } // Field 35: PendingPartialWithdrawals { - if len(c.PendingPartialWithdrawals) > 134217728 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PendingPartialWithdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PendingPartialWithdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PendingPartialWithdrawals)), 134217728) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PendingPartialWithdrawals))) } // Field 36: PendingConsolidations { - if len(c.PendingConsolidations) > 262144 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PendingConsolidations { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PendingConsolidations: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PendingConsolidations)), 262144) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PendingConsolidations))) } // Field 37: ProposerLookahead { @@ -2780,16 +2652,13 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 38: Builders { - if len(c.Builders) > 1099511627776 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Builders { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("Builders: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Builders)), 1099511627776) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Builders))) } // Field 39: NextWithdrawalBuilderIndex if err := c.NextWithdrawalBuilderIndex.HashTreeRootWith(hh); err != nil { @@ -2815,16 +2684,13 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 42: BuilderPendingWithdrawals { - if len(c.BuilderPendingWithdrawals) > 1048576 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BuilderPendingWithdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("BuilderPendingWithdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BuilderPendingWithdrawals)), 1048576) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BuilderPendingWithdrawals))) } // Field 43: LatestExecutionPayloadBid if err := c.LatestExecutionPayloadBid.HashTreeRootWith(hh); err != nil { @@ -2832,16 +2698,13 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 44: PayloadExpectedWithdrawals { - if len(c.PayloadExpectedWithdrawals) > 16 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.PayloadExpectedWithdrawals { if err := o.HashTreeRootWith(hh); err != nil { return fmt.Errorf("PayloadExpectedWithdrawals: %w", err) } } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.PayloadExpectedWithdrawals)), 16) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.PayloadExpectedWithdrawals))) } // Field 45: PtcWindow { @@ -2856,7 +2719,7 @@ func (c *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.Merkleize(subIndx) } - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsBeaconStateGloas) return nil } @@ -3547,9 +3410,6 @@ func (c *DataColumnSidecarGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.BeaconBlockRoot...) // Field 1: Column - if len(c.Column) > 4096 { - return nil, ssz.ErrListTooBig - } for _, o := range c.Column { if len(o) != 2048 { return nil, ssz.ErrBytesLength @@ -3558,9 +3418,6 @@ func (c *DataColumnSidecarGloas) MarshalSSZTo(dst []byte) ([]byte, error) { } // Field 2: KzgProofs - if len(c.KzgProofs) > 4096 { - return nil, ssz.ErrListTooBig - } for _, o := range c.KzgProofs { if len(o) != 48 { return nil, ssz.ErrBytesLength @@ -3604,9 +3461,6 @@ func (c *DataColumnSidecarGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.Column length is %d, which is not a multiple of 2048: %w", len(sszSlice1), ssz.ErrIncorrectListSize) } numElem := len(sszSlice1) / 2048 - if numElem > 4096 { - return fmt.Errorf("ssz-max exceeded: c.Column has %d elements, ssz-max is 4096: %w", numElem, ssz.ErrListTooBig) - } c.Column = make([][]byte, numElem) for i := 0; i < numElem; i++ { var tmp []byte @@ -3624,9 +3478,6 @@ func (c *DataColumnSidecarGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.KzgProofs length is %d, which is not a multiple of 48: %w", len(sszSlice2), ssz.ErrIncorrectListSize) } numElem := len(sszSlice2) / 48 - if numElem > 4096 { - return fmt.Errorf("ssz-max exceeded: c.KzgProofs has %d elements, ssz-max is 4096: %w", numElem, ssz.ErrListTooBig) - } c.KzgProofs = make([][]byte, numElem) for i := 0; i < numElem; i++ { var tmp []byte @@ -3666,9 +3517,6 @@ func (c *DataColumnSidecarGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.PutUint64(c.Index) // Field 1: Column { - if len(c.Column) > 4096 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.Column { if len(o) != 2048 { @@ -3676,13 +3524,10 @@ func (c *DataColumnSidecarGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.PutBytes(o) } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.Column)), 4096) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.Column))) } // Field 2: KzgProofs { - if len(c.KzgProofs) > 4096 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.KzgProofs { if len(o) != 48 { @@ -3690,7 +3535,7 @@ func (c *DataColumnSidecarGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.PutBytes(o) } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.KzgProofs)), 4096) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.KzgProofs))) } // Field 3: Slot if err := c.Slot.HashTreeRootWith(hh); err != nil { @@ -3784,9 +3629,6 @@ func (c *ExecutionPayloadBid) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.ExecutionRequestsRoot...) // Field 10: BlobKzgCommitments - if len(c.BlobKzgCommitments) > 4096 { - return nil, ssz.ErrListTooBig - } for _, o := range c.BlobKzgCommitments { if len(o) != 48 { return nil, ssz.ErrBytesLength @@ -3873,9 +3715,6 @@ func (c *ExecutionPayloadBid) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.BlobKzgCommitments length is %d, which is not a multiple of 48: %w", len(sszSlice10), ssz.ErrIncorrectListSize) } numElem := len(sszSlice10) / 48 - if numElem > 4096 { - return fmt.Errorf("ssz-max exceeded: c.BlobKzgCommitments has %d elements, ssz-max is 4096: %w", numElem, ssz.ErrListTooBig) - } c.BlobKzgCommitments = make([][]byte, numElem) for i := 0; i < numElem; i++ { var tmp []byte @@ -3894,8 +3733,18 @@ func (c *ExecutionPayloadBid) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionPayloadBid) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionPayloadBid = []byte{0b11111111, 0b00001111} + +func (c *ExecutionPayloadBid) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -3904,7 +3753,7 @@ func (c *ExecutionPayloadBid) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionPayloadBid) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: ParentBlockHash if len(c.ParentBlockHash) != 32 { @@ -3951,9 +3800,6 @@ func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { } // Field 10: BlobKzgCommitments { - if len(c.BlobKzgCommitments) > 4096 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.BlobKzgCommitments { if len(o) != 48 { @@ -3961,14 +3807,14 @@ func (c *ExecutionPayloadBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { } hh.PutBytes(o) } - hh.MerkleizeWithMixin(subIndx, uint64(len(c.BlobKzgCommitments)), 4096) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.BlobKzgCommitments))) } // Field 11: ExecutionRequestsRoot if len(c.ExecutionRequestsRoot) != 32 { return ssz.ErrBytesLength } hh.PutBytes(c.ExecutionRequestsRoot) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionPayloadBid) return nil } @@ -4090,8 +3936,18 @@ func (c *ExecutionPayloadEnvelope) UnmarshalSSZ(buf []byte) error { } func (c *ExecutionPayloadEnvelope) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsExecutionPayloadEnvelope = []byte{0b00011111} + +func (c *ExecutionPayloadEnvelope) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -4100,7 +3956,7 @@ func (c *ExecutionPayloadEnvelope) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *ExecutionPayloadEnvelope) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: Payload if err := c.Payload.HashTreeRootWith(hh); err != nil { @@ -4124,7 +3980,7 @@ func (c *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) (err error) return ssz.ErrBytesLength } hh.PutBytes(c.ParentBeaconBlockRoot) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsExecutionPayloadEnvelope) return nil } @@ -4162,9 +4018,6 @@ func (c *IndexedAttestationGloas) MarshalSSZTo(dst []byte) ([]byte, error) { dst = append(dst, c.Signature...) // Field 0: AttestingIndices - if len(c.AttestingIndices) > 131072 { - return nil, ssz.ErrListTooBig - } for _, o := range c.AttestingIndices { dst = binary.LittleEndian.AppendUint64(dst, o) } @@ -4196,9 +4049,6 @@ func (c *IndexedAttestationGloas) UnmarshalSSZ(buf []byte) error { return fmt.Errorf("misaligned bytes: c.AttestingIndices length is %d, which is not a multiple of 8: %w", len(sszSlice0), ssz.ErrIncorrectListSize) } numElem := len(sszSlice0) / 8 - if numElem > 131072 { - return fmt.Errorf("ssz-max exceeded: c.AttestingIndices has %d elements, ssz-max is 131072: %w", numElem, ssz.ErrListTooBig) - } c.AttestingIndices = make([]uint64, numElem) for i := 0; i < numElem; i++ { var tmp uint64 @@ -4222,8 +4072,18 @@ func (c *IndexedAttestationGloas) UnmarshalSSZ(buf []byte) error { } func (c *IndexedAttestationGloas) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *IndexedAttestationGloas) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsIndexedAttestationGloas = []byte{0b00000111} + +func (c *IndexedAttestationGloas) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -4232,20 +4092,16 @@ func (c *IndexedAttestationGloas) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *IndexedAttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *IndexedAttestationGloas) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: AttestingIndices { - if len(c.AttestingIndices) > 131072 { - return ssz.ErrListTooBig - } subIndx := hh.Index() for _, o := range c.AttestingIndices { hh.AppendUint64(o) } hh.FillUpTo32() - numItems := uint64(len(c.AttestingIndices)) - hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(131072, numItems, 8)) + hh.MerkleizeProgressiveWithMixin(subIndx, uint64(len(c.AttestingIndices))) } // Field 1: Data if err := c.Data.HashTreeRootWith(hh); err != nil { @@ -4256,7 +4112,7 @@ func (c *IndexedAttestationGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { return ssz.ErrBytesLength } hh.PutBytes(c.Signature) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsIndexedAttestationGloas) return nil } @@ -4325,8 +4181,18 @@ func (c *PayloadAttestation) UnmarshalSSZ(buf []byte) error { } func (c *PayloadAttestation) HashTreeRoot() ([32]byte, error) { + return c.ProgressiveHashTreeRoot() +} + +func (c *PayloadAttestation) HashTreeRootWith(hh *ssz.Hasher) error { + return c.ProgressiveHashTreeRootWith(hh) +} + +var activeFieldsPayloadAttestation = []byte{0b00000111} + +func (c *PayloadAttestation) ProgressiveHashTreeRoot() ([32]byte, error) { hh := ssz.DefaultHasherPool.Get() - if err := c.HashTreeRootWith(hh); err != nil { + if err := c.ProgressiveHashTreeRootWith(hh); err != nil { ssz.DefaultHasherPool.Put(hh) return [32]byte{}, err } @@ -4335,7 +4201,7 @@ func (c *PayloadAttestation) HashTreeRoot() ([32]byte, error) { return root, err } -func (c *PayloadAttestation) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *PayloadAttestation) ProgressiveHashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() // Field 0: AggregationBits if len([]byte(c.AggregationBits)) != 64 { @@ -4351,7 +4217,7 @@ func (c *PayloadAttestation) HashTreeRootWith(hh *ssz.Hasher) (err error) { return ssz.ErrBytesLength } hh.PutBytes(c.Signature) - hh.Merkleize(indx) + hh.MerkleizeProgressiveWithActiveFields(indx, activeFieldsPayloadAttestation) return nil } diff --git a/proto/prysm/v1alpha1/gloas.yaml b/proto/prysm/v1alpha1/gloas.yaml index c5f875c07018..018ad0742d47 100644 --- a/proto/prysm/v1alpha1/gloas.yaml +++ b/proto/prysm/v1alpha1/gloas.yaml @@ -1,13 +1,38 @@ package: "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" types: - name: "AttestationGloas" + progressive: {} + fields: + AggregationBits: {type: "ProgressiveBitlist"} - name: "AggregateAttestationAndProofGloas" - name: "SignedAggregateAttestationAndProofGloas" - name: "AttesterSlashingGloas" - name: "BeaconBlockBodyGloas" + progressive: {} + fields: + ProposerSlashings: {type: "ProgressiveList"} + AttesterSlashings: {type: "ProgressiveList"} + Attestations: {type: "ProgressiveList"} + Deposits: {type: "ProgressiveList"} + VoluntaryExits: {type: "ProgressiveList"} + BlsToExecutionChanges: {type: "ProgressiveList"} + PayloadAttestations: {type: "ProgressiveList"} - name: "BeaconBlockContentsGloas" - name: "BeaconBlockGloas" - name: "BeaconStateGloas" + progressive: {} + fields: + Validators: {type: "ProgressiveList"} + Balances: {type: "ProgressiveList"} + PreviousEpochParticipation: {type: "ProgressiveList"} + CurrentEpochParticipation: {type: "ProgressiveList"} + InactivityScores: {type: "ProgressiveList"} + PendingDeposits: {type: "ProgressiveList"} + PendingPartialWithdrawals: {type: "ProgressiveList"} + PendingConsolidations: {type: "ProgressiveList"} + Builders: {type: "ProgressiveList"} + BuilderPendingWithdrawals: {type: "ProgressiveList"} + PayloadExpectedWithdrawals: {type: "ProgressiveList"} - name: "BlindedExecutionPayloadEnvelope" - name: "Builder" - name: "BuilderPendingPayment" @@ -15,10 +40,21 @@ types: - name: "BuilderPreferencesRequest" - name: "BuilderPreferences" - name: "DataColumnSidecarGloas" + fields: + Column: {type: "ProgressiveList"} + KzgProofs: {type: "ProgressiveList"} - name: "ExecutionPayloadBid" + progressive: {} + fields: + BlobKzgCommitments: {type: "ProgressiveList"} - name: "ExecutionPayloadEnvelope" + progressive: {} - name: "IndexedAttestationGloas" + progressive: {} + fields: + AttestingIndices: {type: "ProgressiveList"} - name: "PayloadAttestation" + progressive: {} - name: "PayloadAttestationData" - name: "PayloadAttestationMessage" - name: "ProposerPreferences" diff --git a/specrefs/configs.yml b/specrefs/configs.yml index 42e0f7f432d3..2472813fc566 100644 --- a/specrefs/configs.yml +++ b/specrefs/configs.yml @@ -4,15 +4,15 @@ search: AggregateDueBPS\s+primitives.BP regex: true spec: | - - AGGREGATE_DUE_BPS: uint64 = 6667 + + AGGREGATE_DUE_BPS: Uint64 = 6667 - name: AGGREGATE_DUE_BPS_GLOAS#gloas sources: [] spec: | - - AGGREGATE_DUE_BPS_GLOAS: uint64 = 5000 + + AGGREGATE_DUE_BPS_GLOAS: Uint64 = 5000 - name: ALTAIR_FORK_EPOCH#altair @@ -41,15 +41,15 @@ search: ^\tAttestationDueBPS\s regex: true spec: | - - ATTESTATION_DUE_BPS: uint64 = 3333 + + ATTESTATION_DUE_BPS: Uint64 = 3333 - name: ATTESTATION_DUE_BPS_GLOAS#gloas sources: [] spec: | - - ATTESTATION_DUE_BPS_GLOAS: uint64 = 2500 + + ATTESTATION_DUE_BPS_GLOAS: Uint64 = 2500 - name: ATTESTATION_PROPAGATION_SLOT_RANGE#phase0 @@ -58,8 +58,8 @@ search: AttestationPropagationSlotRange\s+primitives.Slot regex: true spec: | - - ATTESTATION_PROPAGATION_SLOT_RANGE = 32 + + ATTESTATION_PROPAGATION_SLOT_RANGE: Slot = 32 - name: ATTESTATION_SUBNET_COUNT#phase0 @@ -68,8 +68,8 @@ search: AttestationSubnetCount\s+uint64 regex: true spec: | - - ATTESTATION_SUBNET_COUNT = 64 + + ATTESTATION_SUBNET_COUNT: Uint64 = 64 - name: ATTESTATION_SUBNET_EXTRA_BITS#phase0 @@ -78,8 +78,8 @@ search: AttestationSubnetExtraBits\s+uint64 regex: true spec: | - - ATTESTATION_SUBNET_EXTRA_BITS = 0 + + ATTESTATION_SUBNET_EXTRA_BITS: Uint64 = 0 - name: BALANCE_PER_ADDITIONAL_CUSTODY_GROUP#fulu @@ -137,8 +137,8 @@ search: BlobsidecarSubnetCount\s+uint64 regex: true spec: | - - BLOB_SIDECAR_SUBNET_COUNT = 6 + + BLOB_SIDECAR_SUBNET_COUNT: Uint64 = 6 - name: BLOB_SIDECAR_SUBNET_COUNT_ELECTRA#electra @@ -147,8 +147,8 @@ search: BlobsidecarSubnetCountElectra\s+uint64 regex: true spec: | - - BLOB_SIDECAR_SUBNET_COUNT_ELECTRA = 9 + + BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: Uint64 = 9 - name: CAPELLA_FORK_EPOCH#capella @@ -177,29 +177,29 @@ search: \bChurnLimitQuotient\s+uint64 regex: true spec: | - - CHURN_LIMIT_QUOTIENT: uint64 = 65536 + + CHURN_LIMIT_QUOTIENT: Uint64 = 65536 - name: CHURN_LIMIT_QUOTIENT_GLOAS#gloas sources: [] spec: | - - CHURN_LIMIT_QUOTIENT_GLOAS: uint64 = 32768 + + CHURN_LIMIT_QUOTIENT_GLOAS: Uint64 = 32768 - name: CONFIRMATION_BYZANTINE_THRESHOLD#phase0 sources: [] spec: | - - CONFIRMATION_BYZANTINE_THRESHOLD: uint64 = 25 + + CONFIRMATION_BYZANTINE_THRESHOLD: Uint64 = 25 - name: CONSOLIDATION_CHURN_LIMIT_QUOTIENT#gloas sources: [] spec: | - - CONSOLIDATION_CHURN_LIMIT_QUOTIENT: uint64 = 65536 + + CONSOLIDATION_CHURN_LIMIT_QUOTIENT: Uint64 = 65536 - name: CONTRIBUTION_DUE_BPS#altair @@ -208,15 +208,15 @@ search: ContributionDueBPS\s+primitives.BP regex: true spec: | - - CONTRIBUTION_DUE_BPS: uint64 = 6667 + + CONTRIBUTION_DUE_BPS: Uint64 = 6667 - name: CONTRIBUTION_DUE_BPS_GLOAS#gloas sources: [] spec: | - - CONTRIBUTION_DUE_BPS_GLOAS: uint64 = 5000 + + CONTRIBUTION_DUE_BPS_GLOAS: Uint64 = 5000 - name: CUSTODY_REQUIREMENT#fulu @@ -225,8 +225,8 @@ search: CustodyRequirement\s+uint64.*yaml:"CUSTODY_REQUIREMENT" regex: true spec: | - - CUSTODY_REQUIREMENT = 4 + + CUSTODY_REQUIREMENT: Uint64 = 4 - name: DATA_COLUMN_SIDECAR_SUBNET_COUNT#fulu @@ -235,8 +235,8 @@ search: DataColumnSidecarSubnetCount\s+uint64 regex: true spec: | - - DATA_COLUMN_SIDECAR_SUBNET_COUNT = 128 + + DATA_COLUMN_SIDECAR_SUBNET_COUNT: Uint64 = 128 - name: DENEB_FORK_EPOCH#deneb @@ -259,6 +259,36 @@ DENEB_FORK_VERSION: Version = '0x04000000' +- name: DEPOSIT_CHAIN_ID#phase0 + sources: + - file: config/params/config.go + search: DepositChainID\s+uint64 + regex: true + spec: | + + DEPOSIT_CHAIN_ID: Uint64 = 1 + + +- name: DEPOSIT_CONTRACT_ADDRESS#phase0 + sources: + - file: config/params/config.go + search: DepositContractAddress\s+string + regex: true + spec: | + + DEPOSIT_CONTRACT_ADDRESS: ExecutionAddress = '0x00000000219ab540356cBB839Cbe05303d7705Fa' + + +- name: DEPOSIT_NETWORK_ID#phase0 + sources: + - file: config/params/config.go + search: DepositNetworkID\s+uint64 + regex: true + spec: | + + DEPOSIT_NETWORK_ID: Uint64 = 1 + + - name: EJECTION_BALANCE#phase0 sources: - file: config/params/config.go @@ -295,8 +325,8 @@ search: EpochsPerSubnetSubscription\s+uint64 regex: true spec: | - - EPOCHS_PER_SUBNET_SUBSCRIPTION = 256 + + EPOCHS_PER_SUBNET_SUBSCRIPTION: Epoch = 256 - name: ETH1_FOLLOW_DISTANCE#phase0 @@ -305,8 +335,8 @@ search: Eth1FollowDistance\s+uint64 regex: true spec: | - - ETH1_FOLLOW_DISTANCE: uint64 = 2048 + + ETH1_FOLLOW_DISTANCE: Uint64 = 2048 - name: FULU_FORK_EPOCH#fulu @@ -329,14 +359,22 @@ FULU_FORK_VERSION: Version = '0x06000000' +- name: GAS_LIMIT_SCHEDULE#gloas + sources: [] + spec: | + + GAS_LIMIT_SCHEDULE: tuple[frozendict[str, Any], ...] = ( + ) + + - name: GENESIS_DELAY#phase0 sources: - file: config/params/config.go search: GenesisDelay\s+uint64 regex: true spec: | - - GENESIS_DELAY: uint64 = 604800 + + GENESIS_DELAY: Uint64 = 604800 - name: GENESIS_FORK_VERSION#phase0 @@ -383,8 +421,8 @@ search: InactivityScoreBias\s+uint64 regex: true spec: | - - INACTIVITY_SCORE_BIAS: uint64 = 4 + + INACTIVITY_SCORE_BIAS: Uint64 = 4 - name: INACTIVITY_SCORE_RECOVERY_RATE#altair @@ -393,15 +431,15 @@ search: InactivityScoreRecoveryRate\s+uint64 regex: true spec: | - - INACTIVITY_SCORE_RECOVERY_RATE: uint64 = 16 + + INACTIVITY_SCORE_RECOVERY_RATE: Uint64 = 16 - name: INCLUSION_LIST_DUE_BPS#heze sources: [] spec: | - - INCLUSION_LIST_DUE_BPS: uint64 = 6667 + + INCLUSION_LIST_DUE_BPS: Uint64 = 6667 - name: MAXIMUM_GOSSIP_CLOCK_DISPARITY#phase0 @@ -410,8 +448,8 @@ search: MaximumGossipClockDisparity\s+uint64 regex: true spec: | - - MAXIMUM_GOSSIP_CLOCK_DISPARITY = 500 + + MAXIMUM_GOSSIP_CLOCK_DISPARITY: Uint64 = 500 - name: MAX_BLOBS_PER_BLOCK#deneb @@ -420,8 +458,8 @@ search: DeprecatedMaxBlobsPerBlock\s+int regex: true spec: | - - MAX_BLOBS_PER_BLOCK: uint64 = 6 + + MAX_BLOBS_PER_BLOCK: Uint64 = 6 - name: MAX_BLOBS_PER_BLOCK_ELECTRA#electra @@ -430,15 +468,8 @@ search: DeprecatedMaxBlobsPerBlockElectra\s+int regex: true spec: | - - MAX_BLOBS_PER_BLOCK_ELECTRA: uint64 = 9 - - -- name: MAX_BYTES_PER_INCLUSION_LIST#heze - sources: [] - spec: | - - MAX_BYTES_PER_INCLUSION_LIST = 8192 + + MAX_BLOBS_PER_BLOCK_ELECTRA: Uint64 = 9 - name: MAX_PAYLOAD_SIZE#phase0 @@ -447,8 +478,8 @@ search: MaxPayloadSize\s+uint64 regex: true spec: | - - MAX_PAYLOAD_SIZE = 10485760 + + MAX_PAYLOAD_SIZE: Uint64 = 10485760 - name: MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT#deneb @@ -457,8 +488,8 @@ search: MaxPerEpochActivationChurnLimit\s+uint64 regex: true spec: | - - MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: uint64 = 8 + + MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: Uint64 = 8 - name: MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT_GLOAS#gloas @@ -484,8 +515,8 @@ search: MaxRequestBlocks\s+uint64 regex: true spec: | - - MAX_REQUEST_BLOCKS = 1024 + + MAX_REQUEST_BLOCKS: Uint64 = 1024 - name: MAX_REQUEST_BLOCKS_DENEB#deneb @@ -494,15 +525,15 @@ search: MaxRequestBlocksDeneb\s+uint64 regex: true spec: | - - MAX_REQUEST_BLOCKS_DENEB = 128 + + MAX_REQUEST_BLOCKS_DENEB: Uint64 = 128 - name: MAX_REQUEST_INCLUSION_LIST#heze sources: [] spec: | - - MAX_REQUEST_INCLUSION_LIST = 16 + + MAX_REQUEST_INCLUSION_LIST: Uint64 = 16 - name: MAX_REQUEST_PAYLOADS#gloas @@ -511,8 +542,8 @@ search: MaxRequestPayloads\s+uint64 regex: true spec: | - - MAX_REQUEST_PAYLOADS = 128 + + MAX_REQUEST_PAYLOADS: Uint64 = 128 - name: MESSAGE_DOMAIN_INVALID_SNAPPY#phase0 @@ -540,8 +571,8 @@ - file: config/params/mainnet_config.go search: MinBuilderWithdrawabilityDelay spec: | - - MIN_BUILDER_WITHDRAWABILITY_DELAY: uint64 = 8192 + + MIN_BUILDER_WITHDRAWABILITY_DELAY: Epoch = 64 - name: MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS#deneb @@ -550,8 +581,8 @@ search: MinEpochsForBlobsSidecarsRequest\s+primitives.Epoch regex: true spec: | - - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS = 4096 + + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: Epoch = 4096 - name: MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS#fulu @@ -560,8 +591,8 @@ search: MinEpochsForDataColumnSidecarsRequest\s+primitives.Epoch regex: true spec: | - - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS = 4096 + + MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS: Epoch = 4096 - name: MIN_GENESIS_ACTIVE_VALIDATOR_COUNT#phase0 @@ -570,8 +601,8 @@ search: MinGenesisActiveValidatorCount\s+uint64 regex: true spec: | - - MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: uint64 = 16384 + + MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: Uint64 = 16384 - name: MIN_GENESIS_TIME#phase0 @@ -580,8 +611,8 @@ search: MinGenesisTime\s+uint64 regex: true spec: | - - MIN_GENESIS_TIME: uint64 = 1606824000 + + MIN_GENESIS_TIME: Uint64 = 1606824000 - name: MIN_PER_EPOCH_CHURN_LIMIT#phase0 @@ -590,8 +621,8 @@ search: MinPerEpochChurnLimit\s+uint64 regex: true spec: | - - MIN_PER_EPOCH_CHURN_LIMIT: uint64 = 4 + + MIN_PER_EPOCH_CHURN_LIMIT: Uint64 = 4 - name: MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA#electra @@ -604,14 +635,21 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: Gwei = 128000000000 +- name: MIN_SLOTS_FOR_INCLUSION_LISTS_REQUESTS#heze + sources: [] + spec: | + + MIN_SLOTS_FOR_INCLUSION_LISTS_REQUESTS: Slot = 1 + + - name: MIN_VALIDATOR_WITHDRAWABILITY_DELAY#phase0 sources: - file: config/params/config.go search: MinValidatorWithdrawabilityDelay\s+primitives.Epoch regex: true spec: | - - MIN_VALIDATOR_WITHDRAWABILITY_DELAY: uint64 = 256 + + MIN_VALIDATOR_WITHDRAWABILITY_DELAY: Epoch = 256 - name: NUMBER_OF_CUSTODY_GROUPS#fulu @@ -620,8 +658,8 @@ search: NumberOfCustodyGroups\s+uint64 regex: true spec: | - - NUMBER_OF_CUSTODY_GROUPS = 128 + + NUMBER_OF_CUSTODY_GROUPS: Uint64 = 128 - name: PAYLOAD_ATTESTATION_DUE_BPS#gloas @@ -630,8 +668,8 @@ search: PayloadAttestationDueBPS\s+primitives.BP regex: true spec: | - - PAYLOAD_ATTESTATION_DUE_BPS: uint64 = 7500 + + PAYLOAD_ATTESTATION_DUE_BPS: Uint64 = 7500 - name: PAYLOAD_DUE_BPS#gloas @@ -640,8 +678,8 @@ search: PayloadDueBPS\s+primitives.BP regex: true spec: | - - PAYLOAD_DUE_BPS: uint64 = 7500 + + PAYLOAD_DUE_BPS: Uint64 = 5000 - name: PROPOSER_REORG_CUTOFF_BPS#phase0 @@ -650,8 +688,8 @@ search: ProposerReorgCutoffBPS\s+primitives.BP regex: true spec: | - - PROPOSER_REORG_CUTOFF_BPS: uint64 = 1667 + + PROPOSER_REORG_CUTOFF_BPS: Uint64 = 1667 - name: PROPOSER_SCORE_BOOST#phase0 @@ -660,8 +698,8 @@ search: ProposerScoreBoost\s+uint64 regex: true spec: | - - PROPOSER_SCORE_BOOST: uint64 = 40 + + PROPOSER_SCORE_BOOST: Uint64 = 40 - name: REORG_HEAD_WEIGHT_THRESHOLD#phase0 @@ -670,8 +708,8 @@ search: ReorgHeadWeightThreshold\s+uint64 regex: true spec: | - - REORG_HEAD_WEIGHT_THRESHOLD: uint64 = 20 + + REORG_HEAD_WEIGHT_THRESHOLD: Uint64 = 20 - name: REORG_MAX_EPOCHS_SINCE_FINALIZATION#phase0 @@ -690,8 +728,8 @@ search: ReorgParentWeightThreshold\s+uint64 regex: true spec: | - - REORG_PARENT_WEIGHT_THRESHOLD: uint64 = 160 + + REORG_PARENT_WEIGHT_THRESHOLD: Uint64 = 160 - name: SAMPLES_PER_SLOT#fulu @@ -700,8 +738,8 @@ search: SamplesPerSlot\s+uint64 regex: true spec: | - - SAMPLES_PER_SLOT = 8 + + SAMPLES_PER_SLOT: Uint64 = 8 - name: SECONDS_PER_ETH1_BLOCK#phase0 @@ -710,8 +748,8 @@ search: SecondsPerETH1Block\s+uint64 regex: true spec: | - - SECONDS_PER_ETH1_BLOCK: uint64 = 14 + + SECONDS_PER_ETH1_BLOCK: Uint64 = 14 - name: SHARD_COMMITTEE_PERIOD#phase0 @@ -720,8 +758,8 @@ search: ShardCommitteePeriod\s+primitives.Epoch regex: true spec: | - - SHARD_COMMITTEE_PERIOD: uint64 = 256 + + SHARD_COMMITTEE_PERIOD: Epoch = 256 - name: SLOT_DURATION_MS#phase0 @@ -730,8 +768,8 @@ search: SlotDurationMilliseconds\s+uint64 regex: true spec: | - - SLOT_DURATION_MS: uint64 = 12000 + + SLOT_DURATION_MS: Uint64 = 12000 - name: SUBNETS_PER_NODE#phase0 @@ -740,8 +778,8 @@ search: SubnetsPerNode\s+uint64 regex: true spec: | - - SUBNETS_PER_NODE = 2 + + SUBNETS_PER_NODE: Uint64 = 2 - name: SYNC_MESSAGE_DUE_BPS#altair @@ -750,15 +788,15 @@ search: SyncMessageDueBPS\s+primitives.BP regex: true spec: | - - SYNC_MESSAGE_DUE_BPS: uint64 = 3333 + + SYNC_MESSAGE_DUE_BPS: Uint64 = 3333 - name: SYNC_MESSAGE_DUE_BPS_GLOAS#gloas sources: [] spec: | - - SYNC_MESSAGE_DUE_BPS_GLOAS: uint64 = 2500 + + SYNC_MESSAGE_DUE_BPS_GLOAS: Uint64 = 2500 - name: TERMINAL_BLOCK_HASH#bellatrix @@ -777,8 +815,8 @@ search: TerminalBlockHashActivationEpoch\s+primitives.Epoch regex: true spec: | - - TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH = 18446744073709551615 + + TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: Epoch = 18446744073709551615 - name: TERMINAL_TOTAL_DIFFICULTY#bellatrix @@ -787,8 +825,8 @@ search: TerminalTotalDifficulty\s+string regex: true spec: | - - TERMINAL_TOTAL_DIFFICULTY = 58750000000000000000000 + + TERMINAL_TOTAL_DIFFICULTY: Uint256 = 58750000000000000000000 - name: VALIDATOR_CUSTODY_REQUIREMENT#fulu @@ -797,6 +835,6 @@ search: ValidatorCustodyRequirement\s+uint64 regex: true spec: | - - VALIDATOR_CUSTODY_REQUIREMENT = 8 + + VALIDATOR_CUSTODY_REQUIREMENT: Uint64 = 8 diff --git a/specrefs/constants.yml b/specrefs/constants.yml index 6e0313904d2c..c644172b546a 100644 --- a/specrefs/constants.yml +++ b/specrefs/constants.yml @@ -1,8 +1,8 @@ - name: ATTESTATION_TIMELINESS_INDEX#gloas sources: [] spec: | - - ATTESTATION_TIMELINESS_INDEX = 0 + + ATTESTATION_TIMELINESS_INDEX: Uint64 = 0 - name: BASE_REWARDS_PER_EPOCH#phase0 @@ -11,22 +11,15 @@ search: BaseRewardsPerEpoch\s+.*yaml:"BASE_REWARDS_PER_EPOCH" regex: true spec: | - - BASE_REWARDS_PER_EPOCH: uint64 = 4 + + BASE_REWARDS_PER_EPOCH: Uint64 = 4 - name: BASIS_POINTS#phase0 sources: [] spec: | - - BASIS_POINTS: uint64 = 10000 - - -- name: BLS_MODULUS#deneb - sources: [] - spec: | - - BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 + + BASIS_POINTS: Uint64 = 10000 - name: BLS_WITHDRAWAL_PREFIX#phase0 @@ -56,8 +49,8 @@ - name: BUILDER_INDEX_FLAG#gloas sources: [] spec: | - - BUILDER_INDEX_FLAG: uint64 = 2**40 + + BUILDER_INDEX_FLAG: Uint64 = 2**40 - name: BUILDER_INDEX_SELF_BUILD#gloas @@ -70,50 +63,36 @@ - name: BUILDER_PAYMENT_THRESHOLD_DENOMINATOR#gloas sources: [] spec: | - - BUILDER_PAYMENT_THRESHOLD_DENOMINATOR: uint64 = 10 + + BUILDER_PAYMENT_THRESHOLD_DENOMINATOR: Uint64 = 10 - name: BUILDER_PAYMENT_THRESHOLD_NUMERATOR#gloas sources: [] spec: | - - BUILDER_PAYMENT_THRESHOLD_NUMERATOR: uint64 = 6 + + BUILDER_PAYMENT_THRESHOLD_NUMERATOR: Uint64 = 6 - name: BUILDER_WITHDRAWAL_PREFIX#gloas sources: [] spec: | - - BUILDER_WITHDRAWAL_PREFIX: Bytes1 = '0x03' - - -- name: BYTES_PER_COMMITMENT#deneb - sources: [] - spec: | - - BYTES_PER_COMMITMENT: uint64 = 48 + + BUILDER_WITHDRAWAL_PREFIX: Bytes1 = '0xB0' - name: BYTES_PER_FIELD_ELEMENT#deneb sources: [] spec: | - - BYTES_PER_FIELD_ELEMENT: uint64 = 32 - - -- name: BYTES_PER_PROOF#deneb - sources: [] - spec: | - - BYTES_PER_PROOF: uint64 = 48 + + BYTES_PER_FIELD_ELEMENT: Uint64 = 32 - name: COMMITTEE_WEIGHT_ESTIMATION_ADJUSTMENT_FACTOR#phase0 sources: [] spec: | - - COMMITTEE_WEIGHT_ESTIMATION_ADJUSTMENT_FACTOR: uint64 = 5 + + COMMITTEE_WEIGHT_ESTIMATION_ADJUSTMENT_FACTOR: Uint64 = 5 - name: COMPOUNDING_WITHDRAWAL_PREFIX#electra @@ -142,8 +121,8 @@ search: DepositContractTreeDepth\s+.*yaml:"DEPOSIT_CONTRACT_TREE_DEPTH" regex: true spec: | - - DEPOSIT_CONTRACT_TREE_DEPTH: uint64 = 2**5 + + DEPOSIT_CONTRACT_TREE_DEPTH: Uint64 = 2**5 - name: DEPOSIT_REQUEST_TYPE#electra @@ -344,8 +323,8 @@ search: GweiPerEth\s+uint64 regex: true spec: | - - ETH_TO_GWEI: uint64 = 10**9 + + ETH_TO_GWEI: Uint64 = 10**9 - name: FAR_FUTURE_EPOCH#phase0 @@ -358,28 +337,14 @@ FAR_FUTURE_EPOCH: Epoch = 2**64 - 1 -- name: FIAT_SHAMIR_PROTOCOL_DOMAIN#deneb - sources: [] - spec: | - - FIAT_SHAMIR_PROTOCOL_DOMAIN = b'FSBLOBVERIFY_V1_' - - - name: FULL_EXIT_REQUEST_AMOUNT#electra sources: - file: config/params/config.go search: FullExitRequestAmount\s+.*yaml:"FULL_EXIT_REQUEST_AMOUNT" regex: true spec: | - - FULL_EXIT_REQUEST_AMOUNT: uint64 = 0 - - -- name: G1_POINT_AT_INFINITY#deneb - sources: [] - spec: | - - G1_POINT_AT_INFINITY: Bytes48 = b'\xc0' + b'\x00' * 47 + + FULL_EXIT_REQUEST_AMOUNT: Gwei = 0 - name: G2_POINT_AT_INFINITY#altair @@ -418,36 +383,15 @@ search: JustificationBitsLength\s+.*yaml:"JUSTIFICATION_BITS_LENGTH" regex: true spec: | - - JUSTIFICATION_BITS_LENGTH: uint64 = 4 - - -- name: KZG_ENDIANNESS#deneb - sources: [] - spec: | - - KZG_ENDIANNESS = 'big' - - -- name: KZG_SETUP_G2_LENGTH#deneb - sources: [] - spec: | - - KZG_SETUP_G2_LENGTH = 65 - - -- name: KZG_SETUP_G2_MONOMIAL#deneb - sources: [] - spec: | - - KZG_SETUP_G2_MONOMIAL: Vector[G2Point, KZG_SETUP_G2_LENGTH] = ['0x93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8', '0xb5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2', '0xb5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc', '0xb3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874', '0x954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280', '0x88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487', '0x85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0', '0x80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4', '0xb7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7', '0xac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686', '0x90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6', '0xa8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533', '0x8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda', '0x8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710', '0x8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081', '0xb9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3', '0x9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7', '0x91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46', '0xa9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d', '0xa9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7', '0xa4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc', '0x89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e', '0x9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283', '0x9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199', '0xb212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05', '0x925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974', '0x9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc', '0x935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742', '0xa5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557', '0x935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a', '0x9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6', '0x840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76', '0x92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd', '0x8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4', '0xb0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da', '0x9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2', '0xb373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b', '0xb15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e', '0x8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075', '0xa6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044', '0x8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67', '0x821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df', '0x8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493', '0xa32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468', '0xa040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96', '0x864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf', '0x95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3', '0xa2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774', '0xb145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca', '0xadabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0', '0xae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5', '0x9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b', '0xa9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50', '0x84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04', '0xa1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386', '0x92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1', '0xa525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717', '0x98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b', '0xa9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e', '0xb221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc', '0xa71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef', '0xb990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220', '0x8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db', '0xa92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c', '0x92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10'] + + JUSTIFICATION_BITS_LENGTH: Uint64 = 4 - name: MAX_CONCURRENT_REQUESTS#phase0 sources: [] spec: | - - MAX_CONCURRENT_REQUESTS = 2 + + MAX_CONCURRENT_REQUESTS: Uint64 = 2 - name: MAX_REQUEST_LIGHT_CLIENT_UPDATES#altair @@ -456,8 +400,8 @@ search: MaxRequestLightClientUpdates\s+.*yaml:"MAX_REQUEST_LIGHT_CLIENT_UPDATES" regex: true spec: | - - MAX_REQUEST_LIGHT_CLIENT_UPDATES = 2**7 + + MAX_REQUEST_LIGHT_CLIENT_UPDATES: Uint64 = 2**7 - name: NODE_ID_BITS#phase0 @@ -466,15 +410,15 @@ search: NodeIdBits\s+.*yaml:"NODE_ID_BITS" regex: true spec: | - - NODE_ID_BITS = 256 + + NODE_ID_BITS: Uint64 = 256 - name: NUM_BLOCK_TIMELINESS_DEADLINES#gloas sources: [] spec: | - - NUM_BLOCK_TIMELINESS_DEADLINES = 2 + + NUM_BLOCK_TIMELINESS_DEADLINES: Uint64 = 2 - name: PARTICIPATION_FLAG_WEIGHTS#altair @@ -487,8 +431,8 @@ - name: PAYLOAD_BUILDER_VERSION#gloas sources: [] spec: | - - PAYLOAD_BUILDER_VERSION: uint8 = 0 + + PAYLOAD_BUILDER_VERSION: Uint8 = 0 - name: PAYLOAD_STATUS_EMPTY#gloas @@ -533,42 +477,21 @@ PAYLOAD_STATUS_VALID: PayloadValidationStatus = 0 -- name: PRIMITIVE_ROOT_OF_UNITY#deneb - sources: [] - spec: | - - PRIMITIVE_ROOT_OF_UNITY = 7 - - - name: PROPOSER_WEIGHT#altair sources: - file: config/params/config.go search: ProposerWeight\s+.*yaml:"PROPOSER_WEIGHT" regex: true spec: | - - PROPOSER_WEIGHT: uint64 = 8 + + PROPOSER_WEIGHT: Uint64 = 8 - name: PTC_TIMELINESS_INDEX#gloas sources: [] spec: | - - PTC_TIMELINESS_INDEX = 1 - - -- name: RANDOM_CHALLENGE_KZG_BATCH_DOMAIN#deneb - sources: [] - spec: | - - RANDOM_CHALLENGE_KZG_BATCH_DOMAIN = b'RCKZGBATCH___V1_' - - -- name: RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN#fulu - sources: [] - spec: | - - RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN = b'RCKZGCBATCH__V1_' + + PTC_TIMELINESS_INDEX: Uint64 = 1 - name: SAFETY_DECAY#phase0 @@ -577,15 +500,15 @@ search: SafetyDecay\s+uint64 regex: true spec: | - - SAFETY_DECAY: uint64 = 10 + + SAFETY_DECAY: Uint64 = 10 - name: SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY#bellatrix sources: [] spec: | - - SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY = 128 + + SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY: Slot = 128 - name: SYNC_COMMITTEE_SUBNET_COUNT#altair @@ -594,8 +517,8 @@ search: SyncCommitteeSubnetCount\s+.*yaml:"SYNC_COMMITTEE_SUBNET_COUNT" regex: true spec: | - - SYNC_COMMITTEE_SUBNET_COUNT = 4 + + SYNC_COMMITTEE_SUBNET_COUNT: Uint64 = 2**2 - name: SYNC_REWARD_WEIGHT#altair @@ -604,8 +527,8 @@ search: SyncRewardWeight\s+.*yaml:"SYNC_REWARD_WEIGHT" regex: true spec: | - - SYNC_REWARD_WEIGHT: uint64 = 2 + + SYNC_REWARD_WEIGHT: Uint64 = 2 - name: TARGET_AGGREGATORS_PER_COMMITTEE#phase0 @@ -614,8 +537,8 @@ search: TargetAggregatorsPerCommittee\s+.*yaml:"TARGET_AGGREGATORS_PER_COMMITTEE" regex: true spec: | - - TARGET_AGGREGATORS_PER_COMMITTEE = 2**4 + + TARGET_AGGREGATORS_PER_COMMITTEE: Uint64 = 2**4 - name: TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE#altair @@ -624,8 +547,8 @@ search: TargetAggregatorsPerSyncSubcommittee\s+.*yaml:"TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE" regex: true spec: | - - TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE = 2**4 + + TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE: Uint64 = 2**4 - name: TIMELY_HEAD_FLAG_INDEX#altair @@ -634,8 +557,8 @@ search: TimelyHeadFlagIndex\s+.*yaml:"TIMELY_HEAD_FLAG_INDEX" regex: true spec: | - - TIMELY_HEAD_FLAG_INDEX = 2 + + TIMELY_HEAD_FLAG_INDEX: Uint64 = 2 - name: TIMELY_HEAD_WEIGHT#altair @@ -644,8 +567,8 @@ search: TimelyHeadWeight\s+.*yaml:"TIMELY_HEAD_WEIGHT" regex: true spec: | - - TIMELY_HEAD_WEIGHT: uint64 = 14 + + TIMELY_HEAD_WEIGHT: Uint64 = 14 - name: TIMELY_SOURCE_FLAG_INDEX#altair @@ -654,8 +577,8 @@ search: TimelySourceFlagIndex\s+.*yaml:"TIMELY_SOURCE_FLAG_INDEX" regex: true spec: | - - TIMELY_SOURCE_FLAG_INDEX = 0 + + TIMELY_SOURCE_FLAG_INDEX: Uint64 = 0 - name: TIMELY_SOURCE_WEIGHT#altair @@ -664,8 +587,8 @@ search: TimelySourceWeight\s+.*yaml:"TIMELY_SOURCE_WEIGHT" regex: true spec: | - - TIMELY_SOURCE_WEIGHT: uint64 = 14 + + TIMELY_SOURCE_WEIGHT: Uint64 = 14 - name: TIMELY_TARGET_FLAG_INDEX#altair @@ -674,8 +597,8 @@ search: TimelyTargetFlagIndex\s+.*yaml:"TIMELY_TARGET_FLAG_INDEX" regex: true spec: | - - TIMELY_TARGET_FLAG_INDEX = 1 + + TIMELY_TARGET_FLAG_INDEX: Uint64 = 1 - name: TIMELY_TARGET_WEIGHT#altair @@ -684,29 +607,29 @@ search: TimelyTargetWeight\s+.*yaml:"TIMELY_TARGET_WEIGHT" regex: true spec: | - - TIMELY_TARGET_WEIGHT: uint64 = 26 + + TIMELY_TARGET_WEIGHT: Uint64 = 26 - name: UINT256_MAX#fulu sources: [] spec: | - - UINT256_MAX: uint256 = 2**256 - 1 + + UINT256_MAX: Uint256 = 2**256 - 1 - name: UINT64_MAX#phase0 sources: [] spec: | - - UINT64_MAX: uint64 = 2**64 - 1 + + UINT64_MAX: Uint64 = 2**64 - 1 - name: UINT64_MAX_SQRT#phase0 sources: [] spec: | - - UINT64_MAX_SQRT: uint64 = 4294967295 + + UINT64_MAX_SQRT: Uint64 = 4294967295 - name: UNSET_DEPOSIT_REQUESTS_START_INDEX#electra @@ -715,8 +638,8 @@ search: UnsetDepositRequestsStartIndex\s+.*yaml:"UNSET_DEPOSIT_REQUESTS_START_INDEX" regex: true spec: | - - UNSET_DEPOSIT_REQUESTS_START_INDEX: uint64 = 2**64 - 1 + + UNSET_DEPOSIT_REQUESTS_START_INDEX: Uint64 = 2**64 - 1 - name: VERSIONED_HASH_VERSION_KZG#deneb @@ -735,8 +658,8 @@ search: WeightDenominator\s+.*yaml:"WEIGHT_DENOMINATOR" regex: true spec: | - - WEIGHT_DENOMINATOR: uint64 = 64 + + WEIGHT_DENOMINATOR: Uint64 = 64 - name: WITHDRAWAL_REQUEST_TYPE#electra diff --git a/specrefs/containers.yml b/specrefs/containers.yml index 66b57ec341f5..6e03060924f5 100644 --- a/specrefs/containers.yml +++ b/specrefs/containers.yml @@ -23,14 +23,47 @@ selection_proof: BLSSignature +- name: AggregationBits#phase0 + sources: [] + spec: | + + class AggregationBits(BitList[MAX_VALIDATORS_PER_COMMITTEE]): + """ + The participation bits of a single committee, one bit per member in + committee order. + """ + + +- name: AggregationBits#electra + sources: [] + spec: | + + class AggregationBits(BitList[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT]): # type: ignore + """ + The participation bits of all committees participating in an attestation, + concatenated in committee order. + """ + + +- name: AggregationBits#gloas + sources: [] + spec: | + + class AggregationBits(ProgressiveBitList): + """ + The participation bits of all committees participating in an attestation, + concatenated in committee order. + """ + + - name: Attestation#phase0 sources: - file: proto/prysm/v1alpha1/attestation.proto search: message Attestation { spec: | - + class Attestation(Container): - aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE] + aggregation_bits: AggregationBits data: AttestationData signature: BLSSignature @@ -40,14 +73,27 @@ - file: proto/prysm/v1alpha1/attestation.proto search: message AttestationElectra { spec: | - + class Attestation(Container): # [Modified in Electra:EIP7549] - aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] + aggregation_bits: AggregationBits data: AttestationData signature: BLSSignature # [New in Electra:EIP7549] - committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT] + committee_bits: CommitteeBits + + +- name: Attestation#gloas + sources: + - file: proto/prysm/v1alpha1/attestation.proto + search: message AttestationGloas { + spec: | + + class Attestation(ProgressiveContainer(active_fields=[1] * 4)): # type: ignore + aggregation_bits: AggregationBits + data: AttestationData + signature: BLSSignature + committee_bits: CommitteeBits - name: AttestationData#phase0 @@ -64,6 +110,36 @@ target: Checkpoint +- name: Attestations#phase0 + sources: [] + spec: | + + class Attestations(List[Attestation, MAX_ATTESTATIONS]): + """ + The attestations included in a beacon block. + """ + + +- name: Attestations#electra + sources: [] + spec: | + + class Attestations(List[Attestation, MAX_ATTESTATIONS_ELECTRA]): + """ + The attestations included in a beacon block. + """ + + +- name: Attestations#gloas + sources: [] + spec: | + + class Attestations(ProgressiveList[Attestation]): + """ + The attestations included in a beacon block. + """ + + - name: AttesterSlashing#phase0 sources: - file: proto/eth/v1/beacon_block.proto @@ -88,6 +164,78 @@ attestation_2: IndexedAttestation +- name: AttesterSlashings#phase0 + sources: [] + spec: | + + class AttesterSlashings(List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]): + """ + The attester slashings included in a beacon block. + """ + + +- name: AttesterSlashings#electra + sources: [] + spec: | + + class AttesterSlashings(List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA]): + """ + The attester slashings included in a beacon block. + """ + + +- name: AttesterSlashings#gloas + sources: [] + spec: | + + class AttesterSlashings(ProgressiveList[AttesterSlashing]): + """ + The attester slashings included in a beacon block. + """ + + +- name: AttestingIndices#phase0 + sources: [] + spec: | + + class AttestingIndices(List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]): + """ + The indices of the validators participating in an attestation. + """ + + +- name: AttestingIndices#electra + sources: [] + spec: | + + class AttestingIndices( + List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] # type: ignore + ): + """ + The indices of the validators participating in an attestation. + """ + + +- name: AttestingIndices#gloas + sources: [] + spec: | + + class AttestingIndices(ProgressiveList[ValidatorIndex]): + """ + The indices of the validators participating in an attestation. + """ + + +- name: Attnets#phase0 + sources: [] + spec: | + + class Attnets(BitVector[ATTESTATION_SUBNET_COUNT]): # type: ignore + """ + The attestation subnets a node is subscribed to, one bit per subnet. + """ + + - name: BLSToExecutionChange#capella sources: - file: proto/prysm/v1alpha1/withdrawals.proto @@ -100,6 +248,48 @@ to_execution_address: ExecutionAddress +- name: BLSToExecutionChanges#capella + sources: [] + spec: | + + class BLSToExecutionChanges(List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]): + """ + The signed BLS-to-execution credential changes included in a beacon + block. + """ + + +- name: BLSToExecutionChanges#gloas + sources: [] + spec: | + + class BLSToExecutionChanges(ProgressiveList[SignedBLSToExecutionChange]): + """ + The signed BLS-to-execution credential changes included in a beacon + block. + """ + + +- name: Balances#phase0 + sources: [] + spec: | + + class Balances(List[Gwei, VALIDATOR_REGISTRY_LIMIT]): + """ + The balances of all validators. + """ + + +- name: Balances#gloas + sources: [] + spec: | + + class Balances(ProgressiveList[Gwei]): + """ + The balances of all validators. + """ + + - name: BeaconBlock#phase0 sources: - file: proto/eth/v1/beacon_block.proto @@ -119,16 +309,16 @@ - file: proto/eth/v1/beacon_block.proto search: message BeaconBlockBody { spec: | - + class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] - attestations: List[Attestation, MAX_ATTESTATIONS] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + proposer_slashings: ProposerSlashings + attester_slashings: AttesterSlashings + attestations: Attestations + deposits: Deposits + voluntary_exits: VoluntaryExits - name: BeaconBlockBody#altair @@ -136,16 +326,16 @@ - file: proto/prysm/v1alpha1/beacon_block.proto search: message BeaconBlockBodyAltair { spec: | - + class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] - attestations: List[Attestation, MAX_ATTESTATIONS] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + proposer_slashings: ProposerSlashings + attester_slashings: AttesterSlashings + attestations: Attestations + deposits: Deposits + voluntary_exits: VoluntaryExits # [New in Altair] sync_aggregate: SyncAggregate @@ -155,16 +345,16 @@ - file: proto/prysm/v1alpha1/beacon_block.proto search: message BeaconBlockBodyBellatrix { spec: | - + class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] - attestations: List[Attestation, MAX_ATTESTATIONS] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + proposer_slashings: ProposerSlashings + attester_slashings: AttesterSlashings + attestations: Attestations + deposits: Deposits + voluntary_exits: VoluntaryExits sync_aggregate: SyncAggregate # [New in Bellatrix] execution_payload: ExecutionPayload @@ -175,20 +365,20 @@ - file: proto/prysm/v1alpha1/beacon_block.proto search: message BeaconBlockBodyCapella { spec: | - + class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] - attestations: List[Attestation, MAX_ATTESTATIONS] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + proposer_slashings: ProposerSlashings + attester_slashings: AttesterSlashings + attestations: Attestations + deposits: Deposits + voluntary_exits: VoluntaryExits sync_aggregate: SyncAggregate execution_payload: ExecutionPayload # [New in Capella] - bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] + bls_to_execution_changes: BLSToExecutionChanges - name: BeaconBlockBody#deneb @@ -196,22 +386,22 @@ - file: proto/prysm/v1alpha1/beacon_block.proto search: message BeaconBlockBodyDeneb { spec: | - + class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] - attestations: List[Attestation, MAX_ATTESTATIONS] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + proposer_slashings: ProposerSlashings + attester_slashings: AttesterSlashings + attestations: Attestations + deposits: Deposits + voluntary_exits: VoluntaryExits sync_aggregate: SyncAggregate # [Modified in Deneb:EIP4844] execution_payload: ExecutionPayload - bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] + bls_to_execution_changes: BLSToExecutionChanges # [New in Deneb:EIP4844] - blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + blob_kzg_commitments: BlobKZGCommitments - name: BeaconBlockBody#electra @@ -219,22 +409,22 @@ - file: proto/prysm/v1alpha1/beacon_block.proto search: message BeaconBlockBodyElectra { spec: | - + class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + proposer_slashings: ProposerSlashings # [Modified in Electra:EIP7549] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA] + attester_slashings: AttesterSlashings # [Modified in Electra:EIP7549] - attestations: List[Attestation, MAX_ATTESTATIONS_ELECTRA] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + attestations: Attestations + deposits: Deposits + voluntary_exits: VoluntaryExits sync_aggregate: SyncAggregate execution_payload: ExecutionPayload - bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] - blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + bls_to_execution_changes: BLSToExecutionChanges + blob_kzg_commitments: BlobKZGCommitments # [New in Electra] execution_requests: ExecutionRequests @@ -242,20 +432,26 @@ - name: BeaconBlockBody#gloas sources: [] spec: | - - class BeaconBlockBody(Container): + + class BeaconBlockBody(ProgressiveContainer(active_fields=[1] * 13)): # type: ignore randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] - attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA] - attestations: List[Attestation, MAX_ATTESTATIONS_ELECTRA] - deposits: List[Deposit, MAX_DEPOSITS] - voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + # [Modified in Gloas:EIP7688] + proposer_slashings: ProposerSlashings + # [Modified in Gloas:EIP7688] + attester_slashings: AttesterSlashings + # [Modified in Gloas:EIP7688] + attestations: Attestations + # [Modified in Gloas:EIP7688] + deposits: Deposits + # [Modified in Gloas:EIP7688] + voluntary_exits: VoluntaryExits sync_aggregate: SyncAggregate # [Modified in Gloas:EIP7732] # Removed `execution_payload` - bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] + # [Modified in Gloas:EIP7688] + bls_to_execution_changes: BLSToExecutionChanges # [Modified in Gloas:EIP7732] # Removed `blob_kzg_commitments` # [Modified in Gloas:EIP7732] @@ -263,7 +459,7 @@ # [New in Gloas:EIP7732] signed_execution_payload_bid: SignedExecutionPayloadBid # [New in Gloas:EIP7732] - payload_attestations: List[PayloadAttestation, MAX_PAYLOAD_ATTESTATIONS] + payload_attestations: PayloadAttestations # [New in Gloas:EIP7732] parent_execution_requests: ExecutionRequests @@ -282,31 +478,51 @@ body_root: Root +- name: BeaconBlockRoots#phase0 + sources: [] + spec: | + + class BeaconBlockRoots(List[Root, MAX_REQUEST_BLOCKS]): # type: ignore + """ + Beacon block roots requested in a ``BeaconBlocksByRoot`` request. + """ + + +- name: BeaconBlockRoots#deneb + sources: [] + spec: | + + class BeaconBlockRoots(List[Root, MAX_REQUEST_BLOCKS_DENEB]): # type: ignore + """ + Beacon block roots requested in a ``BeaconBlocksByRoot`` request. + """ + + - name: BeaconState#phase0 sources: - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconState { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH] - current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_attestations: PendingAttestations + current_epoch_attestations: PendingAttestations + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint @@ -317,33 +533,33 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconStateAltair { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings # [Modified in Altair] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] + previous_epoch_participation: EpochParticipation # [Modified in Altair] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint # [New in Altair] - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores # [New in Altair] current_sync_committee: SyncCommittee # [New in Altair] @@ -355,30 +571,30 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconStateBellatrix { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee # [New in Bellatrix] @@ -390,30 +606,30 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconStateCapella { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee # [Modified in Capella] @@ -423,7 +639,7 @@ # [New in Capella] next_withdrawal_validator_index: ValidatorIndex # [New in Capella] - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] + historical_summaries: HistoricalSummaries - name: BeaconState#deneb @@ -431,37 +647,37 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconStateDeneb { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee # [Modified in Deneb:EIP4844] latest_execution_payload_header: ExecutionPayloadHeader next_withdrawal_index: WithdrawalIndex next_withdrawal_validator_index: ValidatorIndex - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] + historical_summaries: HistoricalSummaries - name: BeaconState#electra @@ -469,38 +685,38 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconStateElectra { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee latest_execution_payload_header: ExecutionPayloadHeader next_withdrawal_index: WithdrawalIndex next_withdrawal_validator_index: ValidatorIndex - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] + historical_summaries: HistoricalSummaries # [New in Electra:EIP6110] - deposit_requests_start_index: uint64 + deposit_requests_start_index: Uint64 # [New in Electra:EIP7251] deposit_balance_to_consume: Gwei # [New in Electra:EIP7251] @@ -512,11 +728,11 @@ # [New in Electra:EIP7251] earliest_consolidation_epoch: Epoch # [New in Electra:EIP7251] - pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT] + pending_deposits: PendingDeposits # [New in Electra:EIP7251] - pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] + pending_partial_withdrawals: PendingPartialWithdrawals # [New in Electra:EIP7251] - pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] + pending_consolidations: PendingConsolidations - name: BeaconState#fulu @@ -524,76 +740,81 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message BeaconStateFulu { spec: | - + class BeaconState(Container): - genesis_time: uint64 + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee latest_execution_payload_header: ExecutionPayloadHeader next_withdrawal_index: WithdrawalIndex next_withdrawal_validator_index: ValidatorIndex - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] - deposit_requests_start_index: uint64 + historical_summaries: HistoricalSummaries + deposit_requests_start_index: Uint64 deposit_balance_to_consume: Gwei exit_balance_to_consume: Gwei earliest_exit_epoch: Epoch consolidation_balance_to_consume: Gwei earliest_consolidation_epoch: Epoch - pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT] - pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] - pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] + pending_deposits: PendingDeposits + pending_partial_withdrawals: PendingPartialWithdrawals + pending_consolidations: PendingConsolidations # [New in Fulu:EIP7917] - proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH] + proposer_lookahead: ProposerLookahead - name: BeaconState#gloas sources: [] spec: | - - class BeaconState(Container): - genesis_time: uint64 + + class BeaconState(ProgressiveContainer(active_fields=[1] * 46)): # type: ignore + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + # [Modified in Gloas:EIP7688] + validators: Validators + # [Modified in Gloas:EIP7688] + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + # [Modified in Gloas:EIP7688] + previous_epoch_participation: EpochParticipation + # [Modified in Gloas:EIP7688] + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + # [Modified in Gloas:EIP7688] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee # [Modified in Gloas:EIP7732] @@ -602,161 +823,154 @@ latest_block_hash: Hash32 next_withdrawal_index: WithdrawalIndex next_withdrawal_validator_index: ValidatorIndex - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] - deposit_requests_start_index: uint64 + historical_summaries: HistoricalSummaries + deposit_requests_start_index: Uint64 deposit_balance_to_consume: Gwei exit_balance_to_consume: Gwei earliest_exit_epoch: Epoch consolidation_balance_to_consume: Gwei earliest_consolidation_epoch: Epoch - pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT] - pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] - pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] - proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH] + # [Modified in Gloas:EIP7688] + pending_deposits: PendingDeposits + # [Modified in Gloas:EIP7688] + pending_partial_withdrawals: PendingPartialWithdrawals + # [Modified in Gloas:EIP7688] + pending_consolidations: PendingConsolidations + proposer_lookahead: ProposerLookahead # [New in Gloas:EIP7732] - builders: List[Builder, BUILDER_REGISTRY_LIMIT] + builders: Builders # [New in Gloas:EIP7732] next_withdrawal_builder_index: BuilderIndex # [New in Gloas:EIP7732] - execution_payload_availability: Bitvector[SLOTS_PER_HISTORICAL_ROOT] + execution_payload_availability: ExecutionPayloadAvailability # [New in Gloas:EIP7732] - builder_pending_payments: Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH] + builder_pending_payments: BuilderPendingPayments # [New in Gloas:EIP7732] - builder_pending_withdrawals: List[BuilderPendingWithdrawal, BUILDER_PENDING_WITHDRAWALS_LIMIT] + builder_pending_withdrawals: BuilderPendingWithdrawals # [New in Gloas:EIP7732] latest_execution_payload_bid: ExecutionPayloadBid # [New in Gloas:EIP7732] - payload_expected_withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] + payload_expected_withdrawals: Withdrawals # [New in Gloas:EIP7732] - ptc_window: Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] + ptc_window: PTCWindow - name: BeaconState#heze sources: [] spec: | - - class BeaconState(Container): - genesis_time: uint64 + + class BeaconState(ProgressiveContainer(active_fields=[1] * 46)): # type: ignore + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee - # [Modified in Gloas:EIP7732] - # Removed `latest_execution_payload_header` - # [New in Gloas:EIP7732] latest_block_hash: Hash32 next_withdrawal_index: WithdrawalIndex next_withdrawal_validator_index: ValidatorIndex - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] - deposit_requests_start_index: uint64 + historical_summaries: HistoricalSummaries + deposit_requests_start_index: Uint64 deposit_balance_to_consume: Gwei exit_balance_to_consume: Gwei earliest_exit_epoch: Epoch consolidation_balance_to_consume: Gwei earliest_consolidation_epoch: Epoch - pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT] - pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] - pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] - proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH] - # [New in Gloas:EIP7732] - builders: List[Builder, BUILDER_REGISTRY_LIMIT] - # [New in Gloas:EIP7732] + pending_deposits: PendingDeposits + pending_partial_withdrawals: PendingPartialWithdrawals + pending_consolidations: PendingConsolidations + proposer_lookahead: ProposerLookahead + builders: Builders next_withdrawal_builder_index: BuilderIndex - # [New in Gloas:EIP7732] - execution_payload_availability: Bitvector[SLOTS_PER_HISTORICAL_ROOT] - # [New in Gloas:EIP7732] - builder_pending_payments: Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH] - # [New in Gloas:EIP7732] - builder_pending_withdrawals: List[BuilderPendingWithdrawal, BUILDER_PENDING_WITHDRAWALS_LIMIT] - # [New in Gloas:EIP7732] + execution_payload_availability: ExecutionPayloadAvailability + builder_pending_payments: BuilderPendingPayments + builder_pending_withdrawals: BuilderPendingWithdrawals + # [Modified in Heze:EIP7805] latest_execution_payload_bid: ExecutionPayloadBid - # [New in Gloas:EIP7732] - payload_expected_withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - # [New in Gloas:EIP7732] - ptc_window: Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] + payload_expected_withdrawals: Withdrawals + ptc_window: PTCWindow - name: BeaconState#heze sources: [] spec: | - - class BeaconState(Container): - genesis_time: uint64 + + class BeaconState(ProgressiveContainer(active_fields=[1] * 46)): # type: ignore + genesis_time: Uint64 genesis_validators_root: Root slot: Slot fork: Fork latest_block_header: BeaconBlockHeader - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + block_roots: BlockRoots + state_roots: StateRoots + historical_roots: HistoricalRoots eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] - eth1_deposit_index: uint64 - validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] - randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR] - slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] - previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] - justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] + eth1_data_votes: Eth1DataVotes + eth1_deposit_index: Uint64 + validators: Validators + balances: Balances + randao_mixes: RandaoMixes + slashings: Slashings + previous_epoch_participation: EpochParticipation + current_epoch_participation: EpochParticipation + justification_bits: JustificationBits previous_justified_checkpoint: Checkpoint current_justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT] + inactivity_scores: InactivityScores current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee - # [Modified in Gloas:EIP7732] - # Removed `latest_execution_payload_header` - # [New in Gloas:EIP7732] latest_block_hash: Hash32 next_withdrawal_index: WithdrawalIndex next_withdrawal_validator_index: ValidatorIndex - historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] - deposit_requests_start_index: uint64 + historical_summaries: HistoricalSummaries + deposit_requests_start_index: Uint64 deposit_balance_to_consume: Gwei exit_balance_to_consume: Gwei earliest_exit_epoch: Epoch consolidation_balance_to_consume: Gwei earliest_consolidation_epoch: Epoch - pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT] - pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] - pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] - proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH] - # [New in Gloas:EIP7732] - builders: List[Builder, BUILDER_REGISTRY_LIMIT] - # [New in Gloas:EIP7732] + pending_deposits: PendingDeposits + pending_partial_withdrawals: PendingPartialWithdrawals + pending_consolidations: PendingConsolidations + proposer_lookahead: ProposerLookahead + builders: Builders next_withdrawal_builder_index: BuilderIndex - # [New in Gloas:EIP7732] - execution_payload_availability: Bitvector[SLOTS_PER_HISTORICAL_ROOT] - # [New in Gloas:EIP7732] - builder_pending_payments: Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH] - # [New in Gloas:EIP7732] - builder_pending_withdrawals: List[BuilderPendingWithdrawal, BUILDER_PENDING_WITHDRAWALS_LIMIT] - # [New in Gloas:EIP7732] + execution_payload_availability: ExecutionPayloadAvailability + builder_pending_payments: BuilderPendingPayments + builder_pending_withdrawals: BuilderPendingWithdrawals + # [Modified in Heze:EIP7805] latest_execution_payload_bid: ExecutionPayloadBid - # [New in Gloas:EIP7732] - payload_expected_withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - # [New in Gloas:EIP7732] - ptc_window: Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] + payload_expected_withdrawals: Withdrawals + ptc_window: PTCWindow + + +- name: Blob#deneb + sources: [] + spec: | + + class Blob(ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]): # type: ignore + """ + A blob of data, encoded as a sequence of BLS scalar field elements. + """ - name: BlobIdentifier#deneb @@ -770,28 +984,79 @@ index: BlobIndex +- name: BlobKZGCommitments#deneb + sources: [] + spec: | + + class BlobKZGCommitments(List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]): + """ + The KZG commitments to the blobs of a beacon block. + """ + + +- name: BlobKZGCommitments#gloas + sources: [] + spec: | + + class BlobKZGCommitments(ProgressiveList[KZGCommitment]): + """ + The KZG commitments to the blobs of a beacon block. + """ + + - name: BlobSidecar#deneb sources: - file: proto/prysm/v1alpha1/beacon_block.proto search: message BlobSidecar { spec: | - + class BlobSidecar(Container): index: BlobIndex blob: Blob kzg_commitment: KZGCommitment kzg_proof: KZGProof signed_block_header: SignedBeaconBlockHeader - kzg_commitment_inclusion_proof: Vector[Bytes32, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH] + kzg_commitment_inclusion_proof: KZGCommitmentInclusionProof + + +- name: Blobs#deneb + sources: [] + spec: | + + class Blobs(List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK]): + """ + The blobs of a single beacon block. + """ + + +- name: BlockAccessList#gloas + sources: [] + spec: | + + class BlockAccessList(ProgressiveByteList): + """ + The serialized block access list of an execution payload. + """ + + +- name: BlockRoots#phase0 + sources: [] + spec: | + + class BlockRoots(Vector[Root, SLOTS_PER_HISTORICAL_ROOT]): + """ + A rolling window of recent block roots, indexed by slot modulo + ``SLOTS_PER_HISTORICAL_ROOT``. + """ - name: Builder#gloas sources: [] spec: | - + class Builder(Container): pubkey: BLSPubkey - version: uint8 + version: Uint8 execution_address: ExecutionAddress balance: Gwei deposit_epoch: Epoch @@ -809,6 +1074,16 @@ signature: BLSSignature +- name: BuilderDepositRequests#gloas + sources: [] + spec: | + + class BuilderDepositRequests(ProgressiveList[BuilderDepositRequest]): + """ + The builder deposit requests pertaining to a single execution payload. + """ + + - name: BuilderExitRequest#gloas sources: [] spec: | @@ -818,6 +1093,16 @@ pubkey: BLSPubkey +- name: BuilderExitRequests#gloas + sources: [] + spec: | + + class BuilderExitRequests(ProgressiveList[BuilderExitRequest]): + """ + The builder exit requests pertaining to a single execution payload. + """ + + - name: BuilderPendingPayment#gloas sources: [] spec: | @@ -828,6 +1113,16 @@ proposer_index: ValidatorIndex +- name: BuilderPendingPayments#gloas + sources: [] + spec: | + + class BuilderPendingPayments(Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH]): # type: ignore + """ + The pending builder payments of the previous and current epoch. + """ + + - name: BuilderPendingWithdrawal#gloas sources: [] spec: | @@ -838,6 +1133,76 @@ builder_index: BuilderIndex +- name: BuilderPendingWithdrawals#gloas + sources: [] + spec: | + + class BuilderPendingWithdrawals(ProgressiveList[BuilderPendingWithdrawal]): + """ + The queue of builder withdrawals awaiting processing. + """ + + +- name: Builders#gloas + sources: [] + spec: | + + class Builders(ProgressiveList[Builder]): + """ + The builder registry. + """ + + +- name: Cell#fulu + sources: [] + spec: | + + class Cell(ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_CELL]): # type: ignore + """ + The unit of extended blob data that has its own ``KZGProof``. + """ + + +- name: CellKZGProofs#fulu + sources: [] + spec: | + + class CellKZGProofs(List[KZGProof, FIELD_ELEMENTS_PER_EXT_BLOB * MAX_BLOB_COMMITMENTS_PER_BLOCK]): # type: ignore + """ + The KZG cell proofs for every blob in a block, one proof per cell. + """ + + +- name: Cells#fulu + sources: [] + spec: | + + class Cells(Vector[Cell, CELLS_PER_EXT_BLOB]): + """ + The cells of a single extended blob. + """ + + +- name: CellsBitList#fulu + sources: [] + spec: | + + class CellsBitList(BitList[MAX_BLOB_COMMITMENTS_PER_BLOCK]): + """ + A bitfield over the cells of a column, one bit per blob. + """ + + +- name: CellsBitList#gloas + sources: [] + spec: | + + class CellsBitList(ProgressiveBitList): + """ + A bitfield over the cells of a column, one bit per blob. + """ + + - name: Checkpoint#phase0 sources: - file: proto/eth/v1/attestation.proto @@ -849,6 +1214,16 @@ root: Root +- name: CommitteeBits#electra + sources: [] + spec: | + + class CommitteeBits(BitVector[MAX_COMMITTEES_PER_SLOT]): + """ + Bits marking which committees of a slot participate in an attestation. + """ + + - name: ConsolidationRequest#electra sources: - file: proto/engine/v1/electra.proto @@ -861,6 +1236,26 @@ target_pubkey: BLSPubkey +- name: ConsolidationRequests#electra + sources: [] + spec: | + + class ConsolidationRequests(List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD]): + """ + The consolidation requests pertaining to a single execution payload. + """ + + +- name: ConsolidationRequests#gloas + sources: [] + spec: | + + class ConsolidationRequests(ProgressiveList[ConsolidationRequest]): + """ + The consolidation requests pertaining to a single execution payload. + """ + + - name: ContributionAndProof#altair sources: - file: proto/prysm/v1alpha1/sync_committee.proto @@ -873,31 +1268,103 @@ selection_proof: BLSSignature +- name: CurrentSyncCommitteeBranch#altair + sources: [] + spec: | + + class CurrentSyncCommitteeBranch(Vector[Bytes32, floorlog2(CURRENT_SYNC_COMMITTEE_GINDEX)]): # type: ignore + """ + A Merkle branch proving ``current_sync_committee`` within ``BeaconState``. + """ + + +- name: CurrentSyncCommitteeBranch#electra + sources: [] + spec: | + + class CurrentSyncCommitteeBranch(Vector[Bytes32, floorlog2(CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA)]): # type: ignore + """ + A Merkle branch proving ``current_sync_committee`` within ``BeaconState``. + """ + + +- name: CurrentSyncCommitteeBranch#gloas + sources: [] + spec: | + + class CurrentSyncCommitteeBranch(Vector[Bytes32, floorlog2(CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS)]): # type: ignore + """ + A Merkle branch proving ``current_sync_committee`` within ``BeaconState``. + """ + + +- name: CustodyColumnBits#gloas + sources: [] + spec: | + + class CustodyColumnBits(BitVector[NUMBER_OF_COLUMNS]): + """ + Bits marking the data columns custodied by a node, one bit per column. + """ + + +- name: DataColumn#fulu + sources: [] + spec: | + + class DataColumn(List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK]): + """ + A column of the extended blob data matrix, with at most one cell per blob. + """ + + +- name: DataColumn#gloas + sources: [] + spec: | + + class DataColumn(ProgressiveList[Cell]): + """ + A column of the extended blob data matrix, with at most one cell per blob. + """ + + +- name: DataColumnIndices#fulu + sources: [] + spec: | + + class DataColumnIndices(List[ColumnIndex, NUMBER_OF_COLUMNS]): + """ + The indices of the data columns being requested. + """ + + - name: DataColumnSidecar#fulu sources: - file: proto/prysm/v1alpha1/data_columns.proto search: message DataColumnSidecar { spec: | - + class DataColumnSidecar(Container): index: ColumnIndex - column: List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK] - kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - kzg_proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] + column: DataColumn + kzg_commitments: BlobKZGCommitments + kzg_proofs: KZGProofs signed_block_header: SignedBeaconBlockHeader - kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH] + kzg_commitments_inclusion_proof: KZGCommitmentsInclusionProof - name: DataColumnSidecar#gloas sources: [] spec: | - + class DataColumnSidecar(Container): index: ColumnIndex - column: List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK] + # [Modified in Gloas:EIP7688] + column: DataColumn # [Modified in Gloas:EIP7732] # Removed `kzg_commitments` - kzg_proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] + # [Modified in Gloas:EIP7688] + kzg_proofs: KZGProofs # [Modified in Gloas:EIP7732] # Removed `signed_block_header` # [Modified in Gloas:EIP7732] @@ -913,10 +1380,21 @@ - file: proto/prysm/v1alpha1/data_columns.proto search: message DataColumnsByRootIdentifier { spec: | - + class DataColumnsByRootIdentifier(Container): block_root: Root - columns: List[ColumnIndex, NUMBER_OF_COLUMNS] + columns: DataColumnIndices + + +- name: DataColumnsByRootIdentifiers#fulu + sources: [] + spec: | + + class DataColumnsByRootIdentifiers(List[DataColumnsByRootIdentifier, MAX_REQUEST_BLOCKS_DENEB]): # type: ignore + """ + The identifiers of the data column sidecars requested in a + ``DataColumnSidecarsByRoot`` request. + """ - name: Deposit#phase0 @@ -924,9 +1402,9 @@ - file: proto/eth/v1/beacon_block.proto search: message Deposit { spec: | - + class Deposit(Container): - proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH + 1] + proof: DepositProof data: DepositData @@ -943,6 +1421,16 @@ signature: BLSSignature +- name: DepositDataList#phase0 + sources: [] + spec: | + + class DepositDataList(List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH]): # type: ignore + """ + The ``DepositData`` of deposits made to the deposit contract. + """ + + - name: DepositMessage#phase0 sources: - file: proto/prysm/v1alpha1/beacon_state.proto @@ -955,28 +1443,109 @@ amount: Gwei +- name: DepositProof#phase0 + sources: [] + spec: | + + class DepositProof(Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH + 1]): # type: ignore + """ + A Merkle proof of a deposit in the deposit contract's tree. The node + beyond the tree depth accounts for the deposit count mix-in. + """ + + - name: DepositRequest#electra sources: - file: proto/engine/v1/electra.proto search: message DepositRequest { spec: | - + class DepositRequest(Container): pubkey: BLSPubkey withdrawal_credentials: Bytes32 amount: Gwei signature: BLSSignature - index: uint64 + index: Uint64 + + +- name: DepositRequests#electra + sources: [] + spec: | + + class DepositRequests(List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD]): + """ + The deposit requests pertaining to a single execution payload. + """ + + +- name: DepositRequests#gloas + sources: [] + spec: | + + class DepositRequests(ProgressiveList[DepositRequest]): + """ + The deposit requests pertaining to a single execution payload. + """ + + +- name: Deposits#phase0 + sources: [] + spec: | + + class Deposits(List[Deposit, MAX_DEPOSITS]): + """ + The deposits included in a beacon block. + """ + + +- name: Deposits#gloas + sources: [] + spec: | + + class Deposits(ProgressiveList[Deposit]): + """ + The deposits included in a beacon block. + """ + + +- name: EpochParticipation#altair + sources: [] + spec: | + + class EpochParticipation(List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT]): + """ + The participation flags of each validator for an epoch. + """ + + +- name: EpochParticipation#gloas + sources: [] + spec: | + + class EpochParticipation(ProgressiveList[ParticipationFlags]): + """ + The participation flags of each validator for an epoch. + """ + + +- name: ErrorMessage#phase0 + sources: [] + spec: | + + class ErrorMessage(List[Byte, 256]): + """ + The error message of an unsuccessful response chunk. + """ - name: Eth1Block#phase0 sources: [] spec: | - + class Eth1Block(Container): - timestamp: uint64 + timestamp: Uint64 deposit_root: Root - deposit_count: uint64 + deposit_count: Uint64 - name: Eth1Data#phase0 @@ -984,34 +1553,65 @@ - file: proto/prysm/v1alpha1/beacon_core_types.proto search: message Eth1Data { spec: | - + class Eth1Data(Container): deposit_root: Root - deposit_count: uint64 + deposit_count: Uint64 block_hash: Hash32 -- name: ExecutionPayload#bellatrix - sources: - - file: proto/engine/v1/execution_engine.proto +- name: Eth1DataVotes#phase0 + sources: [] + spec: | + + class Eth1DataVotes(List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]): # type: ignore + """ + The ``Eth1Data`` votes of the current voting period. + """ + + +- name: ExecutionBranch#capella + sources: [] + spec: | + + class ExecutionBranch(Vector[Bytes32, floorlog2(EXECUTION_PAYLOAD_GINDEX)]): # type: ignore + """ + A Merkle branch proving ``execution_payload`` within ``BeaconBlockBody``. + """ + + +- name: ExecutionBranch#gloas + sources: [] + spec: | + + class ExecutionBranch(Vector[Bytes32, floorlog2(EXECUTION_BLOCK_HASH_GINDEX_GLOAS)]): # type: ignore + """ + A Merkle branch proving the execution block hash within + ``BeaconBlockBody``. + """ + + +- name: ExecutionPayload#bellatrix + sources: + - file: proto/engine/v1/execution_engine.proto search: message ExecutionPayload { spec: | - + class ExecutionPayload(Container): parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + transactions: Transactions - name: ExecutionPayload#capella @@ -1019,24 +1619,24 @@ - file: proto/engine/v1/execution_engine.proto search: message ExecutionPayloadCapella { spec: | - + class ExecutionPayload(Container): parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + transactions: Transactions # [New in Capella] - withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] + withdrawals: Withdrawals - name: ExecutionPayload#deneb @@ -1044,100 +1644,115 @@ - file: proto/engine/v1/execution_engine.proto search: message ExecutionPayloadDeneb { spec: | - + class ExecutionPayload(Container): parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] - withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] + transactions: Transactions + withdrawals: Withdrawals # [New in Deneb:EIP4844] - blob_gas_used: uint64 + blob_gas_used: Uint64 # [New in Deneb:EIP4844] - excess_blob_gas: uint64 + excess_blob_gas: Uint64 - name: ExecutionPayload#gloas sources: [] spec: | - - class ExecutionPayload(Container): + + class ExecutionPayload(ProgressiveContainer(active_fields=[1] * 19)): # type: ignore parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] - withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - blob_gas_used: uint64 - excess_blob_gas: uint64 + # [Modified in Gloas:EIP7688] + transactions: Transactions + # [Modified in Gloas:EIP7688] + withdrawals: Withdrawals + blob_gas_used: Uint64 + excess_blob_gas: Uint64 # [New in Gloas:EIP7928] block_access_list: BlockAccessList # [New in Gloas:EIP7843] - slot_number: uint64 + slot_number: Uint64 + + +- name: ExecutionPayloadAvailability#gloas + sources: [] + spec: | + + class ExecutionPayloadAvailability(BitVector[SLOTS_PER_HISTORICAL_ROOT]): + """ + Bits tracking payload availability for recent slots, indexed by slot + modulo ``SLOTS_PER_HISTORICAL_ROOT``. + """ - name: ExecutionPayloadBid#gloas sources: [] spec: | - - class ExecutionPayloadBid(Container): + + class ExecutionPayloadBid(ProgressiveContainer(active_fields=[1] * 12)): # type: ignore parent_block_hash: Hash32 parent_block_root: Root block_hash: Hash32 prev_randao: Bytes32 fee_recipient: ExecutionAddress - gas_limit: uint64 + gas_limit: Uint64 builder_index: BuilderIndex slot: Slot value: Gwei execution_payment: Gwei - blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + blob_kzg_commitments: BlobKZGCommitments execution_requests_root: Root - name: ExecutionPayloadBid#heze sources: [] spec: | - - class ExecutionPayloadBid(Container): + + class ExecutionPayloadBid(ProgressiveContainer(active_fields=[1] * 13)): # type: ignore parent_block_hash: Hash32 parent_block_root: Root block_hash: Hash32 prev_randao: Bytes32 fee_recipient: ExecutionAddress - gas_limit: uint64 + gas_limit: Uint64 builder_index: BuilderIndex slot: Slot value: Gwei execution_payment: Gwei - blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + blob_kzg_commitments: BlobKZGCommitments execution_requests_root: Root + # [New in Heze:EIP7805] + inclusion_list_bits: InclusionListBits - name: ExecutionPayloadEnvelope#gloas sources: [] spec: | - - class ExecutionPayloadEnvelope(Container): + + class ExecutionPayloadEnvelope(ProgressiveContainer(active_fields=[1] * 5)): # type: ignore payload: ExecutionPayload execution_requests: ExecutionRequests builder_index: BuilderIndex @@ -1145,25 +1760,36 @@ parent_beacon_block_root: Root +- name: ExecutionPayloadEnvelopeRoots#gloas + sources: [] + spec: | + + class ExecutionPayloadEnvelopeRoots(List[Root, MAX_REQUEST_PAYLOADS]): # type: ignore + """ + The beacon block roots of the payload envelopes requested in an + ``ExecutionPayloadEnvelopesByRoot`` request. + """ + + - name: ExecutionPayloadHeader#bellatrix sources: - file: proto/engine/v1/execution_engine.proto search: message ExecutionPayloadHeader { spec: | - + class ExecutionPayloadHeader(Container): parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 transactions_root: Root @@ -1173,20 +1799,20 @@ - file: proto/engine/v1/execution_engine.proto search: message ExecutionPayloadHeaderCapella { spec: | - + class ExecutionPayloadHeader(Container): parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 transactions_root: Root # [New in Capella] @@ -1198,27 +1824,27 @@ - file: proto/engine/v1/execution_engine.proto search: message ExecutionPayloadHeaderDeneb { spec: | - + class ExecutionPayloadHeader(Container): parent_hash: Hash32 fee_recipient: ExecutionAddress state_root: Bytes32 receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs_bloom: LogsBloom prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 + block_number: Uint64 + gas_limit: Uint64 + gas_used: Uint64 + timestamp: Uint64 + extra_data: ExtraData + base_fee_per_gas: Uint256 block_hash: Hash32 transactions_root: Root withdrawals_root: Root # [New in Deneb:EIP4844] - blob_gas_used: uint64 + blob_gas_used: Uint64 # [New in Deneb:EIP4844] - excess_blob_gas: uint64 + excess_blob_gas: Uint64 - name: ExecutionRequests#electra @@ -1226,28 +1852,71 @@ - file: proto/engine/v1/electra.proto search: message ExecutionRequests { spec: | - + class ExecutionRequests(Container): # [New in Electra:EIP6110] - deposits: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] + deposits: DepositRequests # [New in Electra:EIP7002:EIP7251] - withdrawals: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] + withdrawals: WithdrawalRequests # [New in Electra:EIP7251] - consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] + consolidations: ConsolidationRequests - name: ExecutionRequests#gloas sources: [] spec: | - - class ExecutionRequests(Container): - deposits: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] - withdrawals: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] - consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] + + class ExecutionRequests(ProgressiveContainer(active_fields=[1] * 5)): # type: ignore + deposits: DepositRequests + withdrawals: WithdrawalRequests + consolidations: ConsolidationRequests # [New in Gloas:EIP8282] - builder_deposits: List[BuilderDepositRequest, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD] + builder_deposits: BuilderDepositRequests # [New in Gloas:EIP8282] - builder_exits: List[BuilderExitRequest, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD] + builder_exits: BuilderExitRequests + + +- name: ExtraData#bellatrix + sources: [] + spec: | + + class ExtraData(ByteList[MAX_EXTRA_DATA_BYTES]): + """ + Arbitrary extra data included in an execution payload. + """ + + +- name: FinalityBranch#altair + sources: [] + spec: | + + class FinalityBranch(Vector[Bytes32, floorlog2(FINALIZED_ROOT_GINDEX)]): # type: ignore + """ + A Merkle branch proving ``finalized_checkpoint.root`` within + ``BeaconState``. + """ + + +- name: FinalityBranch#electra + sources: [] + spec: | + + class FinalityBranch(Vector[Bytes32, floorlog2(FINALIZED_ROOT_GINDEX_ELECTRA)]): # type: ignore + """ + A Merkle branch proving ``finalized_checkpoint.root`` within + ``BeaconState``. + """ + + +- name: FinalityBranch#gloas + sources: [] + spec: | + + class FinalityBranch(Vector[Bytes32, floorlog2(FINALIZED_ROOT_GINDEX_GLOAS)]): # type: ignore + """ + A Merkle branch proving ``finalized_checkpoint.root`` within + ``BeaconState``. + """ - name: Fork#phase0 @@ -1278,10 +1947,30 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message HistoricalBatch { spec: | - + class HistoricalBatch(Container): - block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] + block_roots: BlockRoots + state_roots: StateRoots + + +- name: HistoricalRoots#phase0 + sources: [] + spec: | + + class HistoricalRoots(List[Root, HISTORICAL_ROOTS_LIMIT]): + """ + The roots of ``HistoricalBatch`` objects. + """ + + +- name: HistoricalSummaries#capella + sources: [] + spec: | + + class HistoricalSummaries(List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT]): + """ + Summaries of the chain's block and state root history. + """ - name: HistoricalSummary#capella @@ -1295,15 +1984,56 @@ state_summary_root: Root +- name: InactivityScores#altair + sources: [] + spec: | + + class InactivityScores(List[Uint64, VALIDATOR_REGISTRY_LIMIT]): + """ + Each validator's inactivity score, tracking missed timely target votes. + """ + + +- name: InactivityScores#gloas + sources: [] + spec: | + + class InactivityScores(ProgressiveList[Uint64]): + """ + Each validator's inactivity score, tracking missed timely target votes. + """ + + - name: InclusionList#heze sources: [] spec: | - + class InclusionList(Container): slot: Slot validator_index: ValidatorIndex - inclusion_list_committee_root: Root - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + dependent_root: Root + transactions: Transactions + + +- name: InclusionListBits#heze + sources: [] + spec: | + + class InclusionListBits(BitVector[INCLUSION_LIST_COMMITTEE_SIZE]): + """ + A bitfield over the inclusion list committee, one bit per member in + committee order. + """ + + +- name: InclusionListCommittee#heze + sources: [] + spec: | + + class InclusionListCommittee(Vector[ValidatorIndex, INCLUSION_LIST_COMMITTEE_SIZE]): + """ + The inclusion list committee of a slot. + """ - name: IndexedAttestation#phase0 @@ -1311,9 +2041,9 @@ - file: proto/prysm/v1alpha1/beacon_block.proto search: message IndexedAttestation { spec: | - + class IndexedAttestation(Container): - attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] + attesting_indices: AttestingIndices data: AttestationData signature: BLSSignature @@ -1323,10 +2053,22 @@ - file: proto/prysm/v1alpha1/beacon_core_types.proto search: message IndexedAttestationElectra { spec: | - + class IndexedAttestation(Container): # [Modified in Electra:EIP7549] - attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] + attesting_indices: AttestingIndices + data: AttestationData + signature: BLSSignature + + +- name: IndexedAttestation#gloas + sources: + - file: proto/prysm/v1alpha1/beacon_core_types.proto + search: message IndexedAttestationGloas { + spec: | + + class IndexedAttestation(ProgressiveContainer(active_fields=[1] * 3)): # type: ignore + attesting_indices: AttestingIndices data: AttestationData signature: BLSSignature @@ -1334,13 +2076,65 @@ - name: IndexedPayloadAttestation#gloas sources: [] spec: | - - class IndexedPayloadAttestation(Container): - attesting_indices: List[ValidatorIndex, PTC_SIZE] + + class IndexedPayloadAttestation(ProgressiveContainer(active_fields=[1] * 3)): # type: ignore + attesting_indices: PTCAttestingIndices data: PayloadAttestationData signature: BLSSignature +- name: JustificationBits#phase0 + sources: [] + spec: | + + class JustificationBits(BitVector[JUSTIFICATION_BITS_LENGTH]): + """ + The justification status of the last ``JUSTIFICATION_BITS_LENGTH`` epochs. + """ + + +- name: KZGCommitmentInclusionProof#deneb + sources: [] + spec: | + + class KZGCommitmentInclusionProof(Vector[Bytes32, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH]): + """ + A Merkle branch proving a blob's KZG commitment within + ``BeaconBlockBody``. + """ + + +- name: KZGCommitmentsInclusionProof#fulu + sources: [] + spec: | + + class KZGCommitmentsInclusionProof(Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH]): + """ + A Merkle branch proving a block's blob KZG commitments within + ``BeaconBlockBody``. + """ + + +- name: KZGProofs#deneb + sources: [] + spec: | + + class KZGProofs(List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK]): + """ + A list of KZG proofs, one for each blob or cell being proven. + """ + + +- name: KZGProofs#gloas + sources: [] + spec: | + + class KZGProofs(ProgressiveList[KZGProof]): + """ + The KZG cell proofs of the cells held by a data column. + """ + + - name: LightClientBootstrap#altair sources: - file: proto/prysm/v1alpha1/light_client.proto @@ -1499,6 +2293,26 @@ signature_slot: Slot +- name: LightClientUpdates#altair + sources: [] + spec: | + + class LightClientUpdates(List[LightClientUpdate, MAX_REQUEST_LIGHT_CLIENT_UPDATES]): + """ + Light client updates returned in a ``LightClientUpdatesByRange`` response. + """ + + +- name: LogsBloom#bellatrix + sources: [] + spec: | + + class LogsBloom(ByteVector[BYTES_PER_LOGS_BLOOM]): + """ + A Bloom filter aggregating the logs emitted by an execution payload. + """ + + - name: MatrixEntry#fulu sources: [] spec: | @@ -1510,72 +2324,175 @@ row_index: RowIndex +- name: NextSyncCommitteeBranch#altair + sources: [] + spec: | + + class NextSyncCommitteeBranch(Vector[Bytes32, floorlog2(NEXT_SYNC_COMMITTEE_GINDEX)]): # type: ignore + """ + A Merkle branch proving ``next_sync_committee`` within ``BeaconState``. + """ + + +- name: NextSyncCommitteeBranch#electra + sources: [] + spec: | + + class NextSyncCommitteeBranch(Vector[Bytes32, floorlog2(NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA)]): # type: ignore + """ + A Merkle branch proving ``next_sync_committee`` within ``BeaconState``. + """ + + +- name: NextSyncCommitteeBranch#gloas + sources: [] + spec: | + + class NextSyncCommitteeBranch(Vector[Bytes32, floorlog2(NEXT_SYNC_COMMITTEE_GINDEX_GLOAS)]): # type: ignore + """ + A Merkle branch proving ``next_sync_committee`` within ``BeaconState``. + """ + + +- name: OptionalPartialDataColumnHeader#fulu + sources: [] + spec: | + + class OptionalPartialDataColumnHeader(List[PartialDataColumnHeader, 1]): + """ + A header that may or may not be present, encoded as a list of length zero + or one. + """ + + +- name: PTC#gloas + sources: [] + spec: | + + class PTC(Vector[ValidatorIndex, PTC_SIZE]): + """ + The payload timeliness committee of a slot. + """ + + +- name: PTCAttestingIndices#gloas + sources: [] + spec: | + + class PTCAttestingIndices(List[ValidatorIndex, PTC_SIZE]): + """ + The indices of the PTC members participating in a payload attestation. + """ + + +- name: PTCBits#gloas + sources: [] + spec: | + + class PTCBits(BitVector[PTC_SIZE]): + """ + The participation bits of the payload timeliness committee, one bit per + member in committee order. + """ + + +- name: PTCWindow#gloas + sources: [] + spec: | + + class PTCWindow(Vector[PTC, (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH]): # type: ignore + """ + A rolling window of payload timeliness committees for the previous, + current, and lookahead epochs. + """ + + +- name: PartialDataColumnGroupID#fulu + sources: [] + spec: | + + class PartialDataColumnGroupID(Container): + beacon_block_root: Root + + - name: PartialDataColumnGroupID#gloas sources: [] spec: | - + class PartialDataColumnGroupID(Container): - slot: Slot beacon_block_root: Root + # [New in Gloas:EIP7732] + slot: Slot - name: PartialDataColumnHeader#fulu sources: [] spec: | - + class PartialDataColumnHeader(Container): - kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + kzg_commitments: BlobKZGCommitments signed_block_header: SignedBeaconBlockHeader - kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH] + kzg_commitments_inclusion_proof: KZGCommitmentsInclusionProof - name: PartialDataColumnHeader#gloas sources: [] spec: | - + class PartialDataColumnHeader(Container): - kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + kzg_commitments: BlobKZGCommitments signed_block_header: SignedBeaconBlockHeader - kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH] + kzg_commitments_inclusion_proof: KZGCommitmentsInclusionProof - name: PartialDataColumnPartsMetadata#fulu sources: [] spec: | - + class PartialDataColumnPartsMetadata(Container): - available: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] - requests: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] + available: CellsBitList + requests: CellsBitList + + +- name: PartialDataColumnPartsMetadata#gloas + sources: [] + spec: | + + class PartialDataColumnPartsMetadata(Container): + # [Modified in Gloas:EIP7688] + available: CellsBitList + # [Modified in Gloas:EIP7688] + requests: CellsBitList - name: PartialDataColumnSidecar#fulu sources: [] spec: | - + class PartialDataColumnSidecar(Container): - cells_present_bitmap: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] - partial_column: List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK] - kzg_proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] + cells_present_bitmap: CellsBitList + partial_column: DataColumn + kzg_proofs: KZGProofs # Optional header, only sent on eager pushes - header: List[PartialDataColumnHeader, 1] + header: OptionalPartialDataColumnHeader - name: PartialDataColumnSidecar#gloas sources: [] spec: | - + class PartialDataColumnSidecar(Container): - cells_present_bitmap: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] - partial_column: List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK] - kzg_proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] + cells_present_bitmap: CellsBitList + partial_column: DataColumn + kzg_proofs: KZGProofs - name: PayloadAttestation#gloas sources: [] spec: | - - class PayloadAttestation(Container): - aggregation_bits: Bitvector[PTC_SIZE] + + class PayloadAttestation(ProgressiveContainer(active_fields=[1] * 3)): # type: ignore + aggregation_bits: PTCBits data: PayloadAttestationData signature: BLSSignature @@ -1583,12 +2500,12 @@ - name: PayloadAttestationData#gloas sources: [] spec: | - + class PayloadAttestationData(Container): beacon_block_root: Root slot: Slot - payload_present: boolean - blob_data_available: boolean + payload_present: Boolean + blob_data_available: Boolean - name: PayloadAttestationMessage#gloas @@ -1601,19 +2518,39 @@ signature: BLSSignature +- name: PayloadAttestations#gloas + sources: [] + spec: | + + class PayloadAttestations(ProgressiveList[PayloadAttestation]): + """ + The payload attestations included in a beacon block. + """ + + - name: PendingAttestation#phase0 sources: - file: proto/prysm/v1alpha1/beacon_state.proto search: message PendingAttestation { spec: | - + class PendingAttestation(Container): - aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE] + aggregation_bits: AggregationBits data: AttestationData inclusion_delay: Slot proposer_index: ValidatorIndex +- name: PendingAttestations#phase0 + sources: [] + spec: | + + class PendingAttestations(List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]): # type: ignore + """ + The attestations included in blocks during an epoch. + """ + + - name: PendingConsolidation#electra sources: - file: proto/prysm/v1alpha1/eip_7251.proto @@ -1625,6 +2562,26 @@ target_index: ValidatorIndex +- name: PendingConsolidations#electra + sources: [] + spec: | + + class PendingConsolidations(List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT]): + """ + The queue of consolidations awaiting processing. + """ + + +- name: PendingConsolidations#gloas + sources: [] + spec: | + + class PendingConsolidations(ProgressiveList[PendingConsolidation]): + """ + The queue of consolidations awaiting processing. + """ + + - name: PendingDeposit#electra sources: - file: proto/prysm/v1alpha1/eip_7251.proto @@ -1639,6 +2596,26 @@ slot: Slot +- name: PendingDeposits#electra + sources: [] + spec: | + + class PendingDeposits(List[PendingDeposit, PENDING_DEPOSITS_LIMIT]): + """ + The queue of deposits awaiting processing. + """ + + +- name: PendingDeposits#gloas + sources: [] + spec: | + + class PendingDeposits(ProgressiveList[PendingDeposit]): + """ + The queue of deposits awaiting processing. + """ + + - name: PendingPartialWithdrawal#electra sources: - file: proto/prysm/v1alpha1/eip_7251.proto @@ -1651,28 +2628,79 @@ withdrawable_epoch: Epoch +- name: PendingPartialWithdrawals#electra + sources: [] + spec: | + + class PendingPartialWithdrawals(List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT]): + """ + The queue of partial withdrawals awaiting processing. + """ + + +- name: PendingPartialWithdrawals#gloas + sources: [] + spec: | + + class PendingPartialWithdrawals(ProgressiveList[PendingPartialWithdrawal]): + """ + The queue of partial withdrawals awaiting processing. + """ + + - name: PowBlock#bellatrix sources: - file: proto/prysm/v1alpha1/beacon_state.proto search: message PowBlock { spec: | - + class PowBlock(Container): block_hash: Hash32 parent_hash: Hash32 - total_difficulty: uint256 + total_difficulty: Uint256 + + +- name: Proofs#fulu + sources: [] + spec: | + + class Proofs(Vector[KZGProof, CELLS_PER_EXT_BLOB]): + """ + The KZG proofs for the cells of a single extended blob. + """ + + +- name: ProposerIndices#fulu + sources: [] + spec: | + + class ProposerIndices(Vector[ValidatorIndex, SLOTS_PER_EPOCH]): + """ + The proposer indices for every slot of a single epoch. + """ + + +- name: ProposerLookahead#fulu + sources: [] + spec: | + + class ProposerLookahead(Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]): # type: ignore + """ + The precomputed proposer indices for the current and next + ``MIN_SEED_LOOKAHEAD`` epochs. + """ - name: ProposerPreferences#gloas sources: [] spec: | - + class ProposerPreferences(Container): dependent_root: Root proposal_slot: Slot validator_index: ValidatorIndex fee_recipient: ExecutionAddress - target_gas_limit: uint64 + target_gas_limit: Uint64 - name: ProposerSlashing#phase0 @@ -1686,6 +2714,37 @@ signed_header_2: SignedBeaconBlockHeader +- name: ProposerSlashings#phase0 + sources: [] + spec: | + + class ProposerSlashings(List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]): + """ + The proposer slashings included in a beacon block. + """ + + +- name: ProposerSlashings#gloas + sources: [] + spec: | + + class ProposerSlashings(ProgressiveList[ProposerSlashing]): + """ + The proposer slashings included in a beacon block. + """ + + +- name: RandaoMixes#phase0 + sources: [] + spec: | + + class RandaoMixes(Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR]): + """ + A rolling window of accumulated RANDAO mixes, indexed by epoch modulo + ``EPOCHS_PER_HISTORICAL_VECTOR``. + """ + + - name: SignedAggregateAndProof#phase0 sources: - file: proto/prysm/v1alpha1/attestation.proto @@ -1742,6 +2801,28 @@ signature: BLSSignature +- name: SignedBeaconBlocks#phase0 + sources: [] + spec: | + + class SignedBeaconBlocks(List[SignedBeaconBlock, MAX_REQUEST_BLOCKS]): # type: ignore + """ + Signed beacon blocks returned in a ``BeaconBlocksByRange`` or + ``BeaconBlocksByRoot`` response. + """ + + +- name: SignedBeaconBlocks#deneb + sources: [] + spec: | + + class SignedBeaconBlocks(List[SignedBeaconBlock, MAX_REQUEST_BLOCKS_DENEB]): # type: ignore + """ + Signed beacon blocks returned in a ``BeaconBlocksByRange`` or + ``BeaconBlocksByRoot`` response. + """ + + - name: SignedContributionAndProof#altair sources: - file: proto/prysm/v1alpha1/sync_committee.proto @@ -1765,8 +2846,9 @@ - name: SignedExecutionPayloadBid#heze sources: [] spec: | - + class SignedExecutionPayloadBid(Container): + # [Modified in Heze:EIP7805] message: ExecutionPayloadBid signature: BLSSignature @@ -1780,6 +2862,18 @@ signature: BLSSignature +- name: SignedExecutionPayloadEnvelopes#gloas + sources: [] + spec: | + + class SignedExecutionPayloadEnvelopes(List[SignedExecutionPayloadEnvelope, MAX_REQUEST_PAYLOADS]): # type: ignore + """ + Signed execution payload envelopes returned in an + ``ExecutionPayloadEnvelopesByRange`` or + ``ExecutionPayloadEnvelopesByRoot`` response. + """ + + - name: SignedInclusionList#heze sources: [] spec: | @@ -1789,6 +2883,17 @@ signature: BLSSignature +- name: SignedInclusionLists#heze + sources: [] + spec: | + + class SignedInclusionLists(List[SignedInclusionList, MAX_REQUEST_INCLUSION_LIST]): # type: ignore + """ + Signed inclusion lists returned in an ``InclusionListsByIndices`` + response. + """ + + - name: SignedProposerPreferences#gloas sources: [] spec: | @@ -1833,14 +2938,36 @@ signature: BLSSignature +- name: Slashings#phase0 + sources: [] + spec: | + + class Slashings(Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR]): + """ + Per-epoch sums of slashed effective balances, indexed by epoch modulo + ``EPOCHS_PER_SLASHINGS_VECTOR``. + """ + + +- name: StateRoots#phase0 + sources: [] + spec: | + + class StateRoots(Vector[Root, SLOTS_PER_HISTORICAL_ROOT]): + """ + A rolling window of recent state roots, indexed by slot modulo + ``SLOTS_PER_HISTORICAL_ROOT``. + """ + + - name: SyncAggregate#altair sources: - file: proto/prysm/v1alpha1/beacon_core_types.proto search: message SyncAggregate { spec: | - + class SyncAggregate(Container): - sync_committee_bits: Bitvector[SYNC_COMMITTEE_SIZE] + sync_committee_bits: SyncCommitteeBits sync_committee_signature: BLSSignature @@ -1849,10 +2976,10 @@ - file: proto/prysm/v1alpha1/beacon_state.proto search: message SyncAggregatorSelectionData { spec: | - + class SyncAggregatorSelectionData(Container): slot: Slot - subcommittee_index: uint64 + subcommittee_index: Uint64 - name: SyncCommittee#altair @@ -1860,23 +2987,34 @@ - file: proto/prysm/v1alpha1/beacon_core_types.proto search: message SyncCommittee { spec: | - + class SyncCommittee(Container): - pubkeys: Vector[BLSPubkey, SYNC_COMMITTEE_SIZE] + pubkeys: SyncCommitteePubkeys aggregate_pubkey: BLSPubkey +- name: SyncCommitteeBits#altair + sources: [] + spec: | + + class SyncCommitteeBits(BitVector[SYNC_COMMITTEE_SIZE]): + """ + The participation bits of the sync committee, one bit per member in + committee order. + """ + + - name: SyncCommitteeContribution#altair sources: - file: proto/prysm/v1alpha1/sync_committee.proto search: message SyncCommitteeContribution { spec: | - + class SyncCommitteeContribution(Container): slot: Slot beacon_block_root: Root - subcommittee_index: uint64 - aggregation_bits: Bitvector[SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT] + subcommittee_index: Uint64 + aggregation_bits: SyncSubcommitteeBits signature: BLSSignature @@ -1893,23 +3031,116 @@ signature: BLSSignature +- name: SyncCommitteePubkeys#altair + sources: [] + spec: | + + class SyncCommitteePubkeys(Vector[BLSPubkey, SYNC_COMMITTEE_SIZE]): + """ + The public keys of the sync committee members, in committee order. + """ + + +- name: SyncSubcommitteeBits#altair + sources: [] + spec: | + + class SyncSubcommitteeBits(BitVector[SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT]): # type: ignore + """ + The participation bits of a single sync subcommittee, one bit per member + in subcommittee order. + """ + + +- name: Syncnets#altair + sources: [] + spec: | + + class Syncnets(BitVector[SYNC_COMMITTEE_SUBNET_COUNT]): + """ + The sync committee subnets a node is subscribed to, one bit per subnet. + """ + + +- name: Transaction#bellatrix + sources: [] + spec: | + + class Transaction(ByteList[MAX_BYTES_PER_TRANSACTION]): + """ + An opaque execution-layer transaction, either a typed transaction + envelope or a legacy RLP-encoded transaction. + """ + + +- name: Transaction#gloas + sources: [] + spec: | + + class Transaction(ProgressiveByteList): + """ + An opaque execution-layer transaction, either a typed transaction + envelope or a legacy RLP-encoded transaction. + """ + + +- name: Transactions#bellatrix + sources: [] + spec: | + + class Transactions(List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]): + """ + A list of execution-layer transactions. + """ + + +- name: Transactions#gloas + sources: [] + spec: | + + class Transactions(ProgressiveList[Transaction]): + """ + A list of execution-layer transactions. + """ + + - name: Validator#phase0 sources: - file: proto/prysm/v1alpha1/beacon_core_types.proto search: message Validator { spec: | - + class Validator(Container): pubkey: BLSPubkey withdrawal_credentials: Bytes32 effective_balance: Gwei - slashed: boolean + slashed: Boolean activation_eligibility_epoch: Epoch activation_epoch: Epoch exit_epoch: Epoch withdrawable_epoch: Epoch +- name: Validators#phase0 + sources: [] + spec: | + + class Validators(List[Validator, VALIDATOR_REGISTRY_LIMIT]): + """ + The validator registry. + """ + + +- name: Validators#gloas + sources: [] + spec: | + + class Validators(ProgressiveList[Validator]): + """ + The validator registry. + """ + + - name: VoluntaryExit#phase0 sources: - file: proto/eth/v1/beacon_block.proto @@ -1921,6 +3152,26 @@ validator_index: ValidatorIndex +- name: VoluntaryExits#phase0 + sources: [] + spec: | + + class VoluntaryExits(List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]): + """ + The signed voluntary exits included in a beacon block. + """ + + +- name: VoluntaryExits#gloas + sources: [] + spec: | + + class VoluntaryExits(ProgressiveList[SignedVoluntaryExit]): + """ + The signed voluntary exits included in a beacon block. + """ + + - name: Withdrawal#capella sources: - file: proto/engine/v1/execution_engine.proto @@ -1945,3 +3196,43 @@ validator_pubkey: BLSPubkey amount: Gwei + +- name: WithdrawalRequests#electra + sources: [] + spec: | + + class WithdrawalRequests(List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD]): + """ + The withdrawal requests pertaining to a single execution payload. + """ + + +- name: WithdrawalRequests#gloas + sources: [] + spec: | + + class WithdrawalRequests(ProgressiveList[WithdrawalRequest]): + """ + The withdrawal requests pertaining to a single execution payload. + """ + + +- name: Withdrawals#capella + sources: [] + spec: | + + class Withdrawals(List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]): + """ + A list of withdrawals. + """ + + +- name: Withdrawals#gloas + sources: [] + spec: | + + class Withdrawals(ProgressiveList[Withdrawal]): + """ + A list of withdrawals. + """ + diff --git a/specrefs/dataclasses.yml b/specrefs/dataclasses.yml index 668ea2b39f16..961b3bf100e0 100644 --- a/specrefs/dataclasses.yml +++ b/specrefs/dataclasses.yml @@ -1,10 +1,10 @@ - name: BlobParameters#fulu sources: [] spec: | - + class BlobParameters: epoch: Epoch - max_blobs_per_block: uint64 + max_blobs_per_block: Uint64 - name: BlobsBundle#deneb @@ -13,11 +13,11 @@ search: ^message BlobsBundle\s*\{ regex: true spec: | - + class BlobsBundle: - commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] - blobs: List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK] + commitments: BlobKZGCommitments + proofs: KZGProofs + blobs: Blobs - name: BlobsBundle#fulu @@ -26,46 +26,46 @@ search: ^message BlobsBundleV2 regex: true spec: | - + class BlobsBundle: - commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + commitments: BlobKZGCommitments # [Modified in Fulu:EIP7594] - proofs: List[KZGProof, FIELD_ELEMENTS_PER_EXT_BLOB * MAX_BLOB_COMMITMENTS_PER_BLOCK] - blobs: List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK] + proofs: CellKZGProofs + blobs: Blobs - name: ExpectedWithdrawals#capella sources: [] spec: | - + class ExpectedWithdrawals: withdrawals: Sequence[Withdrawal] - processed_sweep_withdrawals_count: uint64 + processed_sweep_withdrawals_count: Uint64 - name: ExpectedWithdrawals#electra sources: [] spec: | - + class ExpectedWithdrawals: withdrawals: Sequence[Withdrawal] # [New in Electra:EIP7251] - processed_partial_withdrawals_count: uint64 - processed_sweep_withdrawals_count: uint64 + processed_partial_withdrawals_count: Uint64 + processed_sweep_withdrawals_count: Uint64 - name: ExpectedWithdrawals#gloas sources: [] spec: | - + class ExpectedWithdrawals: withdrawals: Sequence[Withdrawal] # [New in Gloas:EIP7732] - processed_builder_withdrawals_count: uint64 - processed_partial_withdrawals_count: uint64 + processed_builder_withdrawals_count: Uint64 + processed_partial_withdrawals_count: Uint64 # [New in Gloas:EIP7732] - processed_builders_sweep_count: uint64 - processed_sweep_withdrawals_count: uint64 + processed_builders_sweep_count: Uint64 + processed_sweep_withdrawals_count: Uint64 - name: FastConfirmationStore#phase0 @@ -129,10 +129,10 @@ - file: consensus-types/blocks/get_payload.go search: GetPayloadResponseV(1|2 spec: | - + class GetPayloadResponse: execution_payload: ExecutionPayload - block_value: uint256 + block_value: Uint256 - name: GetPayloadResponse#deneb @@ -142,10 +142,10 @@ - file: consensus-types/blocks/get_payload.go search: GetPayloadResponseV(1|2|3 spec: | - + class GetPayloadResponse: execution_payload: ExecutionPayload - block_value: uint256 + block_value: Uint256 # [New in Deneb:EIP4844] blobs_bundle: BlobsBundle @@ -157,10 +157,10 @@ - file: consensus-types/blocks/get_payload.go search: GetPayloadResponseV(1|2|3|4 spec: | - + class GetPayloadResponse: execution_payload: ExecutionPayload - block_value: uint256 + block_value: Uint256 blobs_bundle: BlobsBundle # [New in Electra] execution_requests: Sequence[bytes] @@ -173,27 +173,32 @@ - file: consensus-types/blocks/get_payload.go search: GetPayloadResponseV(1|2|3|4|5 spec: | - + class GetPayloadResponse: execution_payload: ExecutionPayload - block_value: uint256 + block_value: Uint256 # [Modified in Fulu:EIP7594] blobs_bundle: BlobsBundle execution_requests: Sequence[bytes] +- name: InclusionListEntry#heze + sources: [] + spec: | + + @dataclass(eq=True, frozen=True) + class InclusionListEntry: + signed_inclusion_list: SignedInclusionList + timely: Boolean + + - name: InclusionListStore#heze sources: [] spec: | - + class InclusionListStore: - inclusion_lists: DefaultDict[Root, Dict[Root, InclusionList]] = field( - default_factory=lambda: defaultdict(dict) - ) - inclusion_list_timeliness: Dict[Root, boolean] = field(default_factory=dict) - equivocators: DefaultDict[Root, Set[ValidatorIndex]] = field( - default_factory=lambda: defaultdict(set) - ) + inclusion_lists: DefaultDict[Tuple[Slot, Root], Dict[ValidatorIndex, InclusionListEntry]] + equivocators: DefaultDict[Tuple[Slot, Root], Set[ValidatorIndex]] - name: LatestMessage#phase0 @@ -209,18 +214,18 @@ - name: LatestMessage#gloas sources: [] spec: | - + @dataclass(eq=True, frozen=True) class LatestMessage: slot: Slot root: Root - payload_present: boolean + payload_present: Boolean - name: LightClientStore#altair sources: [] spec: | - + class LightClientStore: # Header that is finalized finalized_header: LightClientHeader @@ -232,14 +237,14 @@ # Most recent available reasonably-safe header optimistic_header: LightClientHeader # Max number of active participants in a sync committee (used to calculate safety threshold) - previous_max_active_participants: uint64 - current_max_active_participants: uint64 + previous_max_active_participants: Uint64 + current_max_active_participants: Uint64 - name: LightClientStore#capella sources: [] spec: | - + class LightClientStore: # [Modified in Capella] finalized_header: LightClientHeader @@ -249,8 +254,8 @@ best_valid_update: Optional[LightClientUpdate] # [Modified in Capella] optimistic_header: LightClientHeader - previous_max_active_participants: uint64 - current_max_active_participants: uint64 + previous_max_active_participants: Uint64 + current_max_active_participants: Uint64 - name: NewPayloadRequest#bellatrix @@ -292,12 +297,12 @@ - name: OptimisticStore#bellatrix sources: [] spec: | - - class OptimisticStore(object): + + class OptimisticStore: optimistic_roots: Set[Root] head_block_root: Root - blocks: Dict[Root, BeaconBlock] = field(default_factory=dict) - block_states: Dict[Root, BeaconState] = field(default_factory=dict) + blocks: Dict[Root, BeaconBlock] + block_states: Dict[Root, BeaconState] - name: PayloadAttributes#bellatrix @@ -306,9 +311,9 @@ search: ^message PayloadAttributes\s*\{ regex: true spec: | - + class PayloadAttributes: - timestamp: uint64 + timestamp: Uint64 prev_randao: Bytes32 suggested_fee_recipient: ExecutionAddress @@ -319,9 +324,9 @@ search: ^message PayloadAttributesV2 regex: true spec: | - + class PayloadAttributes: - timestamp: uint64 + timestamp: Uint64 prev_randao: Bytes32 suggested_fee_recipient: ExecutionAddress # [New in Capella] @@ -334,9 +339,9 @@ search: ^message PayloadAttributesV3 regex: true spec: | - + class PayloadAttributes: - timestamp: uint64 + timestamp: Uint64 prev_randao: Bytes32 suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] @@ -347,31 +352,31 @@ - name: PayloadAttributes#gloas sources: [] spec: | - + class PayloadAttributes: - timestamp: uint64 + timestamp: Uint64 prev_randao: Bytes32 suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root # [New in Gloas:EIP7843] - slot_number: uint64 + slot_number: Uint64 # [New in Gloas] - target_gas_limit: uint64 + target_gas_limit: Uint64 - name: PayloadAttributes#heze sources: [] spec: | - + class PayloadAttributes: - timestamp: uint64 + timestamp: Uint64 prev_randao: Bytes32 suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root - slot_number: uint64 - target_gas_limit: uint64 + slot_number: Uint64 + target_gas_limit: Uint64 # [New in Heze:EIP7805] inclusion_list_transactions: Sequence[Transaction] @@ -379,52 +384,52 @@ - name: Seen#phase0 sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - aggregate_data_roots: Dict[Root, Set[Tuple[boolean, ...]]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + aggregate_data_roots: Dict[Root, Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] - name: Seen#altair sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - aggregate_data_roots: Dict[Root, Set[Tuple[boolean, ...]]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + aggregate_data_roots: Dict[Root, Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] # [New in Altair] - sync_contribution_aggregator_slots: Set[Tuple[ValidatorIndex, Slot, uint64]] + sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] # [New in Altair] - sync_contribution_data: Dict[Tuple[Slot, Root, uint64], Set[Tuple[boolean, ...]]] + sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[Boolean, ...]]] # [New in Altair] - sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, uint64]] + sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] - name: Seen#capella sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - aggregate_data_roots: Dict[Root, Set[Tuple[boolean, ...]]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + aggregate_data_roots: Dict[Root, Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - sync_contribution_aggregator_slots: Set[Tuple[ValidatorIndex, Slot, uint64]] - sync_contribution_data: Dict[Tuple[Slot, Root, uint64], Set[Tuple[boolean, ...]]] - sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, uint64]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] + sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[Boolean, ...]]] + sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] # [New in Capella] bls_to_execution_change_indices: Set[ValidatorIndex] @@ -432,18 +437,18 @@ - name: Seen#deneb sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - aggregate_data_roots: Dict[Root, Set[Tuple[boolean, ...]]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + aggregate_data_roots: Dict[Root, Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - sync_contribution_aggregator_slots: Set[Tuple[ValidatorIndex, Slot, uint64]] - sync_contribution_data: Dict[Tuple[Slot, Root, uint64], Set[Tuple[boolean, ...]]] - sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, uint64]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] + sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[Boolean, ...]]] + sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] bls_to_execution_change_indices: Set[ValidatorIndex] # [New in Deneb] blob_sidecar_tuples: Set[Tuple[Slot, ValidatorIndex, BlobIndex]] @@ -452,19 +457,19 @@ - name: Seen#electra sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] # [Modified in Electra:EIP7549] - aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[boolean, ...]]] + aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - sync_contribution_aggregator_slots: Set[Tuple[ValidatorIndex, Slot, uint64]] - sync_contribution_data: Dict[Tuple[Slot, Root, uint64], Set[Tuple[boolean, ...]]] - sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, uint64]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] + sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[Boolean, ...]]] + sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] bls_to_execution_change_indices: Set[ValidatorIndex] blob_sidecar_tuples: Set[Tuple[Slot, ValidatorIndex, BlobIndex]] @@ -472,18 +477,18 @@ - name: Seen#fulu sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[boolean, ...]]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - sync_contribution_aggregator_slots: Set[Tuple[ValidatorIndex, Slot, uint64]] - sync_contribution_data: Dict[Tuple[Slot, Root, uint64], Set[Tuple[boolean, ...]]] - sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, uint64]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] + sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[Boolean, ...]]] + sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] bls_to_execution_change_indices: Set[ValidatorIndex] # [Modified in Fulu:EIP7594] # Removed `blob_sidecar_tuples` @@ -496,97 +501,108 @@ - name: Seen#gloas sources: [] spec: | - + class Seen: - proposer_slots: Set[Tuple[ValidatorIndex, Slot]] - aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[boolean, ...]]] + proposer_slots: Set[Tuple[Slot, ValidatorIndex]] + aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[Boolean, ...]]] voluntary_exit_indices: Set[ValidatorIndex] proposer_slashing_indices: Set[ValidatorIndex] attester_slashing_indices: Set[ValidatorIndex] - attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] - sync_contribution_aggregator_slots: Set[Tuple[ValidatorIndex, Slot, uint64]] - sync_contribution_data: Dict[Tuple[Slot, Root, uint64], Set[Tuple[boolean, ...]]] - sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, uint64]] + attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]] + sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] + sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[Boolean, ...]]] + sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]] bls_to_execution_change_indices: Set[ValidatorIndex] - data_column_sidecar_tuples: Set[Tuple[Slot, ValidatorIndex, ColumnIndex]] + # [Modified in Gloas:EIP7732] + data_column_sidecar_tuples: Set[Tuple[Root, ColumnIndex]] + # [Modified in Gloas:EIP7732] + # Removed `partial_data_column_headers` + # [New in Gloas:EIP7732] + execution_payloads: Dict[Hash32, ExecutionPayload] + # [New in Gloas:EIP7732] + execution_payload_envelopes: Set[Tuple[Root, BuilderIndex]] + # [New in Gloas:EIP7732] + payload_attestation_validators: Set[Tuple[Slot, ValidatorIndex]] + # [New in Gloas:EIP7732] + execution_payload_bids: Set[Tuple[Slot, Hash32, Root, BuilderIndex]] + # [New in Gloas:EIP7732] + best_execution_payload_bid: Dict[Tuple[Slot, Hash32, Root], Gwei] + # [New in Gloas:EIP7732] + proposer_preferences: Dict[Tuple[Root, Slot], ProposerPreferences] - name: Store#phase0 sources: [] spec: | - + class Store: - time: uint64 - genesis_time: uint64 + time: Uint64 + genesis_time: Uint64 justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint unrealized_justified_checkpoint: Checkpoint unrealized_finalized_checkpoint: Checkpoint proposer_boost_root: Root equivocating_indices: Set[ValidatorIndex] - blocks: Dict[Root, BeaconBlock] = field(default_factory=dict) - block_states: Dict[Root, BeaconState] = field(default_factory=dict) - block_timeliness: Dict[Root, boolean] = field(default_factory=dict) - checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict) - latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict) - unrealized_justifications: Dict[Root, Checkpoint] = field(default_factory=dict) + blocks: Dict[Root, BeaconBlock] + block_states: Dict[Root, BeaconState] + block_timeliness: Dict[Root, Boolean] + checkpoint_states: Dict[Checkpoint, BeaconState] + latest_messages: Dict[ValidatorIndex, LatestMessage] + unrealized_justifications: Dict[Root, Checkpoint] - name: Store#gloas sources: [] spec: | - + class Store: - time: uint64 - genesis_time: uint64 + time: Uint64 + genesis_time: Uint64 justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint unrealized_justified_checkpoint: Checkpoint unrealized_finalized_checkpoint: Checkpoint proposer_boost_root: Root equivocating_indices: Set[ValidatorIndex] - blocks: Dict[Root, BeaconBlock] = field(default_factory=dict) - block_states: Dict[Root, BeaconState] = field(default_factory=dict) + blocks: Dict[Root, BeaconBlock] + block_states: Dict[Root, BeaconState] # [Modified in Gloas:EIP7732] - block_timeliness: Dict[Root, list[boolean]] = field(default_factory=dict) - checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict) - latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict) - unrealized_justifications: Dict[Root, Checkpoint] = field(default_factory=dict) + block_timeliness: Dict[Root, list[Boolean]] + checkpoint_states: Dict[Checkpoint, BeaconState] + latest_messages: Dict[ValidatorIndex, LatestMessage] + unrealized_justifications: Dict[Root, Checkpoint] # [New in Gloas:EIP7732] - payloads: Dict[Root, ExecutionPayloadEnvelope] = field(default_factory=dict) + payloads: Dict[Root, ExecutionPayloadEnvelope] # [New in Gloas:EIP7732] - payload_timeliness_vote: Dict[Root, list[Optional[boolean]]] = field(default_factory=dict) + payload_timeliness_vote: Dict[Root, list[Optional[Boolean]]] # [New in Gloas:EIP7732] - payload_data_availability_vote: Dict[Root, list[Optional[boolean]]] = field( - default_factory=dict - ) + payload_data_availability_vote: Dict[Root, list[Optional[Boolean]]] - name: Store#heze sources: [] spec: | - + class Store: - time: uint64 - genesis_time: uint64 + time: Uint64 + genesis_time: Uint64 justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint unrealized_justified_checkpoint: Checkpoint unrealized_finalized_checkpoint: Checkpoint proposer_boost_root: Root equivocating_indices: Set[ValidatorIndex] - blocks: Dict[Root, BeaconBlock] = field(default_factory=dict) - block_states: Dict[Root, BeaconState] = field(default_factory=dict) - block_timeliness: Dict[Root, list[boolean]] = field(default_factory=dict) - checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict) - latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict) - unrealized_justifications: Dict[Root, Checkpoint] = field(default_factory=dict) - payloads: Dict[Root, ExecutionPayloadEnvelope] = field(default_factory=dict) - payload_timeliness_vote: Dict[Root, list[Optional[boolean]]] = field(default_factory=dict) - payload_data_availability_vote: Dict[Root, list[Optional[boolean]]] = field( - default_factory=dict - ) + blocks: Dict[Root, BeaconBlock] + block_states: Dict[Root, BeaconState] + block_timeliness: Dict[Root, list[Boolean]] + checkpoint_states: Dict[Checkpoint, BeaconState] + latest_messages: Dict[ValidatorIndex, LatestMessage] + unrealized_justifications: Dict[Root, Checkpoint] + payloads: Dict[Root, ExecutionPayloadEnvelope] + payload_timeliness_vote: Dict[Root, list[Optional[Boolean]]] + payload_data_availability_vote: Dict[Root, list[Optional[Boolean]]] # [New in Heze:EIP7805] - payload_inclusion_list_satisfaction: Dict[Root, boolean] = field(default_factory=dict) + payload_inclusion_list_satisfaction: Dict[Root, Boolean] diff --git a/specrefs/functions.yml b/specrefs/functions.yml index efc7bd7241f6..94d0c7b6f181 100644 --- a/specrefs/functions.yml +++ b/specrefs/functions.yml @@ -1,13 +1,13 @@ - name: add_builder_to_registry#gloas sources: [] spec: | - + def add_builder_to_registry( state: BeaconState, pubkey: BLSPubkey, - version: uint8, + version: Uint8, execution_address: ExecutionAddress, - amount: uint64, + amount: Uint64, slot: Slot, ) -> None: set_or_append_list( @@ -43,9 +43,9 @@ - file: beacon-chain/core/altair/deposit.go search: func AddValidatorToRegistry( spec: | - + def add_validator_to_registry( - state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64 + state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: Uint64 ) -> None: state.validators.append(get_validator_from_deposit(pubkey, withdrawal_credentials, amount)) state.balances.append(amount) @@ -56,9 +56,9 @@ - file: beacon-chain/core/altair/deposit.go search: func AddValidatorToRegistry( spec: | - + def add_validator_to_registry( - state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64 + state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: Uint64 ) -> None: index = get_index_for_new_validator(state) validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount) @@ -67,7 +67,7 @@ # [New in Altair] set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) - set_or_append_list(state.inactivity_scores, index, uint64(0)) + set_or_append_list(state.inactivity_scores, index, Uint64(0)) - name: add_validator_to_registry#electra @@ -75,9 +75,9 @@ - file: beacon-chain/core/electra/deposits.go search: func AddValidatorToRegistry( spec: | - + def add_validator_to_registry( - state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64 + state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: Uint64 ) -> None: index = get_index_for_new_validator(state) # [Modified in Electra:EIP7251] @@ -86,7 +86,7 @@ set_or_append_list(state.balances, index, amount) set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) - set_or_append_list(state.inactivity_scores, index, uint64(0)) + set_or_append_list(state.inactivity_scores, index, Uint64(0)) - name: adjust_committee_weight_estimate_to_ensure_safety#phase0 @@ -107,12 +107,12 @@ - file: beacon-chain/core/altair/deposit.go search: func ApplyDeposit( spec: | - + def apply_deposit( state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, - amount: uint64, + amount: Uint64, signature: BLSSignature, ) -> None: validator_pubkeys = [v.pubkey for v in state.validators] @@ -139,12 +139,12 @@ - file: beacon-chain/core/electra/deposits.go search: func ApplyDeposit( spec: | - + def apply_deposit( state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, - amount: uint64, + amount: Uint64, signature: BLSSignature, ) -> None: validator_pubkeys = [v.pubkey for v in state.validators] @@ -199,7 +199,7 @@ - file: beacon-chain/core/gloas/parent_payload.go search: func ApplyParentExecutionPayload( spec: | - + def apply_parent_execution_payload( state: BeaconState, requests: ExecutionRequests, @@ -208,6 +208,11 @@ parent_slot = parent_bid.slot parent_epoch = compute_epoch_at_slot(parent_slot) + assert len(requests.withdrawals) <= MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD + assert len(requests.consolidations) <= MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD + assert len(requests.builder_deposits) <= MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD + assert len(requests.builder_exits) <= MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD + # Process execution requests from parent's payload. The execution # requests are processed at state.slot (child's slot), not the parent's slot. def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: @@ -217,9 +222,7 @@ for_ops(requests.deposits, process_deposit_request) for_ops(requests.withdrawals, process_withdrawal_request) for_ops(requests.consolidations, process_consolidation_request) - # [New in Gloas:EIP8282] for_ops(requests.builder_deposits, process_builder_deposit_request) - # [New in Gloas:EIP8282] for_ops(requests.builder_exits, process_builder_exit_request) # Settle the builder payment @@ -478,19 +481,19 @@ - file: encoding/bytesutil/integers.go search: func FromBytes8( spec: | - - def bytes_to_uint64(data: bytes) -> uint64: + + def bytes_to_uint64(data: bytes) -> Uint64: """ Return the integer deserialization of ``data`` interpreted as ``ENDIANNESS``-endian. """ - return uint64(int.from_bytes(data, ENDIANNESS)) + return Uint64(int.from_bytes(data, ENDIANNESS)) - name: calculate_committee_fraction#phase0 sources: [] spec: | - - def calculate_committee_fraction(state: BeaconState, committee_percent: uint64) -> Gwei: + + def calculate_committee_fraction(state: BeaconState, committee_percent: Uint64) -> Gwei: committee_weight = get_total_active_balance(state) // SLOTS_PER_EPOCH return Gwei((committee_weight * committee_percent) // 100) @@ -565,23 +568,23 @@ - name: compute_attestation_subnet_prefix_bits#phase0 sources: [] spec: | - - def compute_attestation_subnet_prefix_bits() -> uint64: + + def compute_attestation_subnet_prefix_bits() -> Uint64: """ Return the number of NodeId bits to use when mapping to a subscribed subnet. """ - return uint64(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS) + return Uint64(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS) - name: compute_balance_weighted_selection#gloas sources: [] spec: | - + def compute_balance_weighted_selection( state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32, - size: uint64, + size: Uint64, shuffle_indices: bool, ) -> Sequence[ValidatorIndex]: """ @@ -591,11 +594,11 @@ ``indices`` is traversed in order. The returned list can contain duplicates. """ MAX_RANDOM_VALUE = 2**16 - 1 - total = uint64(len(indices)) + total = Uint64(len(indices)) assert total > 0 effective_balances = [state.validators[index].effective_balance for index in indices] - selected: List[ValidatorIndex] = [] - i = uint64(0) + selected: list[ValidatorIndex] = [] + i = Uint64(0) while len(selected) < size: offset = i % 16 * 2 if offset == 0: @@ -631,17 +634,17 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func ComputeCommittee( spec: | - + def compute_committee( - indices: Sequence[ValidatorIndex], seed: Bytes32, index: uint64, count: uint64 + indices: Sequence[ValidatorIndex], seed: Bytes32, index: Uint64, count: Uint64 ) -> Sequence[ValidatorIndex]: """ Return the committee corresponding to ``indices``, ``seed``, ``index``, and committee ``count``. """ start = (len(indices) * index) // count - end = (len(indices) * uint64(index + 1)) // count + end = (len(indices) * Uint64(index + 1)) // count return [ - indices[compute_shuffled_index(uint64(i), uint64(len(indices)), seed)] + indices[compute_shuffled_index(Uint64(i), Uint64(len(indices)), seed)] for i in range(start, end) ] @@ -859,7 +862,7 @@ - file: config/params/config.go search: func entryWithForkDigest( spec: | - + def compute_fork_digest( genesis_validators_root: Root, epoch: Epoch, @@ -885,8 +888,8 @@ xor( base_digest, hash( - uint_to_bytes(uint64(blob_parameters.epoch)) - + uint_to_bytes(uint64(blob_parameters.max_blobs_per_block)) + uint_to_bytes(Uint64(blob_parameters.epoch)) + + uint_to_bytes(Uint64(blob_parameters.max_blobs_per_block)) ), ) )[:4] @@ -1131,7 +1134,7 @@ - name: compute_matrix#fulu sources: [] spec: | - + def compute_matrix(blobs: Sequence[Blob]) -> Sequence[MatrixEntry]: """ Return the full, flattened sequence of matrix entries. @@ -1141,7 +1144,7 @@ """ matrix = [] for blob_index, blob in enumerate(blobs): - cells, proofs = compute_cells_and_kzg_proofs(blob) + cells, proofs = kzg.compute_cells_and_kzg_proofs(blob) for cell_index, (cell, proof) in enumerate(zip(cells, proofs, strict=True)): matrix.append( MatrixEntry( @@ -1157,43 +1160,43 @@ - name: compute_max_request_blob_sidecars#deneb sources: [] spec: | - - def compute_max_request_blob_sidecars() -> uint64: + + def compute_max_request_blob_sidecars() -> Uint64: """ Return the maximum number of blob sidecars in a single request. """ - return uint64(MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK) + return Uint64(MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK) - name: compute_max_request_blob_sidecars#electra sources: [] spec: | - - def compute_max_request_blob_sidecars() -> uint64: + + def compute_max_request_blob_sidecars() -> Uint64: """ Return the maximum number of blob sidecars in a single request. """ # [Modified in Electra:EIP7691] - return uint64(MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA) + return Uint64(MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA) - name: compute_max_request_data_column_sidecars#fulu sources: [] spec: | - - def compute_max_request_data_column_sidecars() -> uint64: + + def compute_max_request_data_column_sidecars() -> Uint64: """ Return the maximum number of data column sidecars in a single request. """ - return uint64(MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS) + return Uint64(MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS) - name: compute_merkle_branch_root#phase0 sources: [] spec: | - + def compute_merkle_branch_root( - leaf: Bytes32, branch: Sequence[Bytes32], depth: uint64, index: uint64 + leaf: Bytes32, branch: Sequence[Bytes32], depth: Uint64, index: Uint64 ) -> Root: """ Return the Merkle root obtained by hashing ``leaf`` at ``index`` with ``branch``. @@ -1217,12 +1220,12 @@ - name: compute_min_epochs_for_block_requests#phase0 sources: [] spec: | - - def compute_min_epochs_for_block_requests() -> uint64: + + def compute_min_epochs_for_block_requests() -> Uint64: """ Return the minimum epoch range over which a node must serve blocks. """ - return uint64(MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2) + return Uint64(MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2) - name: compute_new_state_root#phase0 @@ -1243,14 +1246,14 @@ - file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer_attestations_electra.go search: func computeOnChainAggregate( spec: | - + def compute_on_chain_aggregate(network_aggregates: Sequence[Attestation]) -> Attestation: aggregates = sorted( network_aggregates, key=lambda a: get_committee_indices(a.committee_bits)[0] ) data = aggregates[0].data - aggregation_bits = Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT]() + aggregation_bits = AggregationBits() for a in aggregates: for b in a.aggregation_bits: aggregation_bits.append(b) @@ -1259,7 +1262,7 @@ committee_indices = [get_committee_indices(a.committee_bits)[0] for a in aggregates] committee_flags = [(index in committee_indices) for index in range(MAX_COMMITTEES_PER_SLOT)] - committee_bits = Bitvector[MAX_COMMITTEES_PER_SLOT](committee_flags) + committee_bits = CommitteeBits(committee_flags) return Attestation( aggregation_bits=aggregation_bits, @@ -1274,7 +1277,7 @@ - file: beacon-chain/core/helpers/validators.go search: func ComputeProposerIndex( spec: | - + def compute_proposer_index( state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32 ) -> ValidatorIndex: @@ -1283,11 +1286,11 @@ """ assert len(indices) > 0 MAX_RANDOM_BYTE = 2**8 - 1 - i = uint64(0) - total = uint64(len(indices)) + i = Uint64(0) + total = Uint64(len(indices)) while True: candidate_index = indices[compute_shuffled_index(i % total, total, seed)] - random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32] + random_byte = hash(seed + uint_to_bytes(Uint64(i // 32)))[i % 32] effective_balance = state.validators[candidate_index].effective_balance if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: return candidate_index @@ -1301,7 +1304,7 @@ - file: beacon-chain/core/helpers/validators.go search: if bState.Version() >= version.Electra { spec: | - + def compute_proposer_index( state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32 ) -> ValidatorIndex: @@ -1311,8 +1314,8 @@ assert len(indices) > 0 # [Modified in Electra] MAX_RANDOM_VALUE = 2**16 - 1 - i = uint64(0) - total = uint64(len(indices)) + i = Uint64(0) + total = Uint64(len(indices)) while True: candidate_index = indices[compute_shuffled_index(i % total, total, seed)] # [Modified in Electra] @@ -1331,35 +1334,35 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func PrecomputeProposerIndices( spec: | - + def compute_proposer_indices( state: BeaconState, epoch: Epoch, seed: Bytes32, indices: Sequence[ValidatorIndex] - ) -> Vector[ValidatorIndex, SLOTS_PER_EPOCH]: + ) -> ProposerIndices: """ Return the proposer indices for the given ``epoch``. """ start_slot = compute_start_slot_at_epoch(epoch) seeds = [hash(seed + uint_to_bytes(Slot(start_slot + i))) for i in range(SLOTS_PER_EPOCH)] - return [compute_proposer_index(state, indices, seed) for seed in seeds] + return ProposerIndices(compute_proposer_index(state, indices, seed) for seed in seeds) - name: compute_proposer_indices#gloas sources: [] spec: | - + def compute_proposer_indices( state: BeaconState, epoch: Epoch, seed: Bytes32, indices: Sequence[ValidatorIndex] - ) -> Vector[ValidatorIndex, SLOTS_PER_EPOCH]: + ) -> ProposerIndices: """ Return the proposer indices for the given ``epoch``. """ start_slot = compute_start_slot_at_epoch(epoch) seeds = [hash(seed + uint_to_bytes(Slot(start_slot + i))) for i in range(SLOTS_PER_EPOCH)] # [Modified in Gloas:EIP7732] - return [ + return ProposerIndices( compute_balance_weighted_selection(state, indices, seed, size=1, shuffle_indices=True)[0] for seed in seeds - ] + ) - name: compute_proposer_score#phase0 @@ -1374,21 +1377,23 @@ - name: compute_ptc#gloas sources: [] spec: | - - def compute_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: + + def compute_ptc(state: BeaconState, slot: Slot) -> PTC: """ Get the payload timeliness committee, with possible duplicates, for the given ``slot``. """ epoch = compute_epoch_at_slot(slot) seed = hash(get_seed(state, epoch, DOMAIN_PTC_ATTESTER) + uint_to_bytes(slot)) - indices: List[ValidatorIndex] = [] + indices: list[ValidatorIndex] = [] # Concatenate all committees for this slot in order committees_per_slot = get_committee_count_per_slot(state, epoch) for i in range(committees_per_slot): committee = get_beacon_committee(state, slot, CommitteeIndex(i)) indices.extend(committee) - return compute_balance_weighted_selection( - state, indices, seed, size=PTC_SIZE, shuffle_indices=False + return PTC( + compute_balance_weighted_selection( + state, indices, seed, size=PTC_SIZE, shuffle_indices=False + ) ) @@ -1446,8 +1451,8 @@ - file: beacon-chain/core/helpers/shuffle.go search: func ComputeShuffledIndex( spec: | - - def compute_shuffled_index(index: uint64, index_count: uint64, seed: Bytes32) -> uint64: + + def compute_shuffled_index(index: Uint64, index_count: Uint64, seed: Bytes32) -> Uint64: """ Return the shuffled index corresponding to ``seed`` (and ``index_count``). """ @@ -1458,18 +1463,18 @@ - name: compute_shuffled_permutation#phase0 sources: [] spec: | - - def compute_shuffled_permutation(index_count: uint64, seed: Bytes32) -> Sequence[uint64]: + + def compute_shuffled_permutation(index_count: Uint64, seed: Bytes32) -> Sequence[Uint64]: """ Return the full shuffled permutation corresponding to ``seed`` (and ``index_count``). """ # Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf) # See the 'generalized domain' algorithm on page 3 - indices = [uint64(i) for i in range(index_count)] + indices = [Uint64(i) for i in range(index_count)] for current_round in range(SHUFFLE_ROUND_COUNT): round_bytes = current_round.to_bytes(1, "little") pivot = int.from_bytes(hash(seed + round_bytes)[0:8], "little") % index_count - source_by_bucket: Dict[uint64, Bytes32] = {} + source_by_bucket: Dict[Uint64, Bytes32] = {} for i in range(index_count): flip = (pivot + index_count - indices[i]) % index_count position = max(indices[i], flip) @@ -1485,6 +1490,16 @@ return indices +- name: compute_shuffling_dependent_slot#phase0 + sources: [] + spec: | + + def compute_shuffling_dependent_slot(epoch: Epoch) -> Slot: + if epoch <= MIN_SEED_LOOKAHEAD: + return GENESIS_SLOT + return compute_start_slot_at_epoch(epoch - MIN_SEED_LOOKAHEAD) - Slot(1) + + - name: compute_signed_block_header#deneb sources: - file: consensus-types/interfaces/utils.go @@ -1549,15 +1564,15 @@ - file: beacon-chain/core/helpers/attestation.go search: func ComputeSubnetForAttestation( spec: | - + def compute_subnet_for_attestation( - committees_per_slot: uint64, slot: Slot, committee_index: CommitteeIndex + committees_per_slot: Uint64, slot: Slot, committee_index: CommitteeIndex ) -> SubnetID: """ Compute the correct subnet for an attestation for Phase 0. Note, this mimics expected future behavior where attestations will be mapped to their shard subnet. """ - slots_since_epoch_start = uint64(slot % SLOTS_PER_EPOCH) + slots_since_epoch_start = Uint64(slot % SLOTS_PER_EPOCH) committees_since_epoch_start = committees_per_slot * slots_since_epoch_start return SubnetID((committees_since_epoch_start + committee_index) % ATTESTATION_SUBNET_COUNT) @@ -1627,13 +1642,13 @@ - file: beacon-chain/p2p/subnets.go search: func computeSubscribedSubnet( spec: | - + def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID: prefix_bits = int(compute_attestation_subnet_prefix_bits()) - node_id_prefix = node_id >> (NODE_ID_BITS - prefix_bits) - node_offset = node_id % EPOCHS_PER_SUBNET_SUBSCRIPTION + node_id_prefix = node_id >> int(NODE_ID_BITS - prefix_bits) + node_offset = Uint64(node_id % Uint256(EPOCHS_PER_SUBNET_SUBSCRIPTION)) permutation_seed = hash( - uint_to_bytes(uint64((epoch + node_offset) // EPOCHS_PER_SUBNET_SUBSCRIPTION)) + uint_to_bytes(Uint64((epoch + node_offset) // EPOCHS_PER_SUBNET_SUBSCRIPTION)) ) permutated_prefix = compute_shuffled_index( node_id_prefix, @@ -1658,16 +1673,16 @@ - file: time/slots/slottime.go search: func SyncCommitteePeriod( spec: | - - def compute_sync_committee_period(epoch: Epoch) -> uint64: + + def compute_sync_committee_period(epoch: Epoch) -> Uint64: return epoch // EPOCHS_PER_SYNC_COMMITTEE_PERIOD - name: compute_sync_committee_period_at_slot#altair sources: [] spec: | - - def compute_sync_committee_period_at_slot(slot: Slot) -> uint64: + + def compute_sync_committee_period_at_slot(slot: Slot) -> Uint64: return compute_sync_committee_period(compute_epoch_at_slot(slot)) @@ -1676,22 +1691,22 @@ - file: time/slots/slottime.go search: func StartTime( spec: | - - def compute_time_at_slot(state: BeaconState, slot: Slot) -> uint64: + + def compute_time_at_slot(state: BeaconState, slot: Slot) -> Uint64: slots_since_genesis = slot - GENESIS_SLOT - return uint64(state.genesis_time + slots_since_genesis * SLOT_DURATION_MS // 1000) + return Uint64(state.genesis_time + slots_since_genesis * SLOT_DURATION_MS // 1000) - name: compute_time_at_slot_ms#phase0 sources: [] spec: | - - def compute_time_at_slot_ms(state: BeaconState, slot: Slot) -> uint64: + + def compute_time_at_slot_ms(store: Store, slot: Slot) -> Uint64: """ Return the time in milliseconds at the start of the given slot. """ slots_since_genesis = slot - GENESIS_SLOT - return uint64(state.genesis_time * 1000 + slots_since_genesis * SLOT_DURATION_MS) + return Uint64(store.genesis_time * 1000 + slots_since_genesis * SLOT_DURATION_MS) - name: compute_weak_subjectivity_period#phase0 @@ -1699,8 +1714,8 @@ - file: beacon-chain/core/helpers/weak_subjectivity.go search: func ComputeWeakSubjectivityPeriod( spec: | - - def compute_weak_subjectivity_period(state: BeaconState) -> uint64: + + def compute_weak_subjectivity_period(state: BeaconState) -> Uint64: """ Returns the weak subjectivity period for the current ``state``. This computation takes into account the effect of: @@ -1732,8 +1747,8 @@ - name: compute_weak_subjectivity_period#electra sources: [] spec: | - - def compute_weak_subjectivity_period(state: BeaconState) -> uint64: + + def compute_weak_subjectivity_period(state: BeaconState) -> Uint64: """ Returns the weak subjectivity period for the current ``state``. This computation takes into account the effect of: @@ -1750,8 +1765,8 @@ - name: compute_weak_subjectivity_period#gloas sources: [] spec: | - - def compute_weak_subjectivity_period(state: BeaconState) -> uint64: + + def compute_weak_subjectivity_period(state: BeaconState) -> Uint64: """ Returns the weak subjectivity period for the current ``state``. This computation takes into account the effect of: @@ -1846,7 +1861,7 @@ - file: beacon-chain/light-client/lightclient.go search: func NewLightClientUpdateFromBeaconState( spec: | - + def create_light_client_update( state: BeaconState, block: SignedBeaconBlock, @@ -1856,7 +1871,7 @@ ) -> LightClientUpdate: assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH assert ( - sum(block.message.body.sync_aggregate.sync_committee_bits) + get_set_bit_count(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS ) @@ -1932,6 +1947,21 @@ return CURRENT_SYNC_COMMITTEE_GINDEX +- name: current_sync_committee_gindex_at_slot#gloas + sources: [] + spec: | + + def current_sync_committee_gindex_at_slot(slot: Slot) -> GeneralizedIndex: + epoch = compute_epoch_at_slot(slot) + + # [Modified in Gloas:EIP7688] + if epoch >= GLOAS_FORK_EPOCH: + return CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS + if epoch >= ELECTRA_FORK_EPOCH: + return CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA + return CURRENT_SYNC_COMMITTEE_GINDEX + + - name: decrease_balance#phase0 sources: - file: beacon-chain/core/helpers/rewards_penalties.go @@ -2106,6 +2136,21 @@ return FINALIZED_ROOT_GINDEX +- name: finalized_root_gindex_at_slot#gloas + sources: [] + spec: | + + def finalized_root_gindex_at_slot(slot: Slot) -> GeneralizedIndex: + epoch = compute_epoch_at_slot(slot) + + # [Modified in Gloas:EIP7688] + if epoch >= GLOAS_FORK_EPOCH: + return FINALIZED_ROOT_GINDEX_GLOAS + if epoch >= ELECTRA_FORK_EPOCH: + return FINALIZED_ROOT_GINDEX_ELECTRA + return FINALIZED_ROOT_GINDEX + + - name: find_latest_confirmed_descendant#phase0 sources: [] spec: | @@ -2302,16 +2347,16 @@ - name: get_aggregate_due_ms#phase0 sources: [] spec: | - - def get_aggregate_due_ms() -> uint64: + + def get_aggregate_due_ms() -> Uint64: return get_slot_component_duration_ms(AGGREGATE_DUE_BPS) - name: get_aggregate_due_ms#gloas sources: [] spec: | - - def get_aggregate_due_ms() -> uint64: + + def get_aggregate_due_ms() -> Uint64: # [Modified in Gloas] return get_slot_component_duration_ms(AGGREGATE_DUE_BPS_GLOAS) @@ -2382,7 +2427,7 @@ - name: get_attestation_component_deltas#phase0 sources: [] spec: | - + def get_attestation_component_deltas( state: BeaconState, attestations: Sequence[PendingAttestation] ) -> Tuple[Sequence[Gwei], Sequence[Gwei]]: @@ -2396,7 +2441,7 @@ attesting_balance = get_total_balance(state, unslashed_attesting_indices) for index in get_eligible_validator_indices(state): if index in unslashed_attesting_indices: - increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from balance totals to avoid uint64 overflow + increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from balance totals to avoid Uint64 overflow if is_in_inactivity_leak(state): # Since full base reward will be canceled out by inactivity penalty deltas, # optimal participation receives full base reward compensation here. @@ -2441,16 +2486,16 @@ - name: get_attestation_due_ms#phase0 sources: [] spec: | - - def get_attestation_due_ms() -> uint64: + + def get_attestation_due_ms() -> Uint64: return get_slot_component_duration_ms(ATTESTATION_DUE_BPS) - name: get_attestation_due_ms#gloas sources: [] spec: | - - def get_attestation_due_ms() -> uint64: + + def get_attestation_due_ms() -> Uint64: # [Modified in Gloas] return get_slot_component_duration_ms(ATTESTATION_DUE_BPS_GLOAS) @@ -2460,9 +2505,9 @@ - file: beacon-chain/core/altair/attestation.go search: func AttestationParticipationFlagIndices( spec: | - + def get_attestation_participation_flag_indices( - state: BeaconState, data: AttestationData, inclusion_delay: uint64 + state: BeaconState, data: AttestationData, inclusion_delay: Uint64 ) -> Sequence[int]: """ Return the flag indices that are satisfied by an attestation. @@ -2502,9 +2547,9 @@ - file: beacon-chain/core/altair/attestation.go search: func AttestationParticipationFlagIndices( spec: | - + def get_attestation_participation_flag_indices( - state: BeaconState, data: AttestationData, inclusion_delay: uint64 + state: BeaconState, data: AttestationData, inclusion_delay: Uint64 ) -> Sequence[int]: """ Return the flag indices that are satisfied by an attestation. @@ -2543,9 +2588,13 @@ - name: get_attestation_participation_flag_indices#gloas sources: [] spec: | - + def get_attestation_participation_flag_indices( - state: BeaconState, data: AttestationData, inclusion_delay: uint64 + state: BeaconState, + data: AttestationData, + inclusion_delay: Uint64, + # [New in Gloas:EIP7732] + parent_slot: Slot, ) -> Sequence[int]: """ Return the flag indices that are satisfied by an attestation. @@ -2567,7 +2616,7 @@ assert data.index == 0 payload_matches = True else: - slot_index = data.slot % SLOTS_PER_HISTORICAL_ROOT + slot_index = parent_slot % SLOTS_PER_HISTORICAL_ROOT payload_index = state.execution_payload_availability[slot_index] payload_matches = data.index == payload_index @@ -2837,10 +2886,8 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func PrecomputeProposerIndices( spec: | - - def get_beacon_proposer_indices( - state: BeaconState, epoch: Epoch - ) -> Vector[ValidatorIndex, SLOTS_PER_EPOCH]: + + def get_beacon_proposer_indices(state: BeaconState, epoch: Epoch) -> ProposerIndices: """ Return the proposer indices for the given ``epoch``. """ @@ -2856,10 +2903,8 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func PrecomputeProposerIndices( spec: | - - def get_beacon_proposer_indices( - state: BeaconState, epoch: Epoch - ) -> Vector[ValidatorIndex, SLOTS_PER_EPOCH]: + + def get_beacon_proposer_indices(state: BeaconState, epoch: Epoch) -> ProposerIndices: """ Return the proposer indices for the given ``epoch``. """ @@ -3023,32 +3068,32 @@ - name: get_builder_payment_quorum_threshold#gloas sources: [] spec: | - - def get_builder_payment_quorum_threshold(state: BeaconState) -> uint64: + + def get_builder_payment_quorum_threshold(state: BeaconState) -> Uint64: """ Calculate the quorum threshold for builder payments. """ per_slot_balance = get_total_active_balance(state) // SLOTS_PER_EPOCH quorum = per_slot_balance * BUILDER_PAYMENT_THRESHOLD_NUMERATOR - return uint64(quorum // BUILDER_PAYMENT_THRESHOLD_DENOMINATOR) + return Uint64(quorum // BUILDER_PAYMENT_THRESHOLD_DENOMINATOR) - name: get_builder_withdrawals#gloas sources: [] spec: | - + def get_builder_withdrawals( state: BeaconState, withdrawal_index: WithdrawalIndex, prior_withdrawals: Sequence[Withdrawal], - ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: + ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: withdrawals_limit = MAX_WITHDRAWALS_PER_PAYLOAD - 1 assert len(prior_withdrawals) <= withdrawals_limit - processed_count: uint64 = 0 - withdrawals: List[Withdrawal] = [] + processed_count: Uint64 = 0 + withdrawals: list[Withdrawal] = [] for withdrawal in state.builder_pending_withdrawals: - all_withdrawals = prior_withdrawals + withdrawals + all_withdrawals = list(prior_withdrawals) + withdrawals has_reached_limit = len(all_withdrawals) >= withdrawals_limit if has_reached_limit: break @@ -3071,22 +3116,22 @@ - name: get_builders_sweep_withdrawals#gloas sources: [] spec: | - + def get_builders_sweep_withdrawals( state: BeaconState, withdrawal_index: WithdrawalIndex, prior_withdrawals: Sequence[Withdrawal], - ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: + ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: epoch = get_current_epoch(state) builders_limit = min(len(state.builders), MAX_BUILDERS_PER_WITHDRAWALS_SWEEP) withdrawals_limit = MAX_WITHDRAWALS_PER_PAYLOAD - 1 assert len(prior_withdrawals) <= withdrawals_limit - processed_count: uint64 = 0 - withdrawals: List[Withdrawal] = [] + processed_count: Uint64 = 0 + withdrawals: list[Withdrawal] = [] builder_index = state.next_withdrawal_builder_index for _ in range(builders_limit): - all_withdrawals = prior_withdrawals + withdrawals + all_withdrawals = list(prior_withdrawals) + withdrawals has_reached_limit = len(all_withdrawals) >= withdrawals_limit if has_reached_limit: break @@ -3182,16 +3227,16 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func SlotCommitteeCount( spec: | - - def get_committee_count_per_slot(state: BeaconState, epoch: Epoch) -> uint64: + + def get_committee_count_per_slot(state: BeaconState, epoch: Epoch) -> Uint64: """ Return the number of committees in each slot for the given ``epoch``. """ return max( - uint64(1), + Uint64(1), min( MAX_COMMITTEES_PER_SLOT, - uint64(len(get_active_validator_indices(state, epoch))) + Uint64(len(get_active_validator_indices(state, epoch))) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, ), @@ -3203,8 +3248,8 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func CommitteeIndices( spec: | - - def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]: + + def get_committee_indices(committee_bits: BitVector) -> Sequence[CommitteeIndex]: return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit] @@ -3275,16 +3320,16 @@ - name: get_contribution_due_ms#altair sources: [] spec: | - - def get_contribution_due_ms() -> uint64: + + def get_contribution_due_ms() -> Uint64: return get_slot_component_duration_ms(CONTRIBUTION_DUE_BPS) - name: get_contribution_due_ms#gloas sources: [] spec: | - - def get_contribution_due_ms() -> uint64: + + def get_contribution_due_ms() -> Uint64: # [Modified in Gloas] return get_slot_component_duration_ms(CONTRIBUTION_DUE_BPS_GLOAS) @@ -3375,21 +3420,36 @@ ) +- name: get_custody_column_bits#gloas + sources: [] + spec: | + + def get_custody_column_bits(node_id: NodeID, custody_group_count: Uint64) -> CustodyColumnBits: + """ + Compute the bitvector of column indices custodied by ``node_id``. + """ + bits = CustodyColumnBits() + for custody_group in get_custody_groups(node_id, custody_group_count): + for column in compute_columns_for_custody_group(custody_group): + bits[column] = True + return bits + + - name: get_custody_groups#fulu sources: - file: beacon-chain/core/peerdas/das_core.go search: func CustodyGroups( spec: | - - def get_custody_groups(node_id: NodeID, custody_group_count: uint64) -> Sequence[CustodyIndex]: + + def get_custody_groups(node_id: NodeID, custody_group_count: Uint64) -> Sequence[CustodyIndex]: assert custody_group_count <= NUMBER_OF_CUSTODY_GROUPS # Skip computation if all groups are custodied if custody_group_count == NUMBER_OF_CUSTODY_GROUPS: return [CustodyIndex(i) for i in range(NUMBER_OF_CUSTODY_GROUPS)] - current_id = uint256(node_id) - custody_groups: List[CustodyIndex] = [] + current_id = Uint256(node_id) + custody_groups: list[CustodyIndex] = [] while len(custody_groups) < custody_group_count: custody_group = CustodyIndex( bytes_to_uint64(hash(uint_to_bytes(current_id))[0:8]) % NUMBER_OF_CUSTODY_GROUPS @@ -3398,7 +3458,7 @@ custody_groups.append(custody_group) if current_id == UINT256_MAX: # Overflow prevention - current_id = uint256(0) + current_id = Uint256(0) else: current_id += 1 @@ -3411,14 +3471,12 @@ - file: beacon-chain/core/peerdas/validator.go search: func DataColumnSidecars( spec: | - + def get_data_column_sidecars( signed_block_header: SignedBeaconBlockHeader, - kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK], - kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH], - cells_and_kzg_proofs: Sequence[ - Tuple[Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]] - ], + kzg_commitments: BlobKZGCommitments, + kzg_commitments_inclusion_proof: KZGCommitmentsInclusionProof, + cells_and_kzg_proofs: Sequence[Tuple[Cells, Proofs]], ) -> Sequence[DataColumnSidecar]: """ Given a signed block header and the commitments, inclusion proof, cells/proofs associated with @@ -3428,7 +3486,8 @@ sidecars = [] for column_index in range(NUMBER_OF_COLUMNS): - column_cells, column_proofs = [], [] + column_cells = DataColumn() + column_proofs = KZGProofs() for cells, proofs in cells_and_kzg_proofs: column_cells.append(cells[column_index]) column_proofs.append(proofs[column_index]) @@ -3448,7 +3507,7 @@ - name: get_data_column_sidecars#gloas sources: [] spec: | - + def get_data_column_sidecars( # [Modified in Gloas:EIP7732] # Removed `signed_block_header` @@ -3460,9 +3519,7 @@ # Removed `kzg_commitments` # [Modified in Gloas:EIP7732] # Removed `kzg_commitments_inclusion_proof` - cells_and_kzg_proofs: Sequence[ - Tuple[Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]] - ], + cells_and_kzg_proofs: Sequence[Tuple[Cells, Proofs]], ) -> Sequence[DataColumnSidecar]: """ Given a beacon block root and the cells/proofs associated with each blob @@ -3471,7 +3528,8 @@ """ sidecars = [] for column_index in range(NUMBER_OF_COLUMNS): - column_cells, column_proofs = [], [] + column_cells = DataColumn() + column_proofs = KZGProofs() for cells, proofs in cells_and_kzg_proofs: column_cells.append(cells[column_index]) column_proofs.append(proofs[column_index]) @@ -3491,12 +3549,10 @@ - name: get_data_column_sidecars_from_block#fulu sources: [] spec: | - + def get_data_column_sidecars_from_block( signed_block: SignedBeaconBlock, - cells_and_kzg_proofs: Sequence[ - Tuple[Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]] - ], + cells_and_kzg_proofs: Sequence[Tuple[Cells, Proofs]], ) -> Sequence[DataColumnSidecar]: """ Given a signed block and the cells/proofs associated with each blob in the @@ -3504,9 +3560,11 @@ """ blob_kzg_commitments = signed_block.message.body.blob_kzg_commitments signed_block_header = compute_signed_block_header(signed_block) - kzg_commitments_inclusion_proof = compute_merkle_proof( - signed_block.message.body, - get_generalized_index(BeaconBlockBody, "blob_kzg_commitments"), + kzg_commitments_inclusion_proof = KZGCommitmentsInclusionProof( + compute_merkle_proof( + signed_block.message.body, + get_generalized_index(BeaconBlockBody, "blob_kzg_commitments"), + ) ) return get_data_column_sidecars( signed_block_header, @@ -3519,12 +3577,10 @@ - name: get_data_column_sidecars_from_block#gloas sources: [] spec: | - + def get_data_column_sidecars_from_block( signed_block: SignedBeaconBlock, - cells_and_kzg_proofs: Sequence[ - Tuple[Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]] - ], + cells_and_kzg_proofs: Sequence[Tuple[Cells, Proofs]], ) -> Sequence[DataColumnSidecar]: """ Given a signed block and the cells/proofs associated with each blob in the @@ -3541,12 +3597,10 @@ - name: get_data_column_sidecars_from_column_sidecar#fulu sources: [] spec: | - + def get_data_column_sidecars_from_column_sidecar( sidecar: DataColumnSidecar, - cells_and_kzg_proofs: Sequence[ - Tuple[Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]] - ], + cells_and_kzg_proofs: Sequence[Tuple[Cells, Proofs]], ) -> Sequence[DataColumnSidecar]: """ Given a data column sidecar and the cells/proofs associated with each blob corresponding @@ -3565,12 +3619,10 @@ - name: get_data_column_sidecars_from_column_sidecar#gloas sources: [] spec: | - + def get_data_column_sidecars_from_column_sidecar( sidecar: DataColumnSidecar, - cells_and_kzg_proofs: Sequence[ - Tuple[Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]] - ], + cells_and_kzg_proofs: Sequence[Tuple[Cells, Proofs]], ) -> Sequence[DataColumnSidecar]: """ Given a data column sidecar and the cells/proofs associated with each blob @@ -3585,40 +3637,6 @@ ) -- name: get_dependent_root#phase0 - sources: [] - spec: | - - def get_dependent_root(store: Store, root: Root) -> Root: - epoch = get_current_store_epoch(store) - if epoch <= MIN_SEED_LOOKAHEAD: - # Genesis block parent - return Root() - - node = ForkChoiceNode(root=root) - dependent_slot = Slot(compute_start_slot_at_epoch(epoch - MIN_SEED_LOOKAHEAD) - 1) - return get_ancestor(store, node, dependent_slot).root - - -- name: get_dependent_root#gloas - sources: [] - spec: | - - def get_dependent_root(store: Store, root: Root) -> Root: - epoch = get_current_store_epoch(store) - if epoch <= MIN_SEED_LOOKAHEAD: - # Genesis block parent - return Root() - - # [Modified in Gloas:EIP7732] - node = ForkChoiceNode( - root=root, - payload_status=PAYLOAD_STATUS_PENDING, - ) - dependent_slot = Slot(compute_start_slot_at_epoch(epoch - MIN_SEED_LOOKAHEAD) - 1) - return get_ancestor(store, node, dependent_slot).root - - - name: get_domain#phase0 sources: - file: beacon-chain/core/signing/domain.go @@ -3698,15 +3716,15 @@ - file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer_deposits.go search: func (vs *Server) deposits( spec: | - - def get_eth1_pending_deposit_count(state: BeaconState) -> uint64: + + def get_eth1_pending_deposit_count(state: BeaconState) -> Uint64: eth1_deposit_index_limit = min( state.eth1_data.deposit_count, state.deposit_requests_start_index ) if state.eth1_deposit_index < eth1_deposit_index_limit: return min(MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index) else: - return uint64(0) + return Uint64(0) - name: get_eth1_vote#phase0 @@ -3832,11 +3850,11 @@ - file: proto/engine/v1/electra.go search: func (ebe *ExecutionBundleElectra) GetDecodedExecutionRequests( spec: | - + def get_execution_requests(execution_requests_list: Sequence[bytes]) -> ExecutionRequests: - deposits = [] - withdrawals = [] - consolidations = [] + deposits = DepositRequests() + withdrawals = WithdrawalRequests() + consolidations = ConsolidationRequests() request_types = [ DEPOSIT_REQUEST_TYPE, @@ -3858,17 +3876,11 @@ prev_request_type = request_type if request_type == DEPOSIT_REQUEST_TYPE: - deposits = ssz_deserialize( - List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], request_data - ) + deposits = ssz_deserialize(DepositRequests, request_data) elif request_type == WITHDRAWAL_REQUEST_TYPE: - withdrawals = ssz_deserialize( - List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], request_data - ) + withdrawals = ssz_deserialize(WithdrawalRequests, request_data) elif request_type == CONSOLIDATION_REQUEST_TYPE: - consolidations = ssz_deserialize( - List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], request_data - ) + consolidations = ssz_deserialize(ConsolidationRequests, request_data) return ExecutionRequests( deposits=deposits, @@ -3880,15 +3892,15 @@ - name: get_execution_requests#gloas sources: [] spec: | - + def get_execution_requests(execution_requests_list: Sequence[bytes]) -> ExecutionRequests: - deposits = [] - withdrawals = [] - consolidations = [] + deposits = DepositRequests() + withdrawals = WithdrawalRequests() + consolidations = ConsolidationRequests() # [New in Gloas:EIP8282] - builder_deposits = [] + builder_deposits = BuilderDepositRequests() # [New in Gloas:EIP8282] - builder_exits = [] + builder_exits = BuilderExitRequests() request_types = [ DEPOSIT_REQUEST_TYPE, @@ -3914,28 +3926,17 @@ prev_request_type = request_type if request_type == DEPOSIT_REQUEST_TYPE: - deposits = ssz_deserialize( - List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], request_data - ) + deposits = ssz_deserialize(DepositRequests, request_data) elif request_type == WITHDRAWAL_REQUEST_TYPE: - withdrawals = ssz_deserialize( - List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], request_data - ) + withdrawals = ssz_deserialize(WithdrawalRequests, request_data) elif request_type == CONSOLIDATION_REQUEST_TYPE: - consolidations = ssz_deserialize( - List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], request_data - ) + consolidations = ssz_deserialize(ConsolidationRequests, request_data) # [New in Gloas:EIP8282] elif request_type == BUILDER_DEPOSIT_REQUEST_TYPE: - builder_deposits = ssz_deserialize( - List[BuilderDepositRequest, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD], - request_data, - ) + builder_deposits = ssz_deserialize(BuilderDepositRequests, request_data) # [New in Gloas:EIP8282] elif request_type == BUILDER_EXIT_REQUEST_TYPE: - builder_exits = ssz_deserialize( - List[BuilderExitRequest, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD], request_data - ) + builder_exits = ssz_deserialize(BuilderExitRequests, request_data) return ExecutionRequests( deposits=deposits, @@ -3953,9 +3954,9 @@ - file: proto/engine/v1/electra.go search: func EncodeExecutionRequests( spec: | - + def get_execution_requests_list(execution_requests: ExecutionRequests) -> Sequence[bytes]: - requests = [ + requests: Sequence[Tuple[Bytes1, List]] = [ (DEPOSIT_REQUEST_TYPE, execution_requests.deposits), (WITHDRAWAL_REQUEST_TYPE, execution_requests.withdrawals), (CONSOLIDATION_REQUEST_TYPE, execution_requests.consolidations), @@ -3971,9 +3972,9 @@ - name: get_execution_requests_list#gloas sources: [] spec: | - + def get_execution_requests_list(execution_requests: ExecutionRequests) -> Sequence[bytes]: - requests = [ + requests: Sequence[Tuple[Bytes1, ProgressiveList]] = [ (DEPOSIT_REQUEST_TYPE, execution_requests.deposits), (WITHDRAWAL_REQUEST_TYPE, execution_requests.withdrawals), (CONSOLIDATION_REQUEST_TYPE, execution_requests.consolidations), @@ -4011,10 +4012,10 @@ - file: beacon-chain/state/state-native/getters_withdrawal.go search: func (b *BeaconState) ExpectedWithdrawals( spec: | - + def get_expected_withdrawals(state: BeaconState) -> ExpectedWithdrawals: withdrawal_index = state.next_withdrawal_index - withdrawals: List[Withdrawal] = [] + withdrawals: list[Withdrawal] = [] # Get validators sweep withdrawals validators_sweep_withdrawals, withdrawal_index, processed_validators_sweep_count = ( @@ -4033,10 +4034,10 @@ - file: beacon-chain/state/state-native/getters_withdrawal.go search: func (b *BeaconState) ExpectedWithdrawals( spec: | - + def get_expected_withdrawals(state: BeaconState) -> ExpectedWithdrawals: withdrawal_index = state.next_withdrawal_index - withdrawals: List[Withdrawal] = [] + withdrawals: list[Withdrawal] = [] # [New in Electra:EIP7251] # Get partial withdrawals @@ -4062,10 +4063,10 @@ - name: get_expected_withdrawals#gloas sources: [] spec: | - + def get_expected_withdrawals(state: BeaconState) -> ExpectedWithdrawals: withdrawal_index = state.next_withdrawal_index - withdrawals: List[Withdrawal] = [] + withdrawals: list[Withdrawal] = [] # [New in Gloas:EIP7732] # Get builder withdrawals @@ -4140,8 +4141,8 @@ - file: beacon-chain/core/helpers/rewards_penalties.go search: func FinalityDelay( spec: | - - def get_finality_delay(state: BeaconState) -> uint64: + + def get_finality_delay(state: BeaconState) -> Uint64: return get_previous_epoch(state) - state.finalized_checkpoint.epoch @@ -4183,7 +4184,7 @@ - name: get_forkchoice_store#phase0 sources: [] spec: | - + def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: assert anchor_block.state_root == hash_tree_root(anchor_state) anchor_root = hash_tree_root(anchor_block) @@ -4192,7 +4193,7 @@ finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root) proposer_boost_root = Root() return Store( - time=uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), + time=Uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), genesis_time=anchor_state.genesis_time, justified_checkpoint=justified_checkpoint, finalized_checkpoint=finalized_checkpoint, @@ -4202,7 +4203,9 @@ equivocating_indices=set(), blocks={anchor_root: copy(anchor_block)}, block_states={anchor_root: copy(anchor_state)}, + block_timeliness={}, checkpoint_states={justified_checkpoint: copy(anchor_state)}, + latest_messages={}, unrealized_justifications={anchor_root: justified_checkpoint}, ) @@ -4210,7 +4213,7 @@ - name: get_forkchoice_store#gloas sources: [] spec: | - + def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: assert anchor_block.state_root == hash_tree_root(anchor_state) anchor_root = hash_tree_root(anchor_block) @@ -4219,7 +4222,7 @@ finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root) proposer_boost_root = Root() return Store( - time=uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), + time=Uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), genesis_time=anchor_state.genesis_time, justified_checkpoint=justified_checkpoint, finalized_checkpoint=finalized_checkpoint, @@ -4232,6 +4235,7 @@ # [New in Gloas:EIP7732] block_timeliness={anchor_root: [True, True]}, checkpoint_states={justified_checkpoint: copy(anchor_state)}, + latest_messages={}, unrealized_justifications={anchor_root: justified_checkpoint}, # [New in Gloas:EIP7732] payloads={}, @@ -4245,7 +4249,7 @@ - name: get_forkchoice_store#heze sources: [] spec: | - + def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: assert anchor_block.state_root == hash_tree_root(anchor_state) anchor_root = hash_tree_root(anchor_block) @@ -4254,7 +4258,7 @@ finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root) proposer_boost_root = Root() return Store( - time=uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), + time=Uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), genesis_time=anchor_state.genesis_time, justified_checkpoint=justified_checkpoint, finalized_checkpoint=finalized_checkpoint, @@ -4266,6 +4270,7 @@ block_states={anchor_root: copy(anchor_state)}, block_timeliness={anchor_root: [True, True]}, checkpoint_states={justified_checkpoint: copy(anchor_state)}, + latest_messages={}, unrealized_justifications={anchor_root: justified_checkpoint}, payloads={}, payload_timeliness_vote={}, @@ -4457,26 +4462,54 @@ return rewards, penalties +- name: get_inclusion_list_bits#heze + sources: [] + spec: | + + def get_inclusion_list_bits( + store: InclusionListStore, + committee: InclusionListCommittee, + slot: Slot, + dependent_root: Root, + only_timely: bool = True, + ) -> InclusionListBits: + key = (slot, dependent_root) + inclusion_lists = store.inclusion_lists[key] + equivocators = store.equivocators[key] + + validator_indices = [] + for validator_index, inclusion_list in inclusion_lists.items(): + # Ignore inclusion lists from equivocators + if validator_index in equivocators: + continue + + # Ignore untimely inclusion lists if only timely ones are requested + if only_timely and not inclusion_list.timely: + continue + + validator_indices.append(validator_index) + + return InclusionListBits(validator_index in validator_indices for validator_index in committee) + + - name: get_inclusion_list_committee#heze sources: [] spec: | - - def get_inclusion_list_committee( - state: BeaconState, slot: Slot - ) -> Vector[ValidatorIndex, INCLUSION_LIST_COMMITTEE_SIZE]: + + def get_inclusion_list_committee(state: BeaconState, slot: Slot) -> InclusionListCommittee: """ Get the inclusion list committee for the given ``slot``. """ epoch = compute_epoch_at_slot(slot) - indices: List[ValidatorIndex] = [] + indices: list[ValidatorIndex] = [] # Concatenate all committees for this slot in order committees_per_slot = get_committee_count_per_slot(state, epoch) for i in range(committees_per_slot): committee = get_beacon_committee(state, slot, CommitteeIndex(i)) indices.extend(committee) - return Vector[ValidatorIndex, INCLUSION_LIST_COMMITTEE_SIZE]([ + return InclusionListCommittee( indices[i % len(indices)] for i in range(INCLUSION_LIST_COMMITTEE_SIZE) - ]) + ) - name: get_inclusion_list_committee_assignment#heze @@ -4504,8 +4537,8 @@ - name: get_inclusion_list_due_ms#heze sources: [] spec: | - - def get_inclusion_list_due_ms() -> uint64: + + def get_inclusion_list_due_ms() -> Uint64: return get_slot_component_duration_ms(INCLUSION_LIST_DUE_BPS) @@ -4539,24 +4572,25 @@ - name: get_inclusion_list_transactions#heze sources: [] spec: | - + def get_inclusion_list_transactions( - store: InclusionListStore, state: BeaconState, slot: Slot, only_timely: bool = True + store: InclusionListStore, slot: Slot, dependent_root: Root, only_timely: bool = True ) -> Sequence[Transaction]: - committee = get_inclusion_list_committee(state, slot) - key = hash_tree_root(committee) - + key = (slot, dependent_root) inclusion_lists = store.inclusion_lists[key] equivocators = store.equivocators[key] - timeliness = store.inclusion_list_timeliness - - transactions = [ - transaction - for inclusion_list_root in inclusion_lists - if inclusion_lists[inclusion_list_root].validator_index not in equivocators - if not only_timely or timeliness[inclusion_list_root] - for transaction in inclusion_lists[inclusion_list_root].transactions - ] + + transactions: list[Transaction] = [] + for validator_index, inclusion_list in inclusion_lists.items(): + # Ignore inclusion lists from equivocators + if validator_index in equivocators: + continue + + # Ignore untimely inclusion lists if only timely ones are requested + if only_timely and not inclusion_list.timely: + continue + + transactions.extend(inclusion_list.signed_inclusion_list.message.transactions) # Deduplicate inclusion list transactions. Order does not need to be preserved. return list(set(transactions)) @@ -4586,7 +4620,7 @@ - file: proto/prysm/v1alpha1/attestation/attestation_utils.go search: func ConvertToIndexed( spec: | - + def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> IndexedAttestation: """ Return the indexed attestation corresponding to ``attestation``. @@ -4594,7 +4628,7 @@ attesting_indices = get_attesting_indices(state, attestation) return IndexedAttestation( - attesting_indices=sorted(attesting_indices), + attesting_indices=AttestingIndices(sorted(attesting_indices)), data=attestation.data, signature=attestation.signature, ) @@ -4603,7 +4637,7 @@ - name: get_indexed_payload_attestation#gloas sources: [] spec: | - + def get_indexed_payload_attestation( state: BeaconState, payload_attestation: PayloadAttestation ) -> IndexedPayloadAttestation: @@ -4616,7 +4650,7 @@ attesting_indices = [index for i, index in enumerate(ptc) if bits[i]] return IndexedPayloadAttestation( - attesting_indices=sorted(attesting_indices), + attesting_indices=PTCAttestingIndices(sorted(attesting_indices)), data=payload_attestation.data, signature=payload_attestation.signature, ) @@ -4899,7 +4933,7 @@ - file: beacon-chain/core/altair/sync_committee.go search: func NextSyncCommitteeIndices( spec: | - + def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]: """ Return the sync committee indices, with possible duplicates, for the next sync committee. @@ -4908,16 +4942,16 @@ MAX_RANDOM_BYTE = 2**8 - 1 active_validator_indices = get_active_validator_indices(state, epoch) - active_validator_count = uint64(len(active_validator_indices)) + active_validator_count = Uint64(len(active_validator_indices)) seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE) i = 0 - sync_committee_indices: List[ValidatorIndex] = [] + sync_committee_indices: list[ValidatorIndex] = [] while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE: shuffled_index = compute_shuffled_index( - uint64(i % active_validator_count), active_validator_count, seed + Uint64(i % active_validator_count), active_validator_count, seed ) candidate_index = active_validator_indices[shuffled_index] - random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32] + random_byte = hash(seed + uint_to_bytes(Uint64(i // 32)))[i % 32] effective_balance = state.validators[candidate_index].effective_balance if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: sync_committee_indices.append(candidate_index) @@ -4932,7 +4966,7 @@ - file: beacon-chain/core/altair/sync_committee.go search: if s.Version() >= version.Electra { spec: | - + def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]: """ Return the sync committee indices, with possible duplicates, for the next sync committee. @@ -4942,13 +4976,13 @@ # [Modified in Electra] MAX_RANDOM_VALUE = 2**16 - 1 active_validator_indices = get_active_validator_indices(state, epoch) - active_validator_count = uint64(len(active_validator_indices)) + active_validator_count = Uint64(len(active_validator_indices)) seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE) - i = uint64(0) - sync_committee_indices: List[ValidatorIndex] = [] + i = Uint64(0) + sync_committee_indices: list[ValidatorIndex] = [] while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE: shuffled_index = compute_shuffled_index( - uint64(i % active_validator_count), active_validator_count, seed + Uint64(i % active_validator_count), active_validator_count, seed ) candidate_index = active_validator_indices[shuffled_index] # [Modified in Electra] @@ -5045,8 +5079,8 @@ - name: get_payload_attestation_due_ms#gloas sources: [] spec: | - - def get_payload_attestation_due_ms() -> uint64: + + def get_payload_attestation_due_ms() -> Uint64: return get_slot_component_duration_ms(PAYLOAD_ATTESTATION_DUE_BPS) @@ -5065,16 +5099,16 @@ - name: get_payload_due_ms#gloas sources: [] spec: | - - def get_payload_due_ms() -> uint64: + + def get_payload_due_ms() -> Uint64: return get_slot_component_duration_ms(PAYLOAD_DUE_BPS) - name: get_payload_status_tiebreaker#gloas sources: [] spec: | - - def get_payload_status_tiebreaker(store: Store, node: ForkChoiceNode) -> uint8: + + def get_payload_status_tiebreaker(store: Store, node: ForkChoiceNode) -> Uint8: if is_previous_slot_payload_decision(store, node): # To decide on a payload from the previous slot, choose # between FULL and EMPTY based on `should_extend_payload` @@ -5124,12 +5158,12 @@ - name: get_pending_partial_withdrawals#electra sources: [] spec: | - + def get_pending_partial_withdrawals( state: BeaconState, withdrawal_index: WithdrawalIndex, prior_withdrawals: Sequence[Withdrawal], - ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: + ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: epoch = get_current_epoch(state) withdrawals_limit = min( len(prior_withdrawals) + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, @@ -5137,10 +5171,10 @@ ) assert len(prior_withdrawals) <= withdrawals_limit - processed_count: uint64 = 0 - withdrawals: List[Withdrawal] = [] + processed_count: Uint64 = 0 + withdrawals: list[Withdrawal] = [] for withdrawal in state.pending_partial_withdrawals: - all_withdrawals = prior_withdrawals + withdrawals + all_withdrawals = list(prior_withdrawals) + withdrawals is_withdrawable = withdrawal.withdrawable_epoch <= epoch has_reached_limit = len(all_withdrawals) >= withdrawals_limit if not is_withdrawable or has_reached_limit: @@ -5213,23 +5247,68 @@ return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1) -- name: get_proposer_dependent_root#gloas +- name: get_proposer_head#phase0 sources: [] spec: | - - def get_proposer_dependent_root(state: BeaconState, epoch: Epoch) -> Root: - """ - Return the dependent root for the proposer lookahead at ``epoch``. - """ - return get_block_root_at_slot( - state, Slot(compute_start_slot_at_epoch(Epoch(epoch - MIN_SEED_LOOKAHEAD)) - 1) - ) + + def get_proposer_head(store: Store, head_node: ForkChoiceNode, slot: Slot) -> ForkChoiceNode: + head_block = store.blocks[head_node.root] + parent_root = head_block.parent_root + parent_block = store.blocks[parent_root] + parent_node = ForkChoiceNode(root=parent_root) + + # Only re-org the head block if it arrived later than the attestation deadline. + head_late = is_head_late(store, head_node.root) + + # Do not re-org on an epoch boundary where the proposer shuffling could change. + shuffling_stable = is_shuffling_stable(slot) + + # Ensure that the FFG information of the new head will be competitive with the current head. + ffg_competitive = is_ffg_competitive(store, head_node.root, parent_root) + + # Do not re-org if the chain is not finalizing with acceptable frequency. + finalization_ok = is_finalization_ok(store, slot) + + # Only re-org if we are proposing on-time. + proposing_on_time = is_proposing_on_time(store) + + # Only re-org a single slot at most. + parent_slot_ok = parent_block.slot + 1 == head_block.slot + current_time_ok = head_block.slot + 1 == slot + single_slot_reorg = parent_slot_ok and current_time_ok + + # Check that the head has few enough votes to be overpowered by our proposer boost. + assert store.proposer_boost_root != head_node.root # ensure boost has worn off + head_weak = is_head_weak(store, head_node.root) + + # Check that the missing votes are assigned to the parent and not being hoarded. + parent_strong = is_parent_strong(store, head_node.root) + + # Re-org more aggressively if there is a proposer equivocation in the previous slot. + proposer_equivocation = is_proposer_equivocation(store, head_node.root) + + if all([ + head_late, + shuffling_stable, + ffg_competitive, + finalization_ok, + proposing_on_time, + single_slot_reorg, + head_weak, + parent_strong, + ]): + # We can re-org the current head by building upon its parent node. + return parent_node + elif all([head_weak, current_time_ok, proposer_equivocation]): + return parent_node + else: + return head_node -- name: get_proposer_head#phase0 +- name: get_proposer_head#fulu sources: [] spec: | - + def get_proposer_head(store: Store, head_node: ForkChoiceNode, slot: Slot) -> ForkChoiceNode: head_block = store.blocks[head_node.root] parent_root = head_block.parent_root @@ -5239,8 +5318,8 @@ # Only re-org the head block if it arrived later than the attestation deadline. head_late = is_head_late(store, head_node.root) - # Do not re-org on an epoch boundary. - epoch_boundary = is_epoch_boundary(slot) + # [Modified in Fulu:EIP7917] + # Removed `shuffling_stable = is_shuffling_stable(slot)` # Ensure that the FFG information of the new head will be competitive with the current head. ffg_competitive = is_ffg_competitive(store, head_node.root, parent_root) @@ -5268,7 +5347,8 @@ if all([ head_late, - epoch_boundary, + # [Modified in Fulu:EIP7917] + # Removed `shuffling_stable` ffg_competitive, finalization_ok, proposing_on_time, @@ -5287,7 +5367,7 @@ - name: get_proposer_head#gloas sources: [] spec: | - + def get_proposer_head(store: Store, head_node: ForkChoiceNode, slot: Slot) -> ForkChoiceNode: head_block = store.blocks[head_node.root] parent_root = head_block.parent_root @@ -5299,9 +5379,6 @@ # Only re-org the head block if it arrived later than the attestation deadline. head_late = is_head_late(store, head_node.root) - # Do not re-org on an epoch boundary. - epoch_boundary = is_epoch_boundary(slot) - # Ensure that the FFG information of the new head will be competitive with the current head. ffg_competitive = is_ffg_competitive(store, head_node.root, parent_root) @@ -5328,7 +5405,6 @@ if all([ head_late, - epoch_boundary, ffg_competitive, finalization_ok, proposing_on_time, @@ -5344,25 +5420,11 @@ return head_node -- name: get_proposer_preferences_signature#gloas - sources: [] - spec: | - - def get_proposer_preferences_signature( - state: BeaconState, preferences: ProposerPreferences, privkey: int - ) -> BLSSignature: - domain = get_domain( - state, DOMAIN_PROPOSER_PREFERENCES, compute_epoch_at_slot(preferences.proposal_slot) - ) - signing_root = compute_signing_root(preferences, domain) - return bls.Sign(privkey, signing_root) - - - name: get_proposer_reorg_cutoff_ms#phase0 sources: [] spec: | - - def get_proposer_reorg_cutoff_ms() -> uint64: + + def get_proposer_reorg_cutoff_ms() -> Uint64: return get_slot_component_duration_ms(PROPOSER_REORG_CUTOFF_BPS) @@ -5388,8 +5450,8 @@ - name: get_ptc#gloas sources: [] spec: | - - def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: + + def get_ptc(state: BeaconState, slot: Slot) -> PTC: """ Get the payload timeliness committee for the given ``slot``. """ @@ -5478,8 +5540,8 @@ - name: get_safety_threshold#altair sources: [] spec: | - - def get_safety_threshold(store: LightClientStore) -> uint64: + + def get_safety_threshold(store: LightClientStore) -> Uint64: return ( max( store.previous_max_active_participants, @@ -5489,6 +5551,20 @@ ) +- name: get_scheduled_gas_limit#gloas + sources: [] + spec: | + + def get_scheduled_gas_limit(epoch: Epoch) -> Optional[Uint64]: + """ + Return the scheduled gas limit at a given epoch, if any. + """ + for entry in sorted(GAS_LIMIT_SCHEDULE, key=lambda e: e["EPOCH"], reverse=True): + if epoch >= entry["EPOCH"]: + return entry["GAS_LIMIT"] + return None + + - name: get_seed#phase0 sources: - file: beacon-chain/core/helpers/randao.go @@ -5505,6 +5581,40 @@ return hash(domain_type + uint_to_bytes(epoch) + mix) +- name: get_set_bit_count#phase0 + sources: [] + spec: | + + def get_set_bit_count(bits: Sequence[Boolean]) -> Uint64: + """ + Return the number of bits that are set in ``bits``. + """ + return Uint64(sum(1 for bit in bits if bit)) + + +- name: get_signed_inclusion_list#heze + sources: [] + spec: | + + def get_signed_inclusion_list( + store: Store, + state: BeaconState, + head_root: Root, + slot: Slot, + validator_index: ValidatorIndex, + inclusion_list_transactions: Sequence[Transaction], + privkey: int, + ) -> SignedInclusionList: + inclusion_list = InclusionList( + slot=slot, + validator_index=validator_index, + dependent_root=get_shuffling_dependent_root(store, head_root, compute_epoch_at_slot(slot)), + transactions=inclusion_list_transactions, + ) + signature = get_inclusion_list_signature(state, inclusion_list, privkey) + return SignedInclusionList(message=inclusion_list, signature=signature) + + - name: get_slot_committee#phase0 sources: [] spec: | @@ -5525,8 +5635,8 @@ - name: get_slot_component_duration_ms#phase0 sources: [] spec: | - - def get_slot_component_duration_ms(basis_points: uint64) -> uint64: + + def get_slot_component_duration_ms(basis_points: Uint64) -> Uint64: """ Calculate the duration of a slot component in milliseconds. """ @@ -5572,9 +5682,9 @@ - name: get_subtree_index#altair sources: [] spec: | - - def get_subtree_index(generalized_index: GeneralizedIndex) -> uint64: - return uint64(generalized_index % 2 ** (floorlog2(generalized_index))) + + def get_subtree_index(generalized_index: GeneralizedIndex) -> Uint64: + return Uint64(generalized_index % 2 ** (floorlog2(generalized_index))) - name: get_support_discount#phase0 @@ -5647,9 +5757,9 @@ - name: get_sync_committee_selection_proof#altair sources: [] spec: | - + def get_sync_committee_selection_proof( - state: BeaconState, slot: Slot, subcommittee_index: uint64, privkey: int + state: BeaconState, slot: Slot, subcommittee_index: Uint64, privkey: int ) -> BLSSignature: domain = get_domain(state, DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, compute_epoch_at_slot(slot)) signing_data = SyncAggregatorSelectionData( @@ -5663,16 +5773,16 @@ - name: get_sync_message_due_ms#altair sources: [] spec: | - - def get_sync_message_due_ms() -> uint64: + + def get_sync_message_due_ms() -> Uint64: return get_slot_component_duration_ms(SYNC_MESSAGE_DUE_BPS) - name: get_sync_message_due_ms#gloas sources: [] spec: | - - def get_sync_message_due_ms() -> uint64: + + def get_sync_message_due_ms() -> Uint64: # [Modified in Gloas] return get_slot_component_duration_ms(SYNC_MESSAGE_DUE_BPS_GLOAS) @@ -5682,9 +5792,9 @@ - file: beacon-chain/core/altair/sync_committee.go search: func SyncSubCommitteePubkeys( spec: | - + def get_sync_subcommittee_pubkeys( - state: BeaconState, subcommittee_index: uint64 + state: BeaconState, subcommittee_index: Uint64 ) -> Sequence[BLSPubkey]: # Committees assigned to `slot` sign for `slot - 1` # This creates the exceptional logic below when transitioning between sync committee periods @@ -5756,12 +5866,12 @@ - file: beacon-chain/core/helpers/rewards_penalties.go search: func TotalBalance( spec: | - + def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei: """ Return the combined effective balance of the ``indices``. ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero. - Math safe up to ~10B ETH, after which this overflows uint64. + Math safe up to ~10B ETH, after which this overflows Uint64. """ return Gwei( max( @@ -5833,8 +5943,8 @@ - file: beacon-chain/core/helpers/validators.go search: func ValidatorActivationChurnLimitDeneb( spec: | - - def get_validator_activation_churn_limit(state: BeaconState) -> uint64: + + def get_validator_activation_churn_limit(state: BeaconState) -> Uint64: """ Return the validator activation churn limit for the current epoch. """ @@ -5846,14 +5956,14 @@ - file: beacon-chain/core/helpers/validators.go search: func ValidatorExitChurnLimit( spec: | - - def get_validator_churn_limit(state: BeaconState) -> uint64: + + def get_validator_churn_limit(state: BeaconState) -> Uint64: """ Return the validator churn limit for the current epoch. """ active_validator_indices = get_active_validator_indices(state, get_current_epoch(state)) return max( - MIN_PER_EPOCH_CHURN_LIMIT, uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT + MIN_PER_EPOCH_CHURN_LIMIT, Uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT ) @@ -5862,9 +5972,9 @@ - file: beacon-chain/core/altair/deposit.go search: func GetValidatorFromDeposit( spec: | - + def get_validator_from_deposit( - pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64 + pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: Uint64 ) -> Validator: effective_balance = min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) @@ -5885,9 +5995,9 @@ - file: beacon-chain/core/electra/deposits.go search: func GetValidatorFromDeposit( spec: | - + def get_validator_from_deposit( - pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64 + pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: Uint64 ) -> Validator: validator = Validator( pubkey=pubkey, @@ -5914,10 +6024,10 @@ - file: beacon-chain/core/peerdas/validator.go search: func ValidatorsCustodyRequirement( spec: | - + def get_validators_custody_requirement( state: BeaconState, validator_indices: Sequence[ValidatorIndex] - ) -> uint64: + ) -> Uint64: total_node_balance = sum( state.validators[index].effective_balance for index in validator_indices ) @@ -5928,23 +6038,23 @@ - name: get_validators_sweep_withdrawals#capella sources: [] spec: | - + def get_validators_sweep_withdrawals( state: BeaconState, withdrawal_index: WithdrawalIndex, prior_withdrawals: Sequence[Withdrawal], - ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: + ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: epoch = get_current_epoch(state) validators_limit = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) withdrawals_limit = MAX_WITHDRAWALS_PER_PAYLOAD # There must be at least one space reserved for validator sweep withdrawals assert len(prior_withdrawals) < withdrawals_limit - processed_count: uint64 = 0 - withdrawals: List[Withdrawal] = [] + processed_count: Uint64 = 0 + withdrawals: list[Withdrawal] = [] validator_index = state.next_withdrawal_validator_index for _ in range(validators_limit): - all_withdrawals = prior_withdrawals + withdrawals + all_withdrawals = list(prior_withdrawals) + withdrawals has_reached_limit = len(all_withdrawals) >= withdrawals_limit if has_reached_limit: break @@ -5981,23 +6091,23 @@ - name: get_validators_sweep_withdrawals#electra sources: [] spec: | - + def get_validators_sweep_withdrawals( state: BeaconState, withdrawal_index: WithdrawalIndex, prior_withdrawals: Sequence[Withdrawal], - ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, uint64]: + ) -> Tuple[Sequence[Withdrawal], WithdrawalIndex, Uint64]: epoch = get_current_epoch(state) validators_limit = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) withdrawals_limit = MAX_WITHDRAWALS_PER_PAYLOAD # There must be at least one space reserved for validator sweep withdrawals assert len(prior_withdrawals) < withdrawals_limit - processed_count: uint64 = 0 - withdrawals: List[Withdrawal] = [] + processed_count: Uint64 = 0 + withdrawals: list[Withdrawal] = [] validator_index = state.next_withdrawal_validator_index for _ in range(validators_limit): - all_withdrawals = prior_withdrawals + withdrawals + all_withdrawals = list(prior_withdrawals) + withdrawals has_reached_limit = len(all_withdrawals) >= withdrawals_limit if has_reached_limit: break @@ -6178,9 +6288,9 @@ - file: beacon-chain/core/transition/state.go search: func GenesisBeaconState( spec: | - + def initialize_beacon_state_from_eth1( - eth1_block_hash: Hash32, eth1_timestamp: uint64, deposits: Sequence[Deposit] + eth1_block_hash: Hash32, eth1_timestamp: Uint64, deposits: Sequence[Deposit] ) -> BeaconState: fork = Fork( previous_version=GENESIS_FORK_VERSION, @@ -6190,7 +6300,7 @@ state = BeaconState( genesis_time=eth1_timestamp + GENESIS_DELAY, fork=fork, - eth1_data=Eth1Data(deposit_count=uint64(len(deposits)), block_hash=eth1_block_hash), + eth1_data=Eth1Data(deposit_count=Uint64(len(deposits)), block_hash=eth1_block_hash), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy @@ -6199,7 +6309,7 @@ # Process deposits leaves = [deposit.data for deposit in deposits] for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[: index + 1]) + deposit_data_list = DepositDataList(*leaves[: index + 1]) state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) process_deposit(state, deposit) @@ -6254,35 +6364,34 @@ - file: beacon-chain/core/helpers/beacon_committee.go search: func InitializeProposerLookahead( spec: | - + def initialize_proposer_lookahead( state: electra.BeaconState, - ) -> Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]: + ) -> ProposerLookahead: """ Return the proposer indices for the full available lookahead starting from current epoch. Used to initialize the ``proposer_lookahead`` field in the beacon state at genesis and after forks. """ current_epoch = get_current_epoch(state) - lookahead = [] + lookahead: list[ValidatorIndex] = [] for i in range(MIN_SEED_LOOKAHEAD + 1): lookahead.extend(get_beacon_proposer_indices(state, Epoch(current_epoch + i))) - return lookahead + return ProposerLookahead(lookahead) - name: initialize_ptc_window#gloas sources: [] spec: | - + def initialize_ptc_window( state: BeaconState, - ) -> Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH]: + ) -> PTCWindow: """ Return the cached PTC window starting from the current epoch. Used to initialize the ``ptc_window`` field in the beacon state at genesis and after forks. """ empty_previous_epoch = [ - Vector[ValidatorIndex, PTC_SIZE]([ValidatorIndex(0) for _ in range(PTC_SIZE)]) - for _ in range(SLOTS_PER_EPOCH) + PTC([ValidatorIndex(0) for _ in range(PTC_SIZE)]) for _ in range(SLOTS_PER_EPOCH) ] ptcs = [] @@ -6292,7 +6401,7 @@ start_slot = compute_start_slot_at_epoch(epoch) ptcs += [compute_ptc(state, Slot(start_slot + i)) for i in range(SLOTS_PER_EPOCH)] - return empty_previous_epoch + ptcs + return PTCWindow(empty_previous_epoch + ptcs) - name: initiate_builder_exit#gloas @@ -6365,8 +6474,8 @@ - file: math/math_helper.go search: func IntegerSquareRoot( spec: | - - def integer_squareroot(n: uint64) -> uint64: + + def integer_squareroot(n: Uint64) -> Uint64: """ Return the largest integer ``x`` such that ``x**2 <= n``. """ @@ -6491,12 +6600,12 @@ - file: beacon-chain/light-client/lightclient.go search: func IsBetterUpdate( spec: | - + def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdate) -> bool: # Compare supermajority (> 2/3) sync committee participation max_active_participants = len(new_update.sync_aggregate.sync_committee_bits) - new_num_active_participants = sum(new_update.sync_aggregate.sync_committee_bits) - old_num_active_participants = sum(old_update.sync_aggregate.sync_committee_bits) + new_num_active_participants = get_set_bit_count(new_update.sync_aggregate.sync_committee_bits) + old_num_active_participants = get_set_bit_count(old_update.sync_aggregate.sync_committee_bits) new_has_supermajority = new_num_active_participants * 3 >= max_active_participants * 2 old_has_supermajority = old_num_active_participants * 3 >= max_active_participants * 2 if new_has_supermajority != old_has_supermajority: @@ -6545,6 +6654,35 @@ return new_update.signature_slot < old_update.signature_slot +- name: is_bid_compatible_with_head#gloas + sources: [] + spec: | + + def is_bid_compatible_with_head(store: Store, bid: ExecutionPayloadBid) -> bool: + """ + Check if ``bid`` is compatible with the head branch. + """ + head_node = get_head(store) + head_block = store.blocks[head_node.root] + head_bid = head_block.body.signed_execution_payload_bid.message + + builds_on_parent_block = bid.parent_block_root == head_block.parent_root + builds_on_parent_payload = bid.parent_block_hash == head_bid.parent_block_hash + + if builds_on_parent_block and builds_on_parent_payload: + return True + + if bid.parent_block_root != head_node.root: + return False + + builds_on_head_payload = bid.parent_block_hash == head_bid.block_hash + + if should_build_on_full(store, head_node, bid.slot): + return builds_on_head_payload + + return builds_on_parent_payload + + - name: is_builder_index#gloas sources: [] spec: | @@ -6564,8 +6702,8 @@ - name: is_candidate_block#phase0 sources: [] spec: | - - def is_candidate_block(block: Eth1Block, period_start: uint64) -> bool: + + def is_candidate_block(block: Eth1Block, period_start: Uint64) -> bool: return ( block.timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= period_start and block.timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE * 2 >= period_start @@ -6624,20 +6762,56 @@ ) +- name: is_current_or_next_slot#gloas + sources: [] + spec: | + + def is_current_or_next_slot( + store: Store, + slot: Slot, + current_time_ms: Uint64, + ) -> bool: + """ + Check if the given slot is the current slot or the next slot + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). + """ + is_current = is_current_slot(store, slot, current_time_ms) + is_next = is_current_slot(store, Slot(slot - 1), current_time_ms) + return is_current or is_next + + +- name: is_current_or_previous_epoch#deneb + sources: [] + spec: | + + def is_current_or_previous_epoch( + store: Store, + epoch: Epoch, + current_time_ms: Uint64, + ) -> bool: + """ + Check if the given epoch is the current or previous epoch + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). + """ + is_current = is_within_epoch(store, epoch, current_time_ms) + is_previous = is_within_epoch(store, Epoch(epoch + 1), current_time_ms) + return is_current or is_previous + + - name: is_current_slot#altair sources: [] spec: | - + def is_current_slot( - state: BeaconState, + store: Store, slot: Slot, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> bool: """ Check if the given slot is the current slot (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). """ - return is_within_slot_range(state, slot, 0, current_time_ms) + return is_within_slot_range(store, slot, 0, current_time_ms) - name: is_data_available#deneb @@ -6647,7 +6821,7 @@ - file: beacon-chain/blockchain/process_block.go search: func (s *Service) areBlobsAvailable( spec: | - + def is_data_available( beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment] ) -> bool: @@ -6657,7 +6831,7 @@ # `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` blobs, proofs = retrieve_blobs_and_proofs(beacon_block_root) - return verify_blob_kzg_proof_batch(blobs, blob_kzg_commitments, proofs) + return kzg.verify_blob_kzg_proof_batch(blobs, blob_kzg_commitments, proofs) - name: is_data_available#fulu @@ -6750,14 +6924,6 @@ ) -- name: is_epoch_boundary#phase0 - sources: [] - spec: | - - def is_epoch_boundary(slot: Slot) -> bool: - return slot % SLOTS_PER_EPOCH != 0 - - - name: is_execution_block#bellatrix sources: - file: beacon-chain/core/blocks/payload.go @@ -6808,13 +6974,13 @@ - name: is_full_validator_set_covered#phase0 sources: [] spec: | - + def is_full_validator_set_covered(start_slot: Slot, end_slot: Slot) -> bool: """ Return ``True`` if the range between ``start_slot`` and ``end_slot`` (inclusive of both) includes an entire epoch. """ - start_full_epoch = compute_epoch_at_slot(start_slot + (SLOTS_PER_EPOCH - 1)) - end_full_epoch = compute_epoch_at_slot(Slot(end_slot + 1)) + start_full_epoch = compute_epoch_at_slot(start_slot + SLOTS_PER_EPOCH - Slot(1)) + end_full_epoch = compute_epoch_at_slot(end_slot + Slot(1)) return start_full_epoch < end_full_epoch @@ -6855,12 +7021,29 @@ ) +- name: is_future_slot#phase0 + sources: [] + spec: | + + def is_future_slot( + store: Store, + slot: Slot, + current_time_ms: Uint64, + ) -> bool: + """ + Check if the given slot is in the future + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). + """ + slot_time_ms = compute_time_at_slot_ms(store, slot) + return current_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY < slot_time_ms + + - name: is_gas_limit_target_compatible#gloas sources: [] spec: | - + def is_gas_limit_target_compatible( - parent_gas_limit: uint64, gas_limit: uint64, target_gas_limit: uint64 + parent_gas_limit: Uint64, gas_limit: Uint64, target_gas_limit: Uint64 ) -> bool: """ Check if ``gas_limit`` is compatible with ``target_gas_limit`` under the @@ -6870,11 +7053,11 @@ min_gas_limit = parent_gas_limit - max_gas_limit_difference max_gas_limit = parent_gas_limit + max_gas_limit_difference - if target_gas_limit >= min_gas_limit and target_gas_limit <= max_gas_limit: - return gas_limit == target_gas_limit + if target_gas_limit < min_gas_limit: + return gas_limit == min_gas_limit if target_gas_limit > max_gas_limit: return gas_limit == max_gas_limit - return gas_limit == min_gas_limit + return gas_limit == target_gas_limit - name: is_head_late#phase0 @@ -6896,18 +7079,35 @@ - name: is_head_weak#phase0 sources: [] spec: | - + def is_head_weak(store: Store, head_root: Root) -> bool: + # Calculate weight threshold for weak head justified_state = store.checkpoint_states[store.justified_checkpoint] reorg_threshold = calculate_committee_fraction(justified_state, REORG_HEAD_WEIGHT_THRESHOLD) - head_weight = get_weight(store, ForkChoiceNode(root=head_root)) + + # Compute head weight including equivocations + head_state = store.block_states[head_root] + head_block = store.blocks[head_root] + epoch = compute_epoch_at_slot(head_block.slot) + head_node = ForkChoiceNode(root=head_root) + head_weight = get_attestation_score(store, head_node, justified_state) + for index in range(get_committee_count_per_slot(head_state, epoch)): + committee = get_beacon_committee(head_state, head_block.slot, CommitteeIndex(index)) + head_weight += Gwei( + sum( + justified_state.validators[i].effective_balance + for i in committee + if i in store.equivocating_indices + ) + ) + return head_weight < reorg_threshold - name: is_head_weak#gloas sources: [] spec: | - + def is_head_weak(store: Store, head_root: Root) -> bool: # Calculate weight threshold for weak head justified_state = store.checkpoint_states[store.justified_checkpoint] @@ -6917,6 +7117,7 @@ head_state = store.block_states[head_root] head_block = store.blocks[head_root] epoch = compute_epoch_at_slot(head_block.slot) + # [Modified in Gloas:EIP7732] head_node = ForkChoiceNode(root=head_root, payload_status=PAYLOAD_STATUS_PENDING) head_weight = get_attestation_score(store, head_node, justified_state) for index in range(get_committee_count_per_slot(head_state, epoch)): @@ -6942,6 +7143,28 @@ return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY +- name: is_inclusion_list_bits_inclusive#heze + sources: [] + spec: | + + def is_inclusion_list_bits_inclusive( + store: InclusionListStore, + committee: InclusionListCommittee, + slot: Slot, + dependent_root: Root, + inclusion_list_bits: InclusionListBits, + only_timely: bool = True, + ) -> bool: + local_inclusion_list_bits = get_inclusion_list_bits( + store, committee, slot, dependent_root, only_timely + ) + + for i in range(INCLUSION_LIST_COMMITTEE_SIZE): + if local_inclusion_list_bits[i] and not inclusion_list_bits[i]: + return False + return True + + - name: is_merge_transition_block#bellatrix sources: [] spec: | @@ -6971,10 +7194,10 @@ - name: is_non_strict_superset#phase0 sources: [] spec: | - + def is_non_strict_superset( - seen_bits_set: Set[Tuple[boolean, ...]], - new_bits: Tuple[boolean, ...], + seen_bits_set: Set[Tuple[Boolean, ...]], + new_bits: Tuple[Boolean, ...], ) -> bool: """ Return True if any prior bitset in ``seen_bits_set`` is a non-strict @@ -6991,23 +7214,6 @@ return False -- name: is_not_from_future_slot#phase0 - sources: [] - spec: | - - def is_not_from_future_slot( - state: BeaconState, - slot: Slot, - current_time_ms: uint64, - ) -> bool: - """ - Check if the given slot is not from the future - (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). - """ - slot_time_ms = compute_time_at_slot_ms(state, slot) - return current_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY >= slot_time_ms - - - name: is_one_confirmed#phase0 sources: [] spec: | @@ -7058,13 +7264,13 @@ - name: is_parent_strong#phase0 sources: [] spec: | - + def is_parent_strong(store: Store, root: Root) -> bool: justified_state = store.checkpoint_states[store.justified_checkpoint] parent_threshold = calculate_committee_fraction(justified_state, REORG_PARENT_WEIGHT_THRESHOLD) parent_root = store.blocks[root].parent_root parent_node = ForkChoiceNode(root=parent_root) - parent_weight = get_weight(store, parent_node) + parent_weight = get_attestation_score(store, parent_node, justified_state) return parent_weight > parent_threshold @@ -7128,6 +7334,23 @@ ) +- name: is_past_slot#gloas + sources: [] + spec: | + + def is_past_slot( + store: Store, + slot: Slot, + current_time_ms: Uint64, + ) -> bool: + """ + Check if the given slot is in the past + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). + """ + slot_time_ms = compute_time_at_slot_ms(store, slot) + return current_time_ms > slot_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY + + - name: is_payload_inclusion_list_satisfied#heze sources: [] spec: | @@ -7228,6 +7451,14 @@ return time_into_slot_ms <= proposer_reorg_cutoff_ms +- name: is_shuffling_stable#phase0 + sources: [] + spec: | + + def is_shuffling_stable(slot: Slot) -> bool: + return slot % SLOTS_PER_EPOCH != 0 + + - name: is_slashable_attestation_data#phase0 sources: - file: beacon-chain/core/blocks/attester_slashing.go @@ -7314,6 +7545,26 @@ return bls.Verify(request.pubkey, signing_root, request.signature) +- name: is_valid_dependent_root#gloas + sources: [] + spec: | + + def is_valid_dependent_root(store: Store, root: Root, epoch: Epoch) -> bool: + """ + Check if the block with the given ``root`` is a possible dependent block + for the given ``epoch``, meaning that on some branch it is, or could + become, the latest block prior to the start of the epoch. + """ + epoch_start_slot = compute_start_slot_at_epoch(epoch) + for block in store.blocks.values(): + if block.parent_root == root: + if block.slot >= epoch_start_slot: + return True + if root == get_head(store).root: + return True + return False + + - name: is_valid_deposit_signature#electra sources: - file: beacon-chain/core/electra/deposits.go @@ -7321,9 +7572,9 @@ - file: beacon-chain/core/helpers/deposit.go search: func IsValidDepositSignature( spec: | - + def is_valid_deposit_signature( - pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64, signature: BLSSignature + pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: Uint64, signature: BLSSignature ) -> bool: deposit_message = DepositMessage( pubkey=pubkey, @@ -7391,6 +7642,34 @@ return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) +- name: is_valid_indexed_attestation#gloas + sources: + - file: beacon-chain/core/blocks/attestation.go + search: func VerifyIndexedAttestation( + spec: | + + def is_valid_indexed_attestation( + state: BeaconState, indexed_attestation: IndexedAttestation + ) -> bool: + """ + Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature. + """ + # Verify indices are sorted and unique + indices = indexed_attestation.attesting_indices + if ( + len(indices) == 0 + # [New in Gloas:EIP7688] + or len(indices) > MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT + or indices != sorted(set(indices)) + ): + return False + # Verify aggregate signature + pubkeys = [state.validators[i].pubkey for i in indices] + domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) + signing_root = compute_signing_root(indexed_attestation.data, domain) + return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) + + - name: is_valid_indexed_payload_attestation#gloas sources: [] spec: | @@ -7447,15 +7726,15 @@ - name: is_valid_light_client_header#deneb sources: [] spec: | - + def is_valid_light_client_header(header: LightClientHeader) -> bool: epoch = compute_epoch_at_slot(header.beacon.slot) # [New in Deneb:EIP4844] if epoch < DENEB_FORK_EPOCH: - if header.execution.blob_gas_used != uint64(0): + if header.execution.blob_gas_used != Uint64(0): return False - if header.execution.excess_blob_gas != uint64(0): + if header.execution.excess_blob_gas != Uint64(0): return False if epoch < CAPELLA_FORK_EPOCH: @@ -7514,9 +7793,9 @@ - name: is_valid_merkle_branch#phase0 sources: [] spec: | - + def is_valid_merkle_branch( - leaf: Bytes32, branch: Sequence[Bytes32], depth: uint64, index: uint64, root: Root + leaf: Bytes32, branch: Sequence[Bytes32], depth: Uint64, index: Uint64, root: Root ) -> bool: """ Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and ``branch``. @@ -7542,27 +7821,6 @@ return is_valid_merkle_branch(leaf, branch[num_extra:], depth, index, root) -- name: is_valid_proposal_slot#gloas - sources: [] - spec: | - - def is_valid_proposal_slot(state: BeaconState, preferences: ProposerPreferences) -> bool: - """ - Check if the validator is the proposer for the given slot within the - proposer lookahead. - """ - current_epoch = get_current_epoch(state) - proposal_epoch = compute_epoch_at_slot(preferences.proposal_slot) - if proposal_epoch < current_epoch: - return False - if proposal_epoch > current_epoch + Epoch(MIN_SEED_LOOKAHEAD): - return False - - index = (proposal_epoch - current_epoch) * SLOTS_PER_EPOCH - index += preferences.proposal_slot % SLOTS_PER_EPOCH - return state.proposer_lookahead[index] == preferences.validator_index - - - name: is_valid_switch_to_compounding_request#electra sources: - file: beacon-chain/core/electra/consolidations.go @@ -7616,24 +7874,45 @@ return is_total_difficulty_reached and is_parent_total_difficulty_valid +- name: is_within_epoch#deneb + sources: [] + spec: | + + def is_within_epoch( + store: Store, + epoch: Epoch, + current_time_ms: Uint64, + ) -> bool: + """ + Check if the current time is within the given epoch + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance on both ends). + """ + return is_within_slot_range( + store, + compute_start_slot_at_epoch(epoch), + SLOTS_PER_EPOCH - 1, + current_time_ms, + ) + + - name: is_within_slot_range#phase0 sources: [] spec: | - + def is_within_slot_range( - state: BeaconState, + store: Store, slot: Slot, - slot_range: uint64, - current_time_ms: uint64, + slot_range: Uint64, + current_time_ms: Uint64, ) -> bool: """ Check if the current time is within the inclusive slot range ``[slot, slot + slot_range]`` (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance on both ends). """ - start_time_ms = compute_time_at_slot_ms(state, slot) + start_time_ms = compute_time_at_slot_ms(store, slot) if current_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY < start_time_ms: return False - end_time_ms = compute_time_at_slot_ms(state, Slot(slot + slot_range + 1)) + end_time_ms = compute_time_at_slot_ms(store, Slot(slot + slot_range + 1)) if end_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY < current_time_ms: return False return True @@ -7703,11 +7982,11 @@ - file: beacon-chain/p2p/encoder/ssz.go search: func MaxCompressedLen( spec: | - - def max_compressed_len(n: uint64) -> uint64: + + def max_compressed_len(n: Uint64) -> Uint64: # Worst-case compressed length for a given payload of size n when using snappy: # https://github.com/google/snappy/blob/32ded457c0b1fe78ceb8397632c416568d6714a0/snappy.cc#L218C1-L218C47 - return uint64(32 + n + n / 6) + return Uint64(32 + n + n / 6) - name: max_message_size#phase0 @@ -7715,8 +7994,8 @@ - file: beacon-chain/p2p/pubsub.go search: func MaxMessageSize( spec: | - - def max_message_size() -> uint64: + + def max_message_size() -> Uint64: # Allow 1024 bytes for framing and encoding overhead but at least 1MiB in case MAX_PAYLOAD_SIZE is small. return max(max_compressed_len(MAX_PAYLOAD_SIZE) + 1024, 1024 * 1024) @@ -7744,6 +8023,21 @@ return NEXT_SYNC_COMMITTEE_GINDEX +- name: next_sync_committee_gindex_at_slot#gloas + sources: [] + spec: | + + def next_sync_committee_gindex_at_slot(slot: Slot) -> GeneralizedIndex: + epoch = compute_epoch_at_slot(slot) + + # [Modified in Gloas:EIP7688] + if epoch >= GLOAS_FORK_EPOCH: + return NEXT_SYNC_COMMITTEE_GINDEX_GLOAS + if epoch >= ELECTRA_FORK_EPOCH: + return NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA + return NEXT_SYNC_COMMITTEE_GINDEX + + - name: normalize_merkle_branch#electra sources: [] spec: | @@ -7788,10 +8082,10 @@ - file: beacon-chain/blockchain/process_attestation.go search: func (s *Service) OnAttestation( spec: | - + def on_attestation(store: Store, attestation: Attestation, is_from_block: bool = False) -> None: """ - Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire. + Run ``on_attestation`` upon receiving a new attestation from either within a block or directly on the wire. An ``attestation`` that is asserted as invalid may be valid at a later time, consider scheduling it for later processing in such case. @@ -7814,10 +8108,10 @@ - file: beacon-chain/core/blocks/attester_slashing.go search: func ProcessAttesterSlashing( spec: | - + def on_attester_slashing(store: Store, attester_slashing: AttesterSlashing) -> None: """ - Run ``on_attester_slashing`` immediately upon receiving a new ``AttesterSlashing`` + Run ``on_attester_slashing`` immediately upon receiving a new attester slashing from either within a block or directly on the wire. """ attestation_1 = attester_slashing.attestation_1 @@ -7837,9 +8131,18 @@ - file: beacon-chain/blockchain/receive_block.go search: func (s *Service) ReceiveBlock( spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: + """ + Run ``on_block`` upon receiving a new block. + """ block = signed_block.message + block_root = hash_tree_root(block) + + # Return early if the block is already known + if block_root in store.blocks: + return + # Parent block must be known assert block.parent_root in store.block_states # Make a copy of the state to avoid mutability issues @@ -7860,7 +8163,6 @@ # Check the block is valid and compute the post-state state = pre_state.copy() - block_root = hash_tree_root(block) state_transition(state, signed_block, validate_result=True) # Compute head before applying the block @@ -7885,7 +8187,7 @@ - file: beacon-chain/blockchain/receive_block.go search: func (s *Service) ReceiveBlock( spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: """ Run ``on_block`` upon receiving a new block. @@ -7894,6 +8196,12 @@ consider scheduling it for later processing in such case. """ block = signed_block.message + block_root = hash_tree_root(block) + + # Return early if the block is already known + if block_root in store.blocks: + return + # Parent block must be known assert block.parent_root in store.block_states # Make a copy of the state to avoid mutability issues @@ -7914,7 +8222,6 @@ # Check the block is valid and compute the post-state state = pre_state.copy() - block_root = hash_tree_root(block) state_transition(state, signed_block, validate_result=True) # [New in Bellatrix] @@ -7943,12 +8250,18 @@ - file: beacon-chain/blockchain/receive_block.go search: func (s *Service) ReceiveBlock( spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: """ Run ``on_block`` upon receiving a new block. """ block = signed_block.message + block_root = hash_tree_root(block) + + # Return early if the block is already known + if block_root in store.blocks: + return + # Parent block must be known assert block.parent_root in store.block_states # Blocks cannot be in the future. If they are, their consideration must be delayed until they are in the past. @@ -7968,7 +8281,6 @@ # Check the block is valid and compute the post-state # Make a copy of the state to avoid mutability issues state = copy(store.block_states[block.parent_root]) - block_root = hash_tree_root(block) state_transition(state, signed_block, validate_result=True) # Compute head before applying the block @@ -7993,12 +8305,18 @@ - file: beacon-chain/blockchain/receive_block.go search: func (s *Service) ReceiveBlock( spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: """ Run ``on_block`` upon receiving a new block. """ block = signed_block.message + block_root = hash_tree_root(block) + + # Return early if the block is already known + if block_root in store.blocks: + return + # Parent block must be known assert block.parent_root in store.block_states # Blocks cannot be in the future. If they are, their consideration must be delayed until they are in the past. @@ -8018,12 +8336,11 @@ # [New in Deneb:EIP4844] # Check if blob data is available # If not, this payload MAY be queued and subsequently considered when blob data becomes available - assert is_data_available(hash_tree_root(block), block.body.blob_kzg_commitments) + assert is_data_available(block_root, block.body.blob_kzg_commitments) # Check the block is valid and compute the post-state # Make a copy of the state to avoid mutability issues state = copy(store.block_states[block.parent_root]) - block_root = hash_tree_root(block) state_transition(state, signed_block, validate_result=True) # Compute head before applying the block @@ -8048,12 +8365,18 @@ - file: beacon-chain/blockchain/receive_block.go search: func (s *Service) ReceiveBlock( spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: """ Run ``on_block`` upon receiving a new block. """ block = signed_block.message + block_root = hash_tree_root(block) + + # Return early if the block is already known + if block_root in store.blocks: + return + # Parent block must be known assert block.parent_root in store.block_states # Make a copy of the state to avoid mutability issues @@ -8075,10 +8398,9 @@ # [Modified in Fulu:EIP7594] # Check if blob data is available # If not, this payload MAY be queued and subsequently considered when blob data becomes available - assert is_data_available(hash_tree_root(block)) + assert is_data_available(block_root) # Check the block is valid and compute the post-state - block_root = hash_tree_root(block) state_transition(state, signed_block, validate_result=True) # Compute head before applying the block @@ -8101,12 +8423,18 @@ - name: on_block#gloas sources: [] spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: """ Run ``on_block`` upon receiving a new block. """ block = signed_block.message + block_root = hash_tree_root(block) + + # Return early if the block is already known + if block_root in store.blocks: + return + # Parent block must be known assert block.parent_root in store.block_states @@ -8134,7 +8462,6 @@ state = copy(store.block_states[block.parent_root]) # Check the block is valid and compute the post-state - block_root = hash_tree_root(block) state_transition(state, signed_block, validate_result=True) # Compute head before applying the block @@ -8190,7 +8517,7 @@ - name: on_execution_payload_envelope#heze sources: [] spec: | - + def on_execution_payload_envelope( store: Store, signed_envelope: SignedExecutionPayloadEnvelope ) -> None: @@ -8214,7 +8541,7 @@ # Check if this payload satisfies the inclusion list constraints # If not, add this payload to the store as inclusion list constraints unsatisfied record_payload_inclusion_list_satisfaction( - store, state, envelope.beacon_block_root, envelope.payload, EXECUTION_ENGINE + store, envelope.beacon_block_root, envelope.payload, EXECUTION_ENGINE ) # Add execution payload envelope to the store @@ -8233,31 +8560,55 @@ - name: on_inclusion_list#heze sources: [] spec: | - + def on_inclusion_list(store: Store, signed_inclusion_list: SignedInclusionList) -> None: """ Run ``on_inclusion_list`` upon receiving a new inclusion list. """ inclusion_list = signed_inclusion_list.message + current_slot = get_current_slot(store) + + # The transactions must not exceed the maximum size + transactions_size = sum(len(transaction) for transaction in inclusion_list.transactions) + assert transactions_size <= MAX_TRANSACTIONS_BYTES_PER_INCLUSION_LIST + + # The slot must be within the retention window + assert inclusion_list.slot <= current_slot + assert inclusion_list.slot + MIN_SLOTS_FOR_INCLUSION_LISTS_REQUESTS >= current_slot + + # The dependent block must be known + assert inclusion_list.dependent_root in store.block_states + + # Verify the validator is in the inclusion list committee + dependent_state = copy(store.block_states[inclusion_list.dependent_root]) + if dependent_state.slot < inclusion_list.slot: + process_slots(dependent_state, inclusion_list.slot) + committee = get_inclusion_list_committee(dependent_state, inclusion_list.slot) + assert inclusion_list.validator_index in committee + + # Verify the signature + assert is_valid_inclusion_list_signature(dependent_state, signed_inclusion_list) + # The inclusion list is timely if it arrives in its slot before the deadline seconds_since_genesis = store.time - store.genesis_time time_into_slot_ms = seconds_to_milliseconds(seconds_since_genesis) % SLOT_DURATION_MS - inclusion_list_due_ms = get_inclusion_list_due_ms() - is_timely = time_into_slot_ms < inclusion_list_due_ms + is_current_slot = inclusion_list.slot == current_slot + is_timely = is_current_slot and time_into_slot_ms < get_inclusion_list_due_ms() - process_inclusion_list(get_inclusion_list_store(), inclusion_list, is_timely) + # Process the inclusion list + process_inclusion_list(get_inclusion_list_store(), signed_inclusion_list, is_timely) - name: on_payload_attestation_message#gloas sources: [] spec: | - + def on_payload_attestation_message( store: Store, ptc_message: PayloadAttestationMessage, is_from_block: bool = False ) -> None: """ - Run ``on_payload_attestation_message`` upon receiving a new ``ptc_message`` from - either within a block or directly on the wire. + Run ``on_payload_attestation_message`` upon receiving a new payload attestation message + from either within a block or directly on the wire. """ data = ptc_message.data @@ -8304,8 +8655,8 @@ - name: on_tick#phase0 sources: [] spec: | - - def on_tick(store: Store, time: uint64) -> None: + + def on_tick(store: Store, time: Uint64) -> None: # If the ``store.time`` falls behind, while loop catches up slot by slot # to ensure that every previous slot is processed with ``on_tick_per_slot`` tick_slot = (time - store.genesis_time) * 1000 // SLOT_DURATION_MS @@ -8320,8 +8671,8 @@ - name: on_tick_per_slot#phase0 sources: [] spec: | - - def on_tick_per_slot(store: Store, time: uint64) -> None: + + def on_tick_per_slot(store: Store, time: Uint64) -> None: previous_slot = get_current_slot(store) # Update store time @@ -8528,7 +8879,7 @@ - name: prepare_execution_payload#heze sources: [] spec: | - + def prepare_execution_payload( store: Store, head: ForkChoiceNode, @@ -8536,11 +8887,11 @@ safe_block_hash: Hash32, finalized_block_hash: Hash32, suggested_fee_recipient: ExecutionAddress, - target_gas_limit: uint64, + target_gas_limit: Uint64, execution_engine: ExecutionEngine, ) -> Optional[PayloadId]: parent_bid = state.latest_execution_payload_bid - if should_build_on_full(store, head): + if should_build_on_full(store, head, get_current_slot(store)): envelope = store.payloads[head.root] # Make a copy of the state to avoid mutability issues state = copy(state) @@ -8563,7 +8914,12 @@ target_gas_limit=target_gas_limit, # [New in Heze:EIP7805] inclusion_list_transactions=get_inclusion_list_transactions( - get_inclusion_list_store(), state, Slot(state.slot - 1), only_timely=False + get_inclusion_list_store(), + state.slot - Slot(1), + get_shuffling_dependent_root( + store, head.root, compute_epoch_at_slot(state.slot - Slot(1)) + ), + only_timely=False, ), ) return execution_engine.notify_forkchoice_updated( @@ -8571,6 +8927,7 @@ safe_block_hash=safe_block_hash, finalized_block_hash=finalized_block_hash, payload_attributes=payload_attributes, + custody_columns=None, ) @@ -8767,8 +9124,13 @@ - name: process_attestation#gloas sources: [] spec: | - - def process_attestation(state: BeaconState, attestation: Attestation) -> None: + + def process_attestation( + state: BeaconState, + attestation: Attestation, + # [New in Gloas:EIP7732] + parent_slot: Slot, + ) -> None: data = attestation.data assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) assert data.target.epoch == compute_epoch_at_slot(data.slot) @@ -8793,8 +9155,9 @@ assert len(attestation.aggregation_bits) == committee_offset # Participation flag indices + # [Modified in Gloas:EIP7732] participation_flag_indices = get_attestation_participation_flag_indices( - state, data, state.slot - data.slot + state, data, state.slot - data.slot, parent_slot ) # Verify signature @@ -8813,8 +9176,7 @@ proposer_reward_numerator = 0 for index in get_attesting_indices(state, attestation): # [New in Gloas:EIP7732] - # For same-slot attestations, check if we are setting any new flags. - # If we are, this validator has not contributed to this slot's quorum yet. + had_no_participation = epoch_participation[index] == ParticipationFlags(0b0000_0000) will_set_new_flag = False for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): @@ -8827,10 +9189,9 @@ will_set_new_flag = True # [New in Gloas:EIP7732] - # Add weight for same-slot attestations when any new flag is set. - # This ensures each validator contributes exactly once per slot. if ( will_set_new_flag + and had_no_participation and is_attestation_same_slot(state, data) and payment.withdrawal.amount > 0 ): @@ -8977,7 +9338,7 @@ - name: process_block#gloas sources: [] spec: | - + def process_block(state: BeaconState, block: BeaconBlock) -> None: # [New in Gloas:EIP7732] process_parent_execution_payload(state, block) @@ -8987,11 +9348,11 @@ # [Modified in Gloas:EIP7732] # Removed `process_execution_payload` # [New in Gloas:EIP7732] - process_execution_payload_bid(state, block.body.signed_execution_payload_bid) + parent_slot = process_execution_payload_bid(state, block.body.signed_execution_payload_bid) process_randao(state, block.body) process_eth1_data(state, block.body) # [Modified in Gloas:EIP7732] - process_operations(state, block.body) + process_operations(state, block.body, parent_slot) process_sync_aggregate(state, block.body.sync_aggregate) @@ -9057,15 +9418,19 @@ - name: process_builder_deposit_request#gloas sources: [] spec: | - + def process_builder_deposit_request(state: BeaconState, request: BuilderDepositRequest) -> None: + # Ignore deposits with unexpected withdrawal credential prefixes + if not is_builder_withdrawal_credential(request.withdrawal_credentials): + return + builder_pubkeys = [b.pubkey for b in state.builders] if request.pubkey not in builder_pubkeys: if is_valid_builder_deposit_signature(request): add_builder_to_registry( state, request.pubkey, - uint8(request.withdrawal_credentials[0]), + PAYLOAD_BUILDER_VERSION, ExecutionAddress(request.withdrawal_credentials[12:]), request.amount, state.slot, @@ -9074,13 +9439,13 @@ builder_index = BuilderIndex(builder_pubkeys.index(request.pubkey)) builder = state.builders[builder_index] - # Increase balance by deposit amount - builder.balance += request.amount - - # If exited, reset the withdrawable epoch - if builder.withdrawable_epoch != FAR_FUTURE_EPOCH: + # If exited and swept, reset the withdrawable epoch + if builder.withdrawable_epoch != FAR_FUTURE_EPOCH and builder.balance == 0: epoch = get_current_epoch(state) builder.withdrawable_epoch = epoch + MIN_BUILDER_WITHDRAWABILITY_DELAY + + # Increase balance by deposit amount + builder.balance += request.amount - name: process_builder_exit_request#gloas @@ -9108,7 +9473,7 @@ - name: process_builder_pending_payments#gloas sources: [] spec: | - + def process_builder_pending_payments(state: BeaconState) -> None: """ Processes the builder pending payments from the previous epoch. @@ -9120,7 +9485,7 @@ old_payments = state.builder_pending_payments[SLOTS_PER_EPOCH:] new_payments = [BuilderPendingPayment() for _ in range(SLOTS_PER_EPOCH)] - state.builder_pending_payments = old_payments + new_payments + state.builder_pending_payments = BuilderPendingPayments(old_payments + new_payments) - name: process_consolidation_request#electra @@ -9322,12 +9687,12 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessEffectiveBalanceUpdates( spec: | - + def process_effective_balance_updates(state: BeaconState) -> None: # Update effective balances with hysteresis for index, validator in enumerate(state.validators): balance = state.balances[index] - HYSTERESIS_INCREMENT = uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT) + HYSTERESIS_INCREMENT = Uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT) DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER if ( @@ -9344,12 +9709,12 @@ - file: beacon-chain/core/electra/effective_balance_updates.go search: func ProcessEffectiveBalanceUpdates( spec: | - + def process_effective_balance_updates(state: BeaconState) -> None: # Update effective balances with hysteresis for index, validator in enumerate(state.validators): balance = state.balances[index] - HYSTERESIS_INCREMENT = uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT) + HYSTERESIS_INCREMENT = Uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT) DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER # [Modified in Electra:EIP7251] @@ -9542,12 +9907,12 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessEth1DataReset( spec: | - + def process_eth1_data_reset(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) # Reset eth1 data votes if next_epoch % EPOCHS_PER_ETH1_VOTING_PERIOD == 0: - state.eth1_data_votes = [] + state.eth1_data_votes = Eth1DataVotes() - name: process_execution_payload#bellatrix @@ -9878,10 +10243,10 @@ - name: process_execution_payload_bid#gloas sources: [] spec: | - + def process_execution_payload_bid( state: BeaconState, signed_bid: SignedExecutionPayloadBid - ) -> None: + ) -> Slot: bid = signed_bid.message builder_index = bid.builder_index amount = bid.value @@ -9929,8 +10294,13 @@ pending_payment ) + # Cache the parent block's slot before overwriting the bid + parent_slot = state.latest_execution_payload_bid.slot + # Cache the signed execution payload bid state.latest_execution_payload_bid = bid + + return parent_slot - name: process_historical_roots_update#phase0 @@ -9995,33 +10365,29 @@ - name: process_inclusion_list#heze sources: [] spec: | - + def process_inclusion_list( - store: InclusionListStore, - inclusion_list: InclusionList, - is_timely: bool, + store: InclusionListStore, signed_inclusion_list: SignedInclusionList, timely: bool ) -> None: - key = inclusion_list.inclusion_list_committee_root - - # Ignore `inclusion_list` from equivocators. - if inclusion_list.validator_index in store.equivocators[key]: - return - - for stored_root in store.inclusion_lists[key]: - stored_inclusion_list = store.inclusion_lists[key][stored_root] - if stored_inclusion_list.validator_index != inclusion_list.validator_index: - continue + inclusion_list = signed_inclusion_list.message + validator_index = inclusion_list.validator_index + key = (inclusion_list.slot, inclusion_list.dependent_root) + if validator_index in store.inclusion_lists[key]: + # Mark the validator as an equivocator if it published a different inclusion list + stored_entry = store.inclusion_lists[key][validator_index] + stored_inclusion_list = stored_entry.signed_inclusion_list.message if stored_inclusion_list != inclusion_list: - store.equivocators[key].add(inclusion_list.validator_index) + store.equivocators[key].add(validator_index) - # Whether it was an equivocation or not, we have processed this `inclusion_list`. + # Ignore an inclusion list that has already been processed return - # Store `inclusion_list` and its timeliness. - inclusion_list_root = hash_tree_root(inclusion_list) - store.inclusion_lists[key][inclusion_list_root] = inclusion_list - store.inclusion_list_timeliness[inclusion_list_root] = is_timely + # Store the signed inclusion list and its timeliness + store.inclusion_lists[key][validator_index] = InclusionListEntry( + signed_inclusion_list=signed_inclusion_list, + timely=timely, + ) - name: process_justification_and_finalization#phase0 @@ -10143,7 +10509,7 @@ - name: process_light_client_update#altair sources: [] spec: | - + def process_light_client_update( store: LightClientStore, update: LightClientUpdate, @@ -10161,12 +10527,12 @@ # Track the maximum number of active participants in the committee signatures store.current_max_active_participants = max( store.current_max_active_participants, - sum(sync_committee_bits), + get_set_bit_count(sync_committee_bits), ) # Update the optimistic header if ( - sum(sync_committee_bits) > get_safety_threshold(store) + get_set_bit_count(sync_committee_bits) > get_safety_threshold(store) and update.attested_header.beacon.slot > store.optimistic_header.beacon.slot ): store.optimistic_header = update.attested_header @@ -10181,7 +10547,7 @@ == compute_sync_committee_period_at_slot(update.attested_header.beacon.slot) ) ) - if sum(sync_committee_bits) * 3 >= len(sync_committee_bits) * 2 and ( + if get_set_bit_count(sync_committee_bits) * 3 >= len(sync_committee_bits) * 2 and ( update.finalized_header.beacon.slot > store.finalized_header.beacon.slot or update_has_finalized_next_sync_committee ): @@ -10304,19 +10670,33 @@ - name: process_operations#gloas sources: [] spec: | - - def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: + + def process_operations( + state: BeaconState, + body: BeaconBlockBody, + # [New in Gloas:EIP7732] + parent_slot: Slot, + ) -> None: assert len(body.deposits) == 0 - def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: + # [Modified in Gloas:EIP7732] + def for_ops(operations: Sequence[Any], fn: Callable[..., None], *args: Any) -> None: for operation in operations: - fn(state, operation) + fn(state, operation, *args) + + # [New in Gloas:EIP7688] + assert len(body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS + assert len(body.attester_slashings) <= MAX_ATTESTER_SLASHINGS_ELECTRA + assert len(body.attestations) <= MAX_ATTESTATIONS_ELECTRA + assert len(body.voluntary_exits) <= MAX_VOLUNTARY_EXITS + assert len(body.bls_to_execution_changes) <= MAX_BLS_TO_EXECUTION_CHANGES + assert len(body.payload_attestations) <= MAX_PAYLOAD_ATTESTATIONS # [Modified in Gloas:EIP7732] for_ops(body.proposer_slashings, process_proposer_slashing) for_ops(body.attester_slashings, process_attester_slashing) # [Modified in Gloas:EIP7732] - for_ops(body.attestations, process_attestation) + for_ops(body.attestations, process_attestation, parent_slot) for_ops(body.voluntary_exits, process_voluntary_exit) for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) # [Modified in Gloas:EIP7732] @@ -10355,12 +10735,12 @@ - file: beacon-chain/core/altair/epoch_spec.go search: func ProcessParticipationFlagUpdates( spec: | - + def process_participation_flag_updates(state: BeaconState) -> None: state.previous_epoch_participation = state.current_epoch_participation - state.current_epoch_participation = [ + state.current_epoch_participation = EpochParticipation( ParticipationFlags(0b0000_0000) for _ in range(len(state.validators)) - ] + ) - name: process_participation_record_updates#phase0 @@ -10368,11 +10748,11 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessParticipationRecordUpdates( spec: | - + def process_participation_record_updates(state: BeaconState) -> None: # Rotate current/previous epoch attestations state.previous_epoch_attestations = state.current_epoch_attestations - state.current_epoch_attestations = [] + state.current_epoch_attestations = PendingAttestations() - name: process_payload_attestation#gloas @@ -10398,7 +10778,7 @@ - file: beacon-chain/core/electra/consolidations.go search: func ProcessPendingConsolidations( spec: | - + def process_pending_consolidations(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) next_pending_consolidation = 0 @@ -10420,7 +10800,9 @@ increase_balance(state, pending_consolidation.target_index, source_effective_balance) next_pending_consolidation += 1 - state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:] + state.pending_consolidations = PendingConsolidations( + state.pending_consolidations[next_pending_consolidation:] + ) - name: process_pending_deposits#electra @@ -10428,7 +10810,7 @@ - file: beacon-chain/core/electra/deposits.go search: func ProcessPendingDeposits( spec: | - + def process_pending_deposits(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit( @@ -10487,7 +10869,9 @@ # Regardless of how the deposit was handled, we move on in the queue. next_deposit_index += 1 - state.pending_deposits = state.pending_deposits[next_deposit_index:] + deposits_to_postpone + state.pending_deposits = PendingDeposits( + state.pending_deposits[next_deposit_index:] + deposits_to_postpone + ) # Accumulate churn only if the churn limit has been hit. if is_churn_limit_reached: @@ -10499,7 +10883,7 @@ - name: process_pending_deposits#fulu sources: [] spec: | - + def process_pending_deposits(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit( @@ -10548,7 +10932,9 @@ # Regardless of how the deposit was handled, we move on in the queue. next_deposit_index += 1 - state.pending_deposits = state.pending_deposits[next_deposit_index:] + deposits_to_postpone + state.pending_deposits = PendingDeposits( + state.pending_deposits[next_deposit_index:] + deposits_to_postpone + ) # Accumulate churn only if the churn limit has been hit. if is_churn_limit_reached: @@ -10560,7 +10946,7 @@ - name: process_pending_deposits#gloas sources: [] spec: | - + def process_pending_deposits(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) # [Modified in Gloas:EIP8061] @@ -10609,7 +10995,9 @@ # Regardless of how the deposit was handled, we move on in the queue. next_deposit_index += 1 - state.pending_deposits = state.pending_deposits[next_deposit_index:] + deposits_to_postpone + state.pending_deposits = PendingDeposits( + state.pending_deposits[next_deposit_index:] + deposits_to_postpone + ) # Accumulate churn only if the churn limit has been hit. if is_churn_limit_reached: @@ -10899,7 +11287,7 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessSlashings( spec: | - + def process_slashings(state: BeaconState) -> None: epoch = get_current_epoch(state) total_balance = get_total_active_balance(state) @@ -10911,7 +11299,7 @@ validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch ): - increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow + increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid Uint64 overflow penalty_numerator = ( validator.effective_balance // increment * adjusted_total_slashing_balance ) @@ -10924,7 +11312,7 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessSlashings( spec: | - + def process_slashings(state: BeaconState) -> None: epoch = get_current_epoch(state) total_balance = get_total_active_balance(state) @@ -10936,7 +11324,7 @@ validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch ): - increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow + increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid Uint64 overflow penalty_numerator = ( validator.effective_balance // increment * adjusted_total_slashing_balance ) @@ -10949,7 +11337,7 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessSlashings( spec: | - + def process_slashings(state: BeaconState) -> None: epoch = get_current_epoch(state) total_balance = get_total_active_balance(state) @@ -10964,7 +11352,7 @@ validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch ): - increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow + increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid Uint64 overflow penalty_numerator = ( validator.effective_balance // increment * adjusted_total_slashing_balance ) @@ -10977,7 +11365,7 @@ - file: beacon-chain/core/epoch/epoch_processing.go search: func ProcessSlashings( spec: | - + def process_slashings(state: BeaconState) -> None: epoch = get_current_epoch(state) total_balance = get_total_active_balance(state) @@ -10985,7 +11373,7 @@ sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, total_balance ) increment = ( - EFFECTIVE_BALANCE_INCREMENT # Factored out from total balance to avoid uint64 overflow + EFFECTIVE_BALANCE_INCREMENT # Factored out from total balance to avoid Uint64 overflow ) penalty_per_effective_balance_increment = adjusted_total_slashing_balance // ( total_balance // increment @@ -11071,15 +11459,15 @@ - file: beacon-chain/core/altair/block.go search: func ProcessSyncAggregate( spec: | - + def process_sync_aggregate(state: BeaconState, sync_aggregate: SyncAggregate) -> None: # Verify sync committee aggregate signature signing over the previous slot block root committee_pubkeys = state.current_sync_committee.pubkeys committee_bits = sync_aggregate.sync_committee_bits - if sum(committee_bits) == SYNC_COMMITTEE_SIZE: + if get_set_bit_count(committee_bits) == SYNC_COMMITTEE_SIZE: # All members participated - use precomputed aggregate key participant_pubkeys = [state.current_sync_committee.aggregate_pubkey] - elif sum(committee_bits) > SYNC_COMMITTEE_SIZE // 2: + elif get_set_bit_count(committee_bits) > SYNC_COMMITTEE_SIZE // 2: # More than half participated - subtract non-participant keys. # First determine nonparticipating members non_participant_pubkeys = [ @@ -11495,16 +11883,17 @@ - name: record_payload_inclusion_list_satisfaction#heze sources: [] spec: | - + def record_payload_inclusion_list_satisfaction( store: Store, - state: BeaconState, root: Root, payload: ExecutionPayload, execution_engine: ExecutionEngine, ) -> None: + slot = store.blocks[root].slot - Slot(1) + dependent_root = get_shuffling_dependent_root(store, root, compute_epoch_at_slot(slot)) inclusion_list_transactions = get_inclusion_list_transactions( - get_inclusion_list_store(), state, Slot(state.slot - 1) + get_inclusion_list_store(), slot, dependent_root, only_timely=True ) is_inclusion_list_satisfied = execution_engine.is_inclusion_list_satisfied( payload, inclusion_list_transactions @@ -11515,21 +11904,21 @@ - name: recover_matrix#fulu sources: [] spec: | - + def recover_matrix( - partial_matrix: Sequence[MatrixEntry], blob_count: uint64 + partial_matrix: Sequence[MatrixEntry], blob_count: Uint64 ) -> Sequence[MatrixEntry]: """ Recover the full, flattened sequence of matrix entries. - This helper demonstrates how to apply ``recover_cells_and_kzg_proofs``. + This helper demonstrates how to apply ``kzg.recover_cells_and_kzg_proofs``. The data structure for storing cells/proofs is implementation-dependent. """ matrix = [] for blob_index in range(blob_count): cell_indices = [e.column_index for e in partial_matrix if e.row_index == blob_index] cells = [e.cell for e in partial_matrix if e.row_index == blob_index] - recovered_cells, recovered_proofs = recover_cells_and_kzg_proofs(cell_indices, cells) + recovered_cells, recovered_proofs = kzg.recover_cells_and_kzg_proofs(cell_indices, cells) for cell_index, (cell, proof) in enumerate( zip(recovered_cells, recovered_proofs, strict=True) ): @@ -11547,8 +11936,8 @@ - name: seconds_to_milliseconds#phase0 sources: [] spec: | - - def seconds_to_milliseconds(seconds: uint64) -> uint64: + + def seconds_to_milliseconds(seconds: Uint64) -> Uint64: """ Convert seconds to milliseconds with overflow protection. Returns ``UINT64_MAX`` if the result would overflow. @@ -11572,8 +11961,8 @@ - name: settle_builder_payment#gloas sources: [] spec: | - - def settle_builder_payment(state: BeaconState, payment_index: uint64) -> None: + + def settle_builder_payment(state: BeaconState, payment_index: Uint64) -> None: assert payment_index < len(state.builder_pending_payments) payment = state.builder_pending_payments[payment_index] if payment.withdrawal.amount > 0: @@ -11621,10 +12010,10 @@ - name: should_build_on_full#gloas sources: [] spec: | - - def should_build_on_full(store: Store, head: ForkChoiceNode) -> bool: + + def should_build_on_full(store: Store, head: ForkChoiceNode, slot: Slot) -> bool: assert head.payload_status != PAYLOAD_STATUS_PENDING - if store.blocks[head.root].slot + 1 != get_current_slot(store): + if store.blocks[head.root].slot + 1 != slot: return head.payload_status == PAYLOAD_STATUS_FULL if head.payload_status == PAYLOAD_STATUS_EMPTY: return False @@ -11899,13 +12288,13 @@ - name: update_builder_pending_withdrawals#gloas sources: [] spec: | - + def update_builder_pending_withdrawals( - state: BeaconState, processed_builder_withdrawals_count: uint64 + state: BeaconState, processed_builder_withdrawals_count: Uint64 ) -> None: - state.builder_pending_withdrawals = state.builder_pending_withdrawals[ - processed_builder_withdrawals_count: - ] + state.builder_pending_withdrawals = BuilderPendingWithdrawals( + state.builder_pending_withdrawals[processed_builder_withdrawals_count:] + ) - name: update_checkpoints#phase0 @@ -11998,9 +12387,9 @@ - name: update_next_withdrawal_builder_index#gloas sources: [] spec: | - + def update_next_withdrawal_builder_index( - state: BeaconState, processed_builders_sweep_count: uint64 + state: BeaconState, processed_builders_sweep_count: Uint64 ) -> None: if len(state.builders) > 0: # Update the next builder index to start the next withdrawal sweep @@ -12044,33 +12433,36 @@ - name: update_payload_expected_withdrawals#gloas sources: [] spec: | - + def update_payload_expected_withdrawals( state: BeaconState, withdrawals: Sequence[Withdrawal] ) -> None: - state.payload_expected_withdrawals = List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD](withdrawals) + state.payload_expected_withdrawals = Withdrawals(withdrawals) - name: update_pending_partial_withdrawals#electra sources: [] spec: | - + def update_pending_partial_withdrawals( - state: BeaconState, processed_partial_withdrawals_count: uint64 + state: BeaconState, processed_partial_withdrawals_count: Uint64 ) -> None: - state.pending_partial_withdrawals = state.pending_partial_withdrawals[ - processed_partial_withdrawals_count: - ] + state.pending_partial_withdrawals = PendingPartialWithdrawals( + state.pending_partial_withdrawals[processed_partial_withdrawals_count:] + ) - name: update_proposer_boost_root#phase0 sources: [] spec: | - + def update_proposer_boost_root(store: Store, head: Root, root: Root) -> None: is_first_block = store.proposer_boost_root == Root() is_timely = store.block_timeliness[root] - is_same_dependent_root = get_dependent_root(store, root) == get_dependent_root(store, head) + epoch = get_current_store_epoch(store) + head_dependent_root = get_shuffling_dependent_root(store, head, epoch) + block_dependent_root = get_shuffling_dependent_root(store, root, epoch) + is_same_dependent_root = head_dependent_root == block_dependent_root # Add proposer score boost if the block is timely, not conflicting with an # existing block, with the same dependent root as the canonical chain head. @@ -12081,12 +12473,15 @@ - name: update_proposer_boost_root#gloas sources: [] spec: | - + def update_proposer_boost_root(store: Store, head: Root, root: Root) -> None: is_first_block = store.proposer_boost_root == Root() # [Modified in Gloas:EIP7732] is_timely = store.block_timeliness[root][ATTESTATION_TIMELINESS_INDEX] - is_same_dependent_root = get_dependent_root(store, root) == get_dependent_root(store, head) + epoch = get_current_store_epoch(store) + head_dependent_root = get_shuffling_dependent_root(store, head, epoch) + block_dependent_root = get_shuffling_dependent_root(store, root, epoch) + is_same_dependent_root = head_dependent_root == block_dependent_root # Add proposer score boost if the block is timely, not conflicting with an # existing block, with the same dependent root as the canonical chain head. @@ -12117,6 +12512,48 @@ store.unrealized_finalized_checkpoint = unrealized_finalized_checkpoint +- name: upgrade_attestation_to_gloas#gloas + sources: + - file: proto/prysm/v1alpha1/attestation.go + search: func AttestationElectraToGloas( + spec: | + + def upgrade_attestation_to_gloas(pre: fulu.Attestation) -> Attestation: + return Attestation( + aggregation_bits=AggregationBits(list(pre.aggregation_bits)), + data=pre.data, + signature=pre.signature, + committee_bits=pre.committee_bits, + ) + + +- name: upgrade_attester_slashing_to_gloas#gloas + sources: + - file: proto/prysm/v1alpha1/attestation.go + search: func AttesterSlashingElectraToGloas( + spec: | + + def upgrade_attester_slashing_to_gloas(pre: fulu.AttesterSlashing) -> AttesterSlashing: + return AttesterSlashing( + attestation_1=upgrade_indexed_attestation_to_gloas(pre.attestation_1), + attestation_2=upgrade_indexed_attestation_to_gloas(pre.attestation_2), + ) + + +- name: upgrade_indexed_attestation_to_gloas#gloas + sources: + - file: proto/prysm/v1alpha1/attestation.go + search: func IndexedAttestationElectraToGloas( + spec: | + + def upgrade_indexed_attestation_to_gloas(pre: fulu.IndexedAttestation) -> IndexedAttestation: + return IndexedAttestation( + attesting_indices=AttestingIndices(list(pre.attesting_indices)), + data=pre.data, + signature=pre.signature, + ) + + - name: upgrade_lc_bootstrap_to_capella#capella sources: [] spec: | @@ -12158,12 +12595,14 @@ - name: upgrade_lc_bootstrap_to_gloas#gloas sources: [] spec: | - + def upgrade_lc_bootstrap_to_gloas(pre: electra.LightClientBootstrap) -> LightClientBootstrap: return LightClientBootstrap( header=upgrade_lc_header_to_gloas(pre.header), current_sync_committee=pre.current_sync_committee, - current_sync_committee_branch=pre.current_sync_committee_branch, + current_sync_committee_branch=normalize_merkle_branch( + pre.current_sync_committee_branch, CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS + ), ) @@ -12218,14 +12657,14 @@ - name: upgrade_lc_finality_update_to_gloas#gloas sources: [] spec: | - + def upgrade_lc_finality_update_to_gloas( pre: electra.LightClientFinalityUpdate, ) -> LightClientFinalityUpdate: return LightClientFinalityUpdate( attested_header=upgrade_lc_header_to_gloas(pre.attested_header), finalized_header=upgrade_lc_header_to_gloas(pre.finalized_header), - finality_branch=pre.finality_branch, + finality_branch=normalize_merkle_branch(pre.finality_branch, FINALIZED_ROOT_GINDEX_GLOAS), sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, ) @@ -12246,7 +12685,7 @@ - name: upgrade_lc_header_to_deneb#deneb sources: [] spec: | - + def upgrade_lc_header_to_deneb(pre: capella.LightClientHeader) -> LightClientHeader: return LightClientHeader( beacon=pre.beacon, @@ -12267,9 +12706,9 @@ transactions_root=pre.execution.transactions_root, withdrawals_root=pre.execution.withdrawals_root, # [New in Deneb:EIP4844] - blob_gas_used=uint64(0), + blob_gas_used=Uint64(0), # [New in Deneb:EIP4844] - excess_blob_gas=uint64(0), + excess_blob_gas=Uint64(0), ), execution_branch=pre.execution_branch, ) @@ -12534,14 +12973,16 @@ - name: upgrade_lc_update_to_gloas#gloas sources: [] spec: | - + def upgrade_lc_update_to_gloas(pre: electra.LightClientUpdate) -> LightClientUpdate: return LightClientUpdate( attested_header=upgrade_lc_header_to_gloas(pre.attested_header), next_sync_committee=pre.next_sync_committee, - next_sync_committee_branch=pre.next_sync_committee_branch, + next_sync_committee_branch=normalize_merkle_branch( + pre.next_sync_committee_branch, NEXT_SYNC_COMMITTEE_GINDEX_GLOAS + ), finalized_header=upgrade_lc_header_to_gloas(pre.finalized_header), - finality_branch=pre.finality_branch, + finality_branch=normalize_merkle_branch(pre.finality_branch, FINALIZED_ROOT_GINDEX_GLOAS), sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, ) @@ -12552,7 +12993,7 @@ - file: beacon-chain/core/altair/upgrade.go search: func UpgradeToAltair( spec: | - + def upgrade_to_altair(pre: phase0.BeaconState) -> BeaconState: epoch = phase0.get_current_epoch(pre) post = BeaconState( @@ -12576,17 +13017,17 @@ balances=pre.balances, randao_mixes=pre.randao_mixes, slashings=pre.slashings, - previous_epoch_participation=[ + previous_epoch_participation=EpochParticipation([ ParticipationFlags(0b0000_0000) for _ in range(len(pre.validators)) - ], - current_epoch_participation=[ + ]), + current_epoch_participation=EpochParticipation([ ParticipationFlags(0b0000_0000) for _ in range(len(pre.validators)) - ], + ]), 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_scores=[uint64(0) for _ in range(len(pre.validators))], + inactivity_scores=InactivityScores([Uint64(0) for _ in range(len(pre.validators))]), ) # Fill in previous epoch participation from the pre state's pending attestations translate_participation(post, pre.previous_epoch_attestations) @@ -12648,7 +13089,7 @@ - file: beacon-chain/core/capella/upgrade.go search: func UpgradeToCapella( spec: | - + def upgrade_to_capella(pre: bellatrix.BeaconState) -> BeaconState: epoch = bellatrix.get_current_epoch(pre) latest_execution_payload_header = ExecutionPayloadHeader( @@ -12705,7 +13146,7 @@ # [New in Capella] next_withdrawal_validator_index=ValidatorIndex(0), # [New in Capella] - historical_summaries=List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT]([]), + historical_summaries=HistoricalSummaries(), ) return post @@ -12716,7 +13157,7 @@ - file: beacon-chain/core/deneb/upgrade.go search: func UpgradeToDeneb( spec: | - + def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState: epoch = capella.get_current_epoch(pre) latest_execution_payload_header = ExecutionPayloadHeader( @@ -12736,9 +13177,9 @@ transactions_root=pre.latest_execution_payload_header.transactions_root, withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, # [New in Deneb:EIP4844] - blob_gas_used=uint64(0), + blob_gas_used=Uint64(0), # [New in Deneb:EIP4844] - excess_blob_gas=uint64(0), + excess_blob_gas=Uint64(0), ) post = BeaconState( genesis_time=pre.genesis_time, @@ -12785,7 +13226,7 @@ - file: beacon-chain/core/electra/upgrade.go search: func UpgradeToElectra( spec: | - + def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState: epoch = deneb.get_current_epoch(pre) @@ -12842,11 +13283,11 @@ # [New in Electra:EIP7251] earliest_consolidation_epoch=compute_activation_exit_epoch(get_current_epoch(pre)), # [New in Electra:EIP7251] - pending_deposits=[], + pending_deposits=PendingDeposits(), # [New in Electra:EIP7251] - pending_partial_withdrawals=[], + pending_partial_withdrawals=PendingPartialWithdrawals(), # [New in Electra:EIP7251] - pending_consolidations=[], + pending_consolidations=PendingConsolidations(), ) post.exit_balance_to_consume = get_activation_exit_churn_limit(post) @@ -12950,7 +13391,7 @@ - name: upgrade_to_gloas#gloas sources: [] spec: | - + def upgrade_to_gloas(pre: fulu.BeaconState) -> BeaconState: epoch = fulu.get_current_epoch(pre) @@ -12971,17 +13412,22 @@ eth1_data=pre.eth1_data, eth1_data_votes=pre.eth1_data_votes, eth1_deposit_index=pre.eth1_deposit_index, - validators=pre.validators, - balances=pre.balances, + # [Modified in Gloas:EIP7688] + validators=Validators(list(pre.validators)), + # [Modified in Gloas:EIP7688] + balances=Balances(list(pre.balances)), randao_mixes=pre.randao_mixes, slashings=pre.slashings, - previous_epoch_participation=pre.previous_epoch_participation, - current_epoch_participation=pre.current_epoch_participation, + # [Modified in Gloas:EIP7688] + previous_epoch_participation=EpochParticipation(list(pre.previous_epoch_participation)), + # [Modified in Gloas:EIP7688] + current_epoch_participation=EpochParticipation(list(pre.current_epoch_participation)), 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_scores=pre.inactivity_scores, + # [Modified in Gloas:EIP7688] + inactivity_scores=InactivityScores(list(pre.inactivity_scores)), current_sync_committee=pre.current_sync_committee, next_sync_committee=pre.next_sync_committee, # [Modified in Gloas:EIP7732] @@ -12997,28 +13443,44 @@ earliest_exit_epoch=pre.earliest_exit_epoch, consolidation_balance_to_consume=pre.consolidation_balance_to_consume, earliest_consolidation_epoch=pre.earliest_consolidation_epoch, - pending_deposits=pre.pending_deposits, - pending_partial_withdrawals=pre.pending_partial_withdrawals, - pending_consolidations=pre.pending_consolidations, + # [Modified in Gloas:EIP7688] + pending_deposits=PendingDeposits(list(pre.pending_deposits)), + # [Modified in Gloas:EIP7688] + pending_partial_withdrawals=PendingPartialWithdrawals( + list(pre.pending_partial_withdrawals) + ), + # [Modified in Gloas:EIP7688] + pending_consolidations=PendingConsolidations(list(pre.pending_consolidations)), proposer_lookahead=pre.proposer_lookahead, # [New in Gloas:EIP7732] - builders=[], + builders=Builders(), # [New in Gloas:EIP7732] next_withdrawal_builder_index=BuilderIndex(0), # [New in Gloas:EIP7732] - execution_payload_availability=[0b1 for _ in range(SLOTS_PER_HISTORICAL_ROOT)], + execution_payload_availability=ExecutionPayloadAvailability([ + 0b1 for _ in range(SLOTS_PER_HISTORICAL_ROOT) + ]), # [New in Gloas:EIP7732] - builder_pending_payments=[BuilderPendingPayment() for _ in range(2 * SLOTS_PER_EPOCH)], + builder_pending_payments=BuilderPendingPayments(), # [New in Gloas:EIP7732] - builder_pending_withdrawals=[], + builder_pending_withdrawals=BuilderPendingWithdrawals(), # [New in Gloas:EIP7732] latest_execution_payload_bid=ExecutionPayloadBid( + parent_block_hash=pre.latest_execution_payload_header.parent_hash, + parent_block_root=pre.latest_block_header.parent_root, block_hash=pre.latest_execution_payload_header.block_hash, + prev_randao=pre.latest_execution_payload_header.prev_randao, + fee_recipient=ExecutionAddress(), gas_limit=pre.latest_execution_payload_header.gas_limit, + builder_index=BUILDER_INDEX_SELF_BUILD, + slot=pre.latest_block_header.slot, + value=Gwei(0), + execution_payment=Gwei(0), + blob_kzg_commitments=BlobKZGCommitments(), execution_requests_root=hash_tree_root(ExecutionRequests()), ), # [New in Gloas:EIP7732] - payload_expected_withdrawals=[], + payload_expected_withdrawals=Withdrawals(), # [New in Gloas:EIP7732] ptc_window=initialize_ptc_window(pre), ) @@ -13032,9 +13494,25 @@ - name: upgrade_to_heze#heze sources: [] spec: | - + def upgrade_to_heze(pre: gloas.BeaconState) -> BeaconState: epoch = gloas.get_current_epoch(pre) + latest_execution_payload_bid = ExecutionPayloadBid( + parent_block_hash=pre.latest_execution_payload_bid.parent_block_hash, + parent_block_root=pre.latest_execution_payload_bid.parent_block_root, + block_hash=pre.latest_execution_payload_bid.block_hash, + prev_randao=pre.latest_execution_payload_bid.prev_randao, + fee_recipient=pre.latest_execution_payload_bid.fee_recipient, + gas_limit=pre.latest_execution_payload_bid.gas_limit, + builder_index=pre.latest_execution_payload_bid.builder_index, + slot=pre.latest_execution_payload_bid.slot, + value=pre.latest_execution_payload_bid.value, + execution_payment=pre.latest_execution_payload_bid.execution_payment, + blob_kzg_commitments=pre.latest_execution_payload_bid.blob_kzg_commitments, + execution_requests_root=pre.latest_execution_payload_bid.execution_requests_root, + # [New in Heze:EIP7805] + inclusion_list_bits=InclusionListBits(), + ) post = BeaconState( genesis_time=pre.genesis_time, @@ -13085,7 +13563,8 @@ execution_payload_availability=pre.execution_payload_availability, builder_pending_payments=pre.builder_pending_payments, builder_pending_withdrawals=pre.builder_pending_withdrawals, - latest_execution_payload_bid=pre.latest_execution_payload_bid, + # [Modified in Heze:EIP7805] + latest_execution_payload_bid=latest_execution_payload_bid, payload_expected_withdrawals=pre.payload_expected_withdrawals, ptc_window=pre.ptc_window, ) @@ -13155,13 +13634,13 @@ - name: validate_beacon_aggregate_and_proof_gossip#phase0 sources: [] spec: | - + def validate_beacon_aggregate_and_proof_gossip( seen: Seen, store: Store, state: BeaconState, signed_aggregate_and_proof: SignedAggregateAndProof, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> None: """ Validate a SignedAggregateAndProof for gossip propagation. @@ -13180,7 +13659,7 @@ # [IGNORE] The aggregate attestation's slot is within the propagation range # (MAY be queued for processing at the appropriate slot) if not is_within_slot_range( - state, aggregate.data.slot, ATTESTATION_PROPAGATION_SLOT_RANGE, current_time_ms + store, aggregate.data.slot, ATTESTATION_PROPAGATION_SLOT_RANGE, current_time_ms ): raise GossipIgnore("attestation slot not within propagation range") @@ -13205,11 +13684,12 @@ if is_non_strict_superset(seen_bits, aggregate_bits): raise GossipIgnore("already seen aggregate for this data") - # [IGNORE] This is the first valid aggregate for this aggregator in this epoch + # [IGNORE] This is the first valid aggregate for this epoch and aggregator aggregator_index = aggregate_and_proof.aggregator_index target_epoch = aggregate.data.target.epoch - if (aggregator_index, target_epoch) in seen.aggregator_epochs: - raise GossipIgnore("already seen aggregate from this aggregator for this epoch") + aggregator_epoch_key = (target_epoch, aggregator_index) + if aggregator_epoch_key in seen.aggregator_epochs: + raise GossipIgnore("already seen aggregate for this epoch and aggregator") # [REJECT] The selection proof selects the validator as an aggregator if not is_aggregator(state, aggregate.data.slot, index, aggregate_and_proof.selection_proof): @@ -13238,29 +13718,27 @@ # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) # (MAY be queued until block is retrieved) - if aggregate.data.beacon_block_root not in store.blocks: + block_root = aggregate.data.beacon_block_root + if block_root not in store.blocks: raise GossipIgnore("block being voted for has not been seen") # [REJECT] The block being voted for passes validation - if aggregate.data.beacon_block_root not in store.block_states: + if block_root not in store.block_states: raise GossipReject("block being voted for failed validation") # [REJECT] The target block is an ancestor of the LMD vote block - checkpoint_block = get_checkpoint_block( - store, aggregate.data.beacon_block_root, aggregate.data.target.epoch - ) + checkpoint_block = get_checkpoint_block(store, block_root, aggregate.data.target.epoch) if checkpoint_block != aggregate.data.target.root: raise GossipReject("target block is not an ancestor of LMD vote block") # [IGNORE] The finalized checkpoint is an ancestor of the block - finalized_checkpoint_block = get_checkpoint_block( - store, aggregate.data.beacon_block_root, store.finalized_checkpoint.epoch - ) + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipIgnore("finalized checkpoint is not an ancestor of block") # Mark this aggregate as seen - seen.aggregator_epochs.add((aggregator_index, target_epoch)) + seen.aggregator_epochs.add(aggregator_epoch_key) if aggregate_data_root not in seen.aggregate_data_roots: seen.aggregate_data_roots[aggregate_data_root] = set() seen.aggregate_data_roots[aggregate_data_root].add(aggregate_bits) @@ -13269,13 +13747,13 @@ - name: validate_beacon_aggregate_and_proof_gossip#deneb sources: [] spec: | - + def validate_beacon_aggregate_and_proof_gossip( seen: Seen, store: Store, state: BeaconState, signed_aggregate_and_proof: SignedAggregateAndProof, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> None: """ Validate a SignedAggregateAndProof for gossip propagation. @@ -13294,26 +13772,14 @@ # [New in Deneb:EIP7045] # [IGNORE] The aggregate attestation's slot is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, aggregate.data.slot, current_time_ms): + if is_future_slot(store, aggregate.data.slot, current_time_ms): raise GossipIgnore("aggregate slot is from a future slot") # [Modified in Deneb:EIP7045] # [IGNORE] The aggregate attestation's epoch is either the current or previous epoch attestation_epoch = compute_epoch_at_slot(aggregate.data.slot) - is_previous_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(Epoch(attestation_epoch + 1)), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - is_current_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(attestation_epoch), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - if not (is_previous_epoch_attestation or is_current_epoch_attestation): - raise GossipIgnore("aggregate epoch is not previous or current epoch") + if not is_current_or_previous_epoch(store, attestation_epoch, current_time_ms): + raise GossipIgnore("aggregate epoch is not current or previous epoch") # [REJECT] The aggregate attestation's epoch matches its target if aggregate.data.target.epoch != compute_epoch_at_slot(aggregate.data.slot): @@ -13336,11 +13802,12 @@ if is_non_strict_superset(seen_bits, aggregate_bits): raise GossipIgnore("already seen aggregate for this data") - # [IGNORE] This is the first valid aggregate for this aggregator in this epoch + # [IGNORE] This is the first valid aggregate for this epoch and aggregator aggregator_index = aggregate_and_proof.aggregator_index target_epoch = aggregate.data.target.epoch - if (aggregator_index, target_epoch) in seen.aggregator_epochs: - raise GossipIgnore("already seen aggregate from this aggregator for this epoch") + aggregator_epoch_key = (target_epoch, aggregator_index) + if aggregator_epoch_key in seen.aggregator_epochs: + raise GossipIgnore("already seen aggregate for this epoch and aggregator") # [REJECT] The selection proof selects the validator as an aggregator if not is_aggregator(state, aggregate.data.slot, index, aggregate_and_proof.selection_proof): @@ -13369,29 +13836,27 @@ # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) # (MAY be queued until block is retrieved) - if aggregate.data.beacon_block_root not in store.blocks: + block_root = aggregate.data.beacon_block_root + if block_root not in store.blocks: raise GossipIgnore("block being voted for has not been seen") # [REJECT] The block being voted for passes validation - if aggregate.data.beacon_block_root not in store.block_states: + if block_root not in store.block_states: raise GossipReject("block being voted for failed validation") # [REJECT] The target block is an ancestor of the LMD vote block - checkpoint_block = get_checkpoint_block( - store, aggregate.data.beacon_block_root, aggregate.data.target.epoch - ) + checkpoint_block = get_checkpoint_block(store, block_root, aggregate.data.target.epoch) if checkpoint_block != aggregate.data.target.root: raise GossipReject("target block is not an ancestor of LMD vote block") # [IGNORE] The finalized checkpoint is an ancestor of the block - finalized_checkpoint_block = get_checkpoint_block( - store, aggregate.data.beacon_block_root, store.finalized_checkpoint.epoch - ) + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipIgnore("finalized checkpoint is not an ancestor of block") # Mark this aggregate as seen - seen.aggregator_epochs.add((aggregator_index, target_epoch)) + seen.aggregator_epochs.add(aggregator_epoch_key) if aggregate_data_root not in seen.aggregate_data_roots: seen.aggregate_data_roots[aggregate_data_root] = set() seen.aggregate_data_roots[aggregate_data_root].add(aggregate_bits) @@ -13400,13 +13865,13 @@ - name: validate_beacon_aggregate_and_proof_gossip#electra sources: [] spec: | - + def validate_beacon_aggregate_and_proof_gossip( seen: Seen, store: Store, state: BeaconState, signed_aggregate_and_proof: SignedAggregateAndProof, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> None: """ Validate a SignedAggregateAndProof for gossip propagation. @@ -13435,25 +13900,13 @@ # [IGNORE] The aggregate attestation's slot is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, aggregate.data.slot, current_time_ms): + if is_future_slot(store, aggregate.data.slot, current_time_ms): raise GossipIgnore("aggregate slot is from a future slot") # [IGNORE] The aggregate attestation's epoch is either the current or previous epoch attestation_epoch = compute_epoch_at_slot(aggregate.data.slot) - is_previous_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(Epoch(attestation_epoch + 1)), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - is_current_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(attestation_epoch), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - if not (is_previous_epoch_attestation or is_current_epoch_attestation): - raise GossipIgnore("aggregate epoch is not previous or current epoch") + if not is_current_or_previous_epoch(store, attestation_epoch, current_time_ms): + raise GossipIgnore("aggregate epoch is not current or previous epoch") # [REJECT] The aggregate attestation's epoch matches its target if aggregate.data.target.epoch != compute_epoch_at_slot(aggregate.data.slot): @@ -13478,11 +13931,12 @@ if is_non_strict_superset(seen_bits, aggregate_bits): raise GossipIgnore("already seen aggregate for this data") - # [IGNORE] This is the first valid aggregate for this aggregator in this epoch + # [IGNORE] This is the first valid aggregate for this epoch and aggregator aggregator_index = aggregate_and_proof.aggregator_index target_epoch = aggregate.data.target.epoch - if (aggregator_index, target_epoch) in seen.aggregator_epochs: - raise GossipIgnore("already seen aggregate from this aggregator for this epoch") + aggregator_epoch_key = (target_epoch, aggregator_index) + if aggregator_epoch_key in seen.aggregator_epochs: + raise GossipIgnore("already seen aggregate for this epoch and aggregator") # [REJECT] The selection proof selects the validator as an aggregator if not is_aggregator(state, aggregate.data.slot, index, aggregate_and_proof.selection_proof): @@ -13511,29 +13965,160 @@ # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) # (MAY be queued until block is retrieved) - if aggregate.data.beacon_block_root not in store.blocks: + block_root = aggregate.data.beacon_block_root + if block_root not in store.blocks: raise GossipIgnore("block being voted for has not been seen") # [REJECT] The block being voted for passes validation - if aggregate.data.beacon_block_root not in store.block_states: + if block_root not in store.block_states: raise GossipReject("block being voted for failed validation") # [REJECT] The target block is an ancestor of the LMD vote block - checkpoint_block = get_checkpoint_block( - store, aggregate.data.beacon_block_root, aggregate.data.target.epoch - ) + checkpoint_block = get_checkpoint_block(store, block_root, aggregate.data.target.epoch) if checkpoint_block != aggregate.data.target.root: raise GossipReject("target block is not an ancestor of LMD vote block") # [IGNORE] The finalized checkpoint is an ancestor of the block - finalized_checkpoint_block = get_checkpoint_block( - store, aggregate.data.beacon_block_root, store.finalized_checkpoint.epoch - ) + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: + raise GossipIgnore("finalized checkpoint is not an ancestor of block") + + # Mark this aggregate as seen + seen.aggregator_epochs.add(aggregator_epoch_key) + if aggregate_cache_key not in seen.aggregate_data_roots: + seen.aggregate_data_roots[aggregate_cache_key] = set() + seen.aggregate_data_roots[aggregate_cache_key].add(aggregate_bits) + + +- name: validate_beacon_aggregate_and_proof_gossip#gloas + sources: [] + spec: | + + def validate_beacon_aggregate_and_proof_gossip( + seen: Seen, + store: Store, + state: BeaconState, + signed_aggregate_and_proof: SignedAggregateAndProof, + current_time_ms: Uint64, + # [New in Gloas:EIP7732] + block_payload_statuses: Dict[Root, PayloadValidationStatus], + ) -> None: + """ + Validate a SignedAggregateAndProof for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + aggregate_and_proof = signed_aggregate_and_proof.message + aggregate = aggregate_and_proof.aggregate + aggregation_bits = aggregate.aggregation_bits + + # [New in Gloas:EIP7732] + # [REJECT] The aggregate attestation's data index is 0 or 1 + if aggregate.data.index > 1: + raise GossipReject("aggregate data index must be 0 or 1") + + # [REJECT] Exactly one committee is specified by the committee bits + committee_indices = get_committee_indices(aggregate.committee_bits) + if len(committee_indices) != 1: + raise GossipReject("aggregate committee bits must specify exactly one committee") + index = committee_indices[0] + + # [REJECT] The committee index is within the expected range + committee_count = get_committee_count_per_slot(state, aggregate.data.target.epoch) + if index >= committee_count: + raise GossipReject("committee index out of range") + + # [IGNORE] The aggregate attestation's slot is not from a future slot + # (MAY be queued for processing at the appropriate slot) + if is_future_slot(store, aggregate.data.slot, current_time_ms): + raise GossipIgnore("aggregate slot is from a future slot") + + # [IGNORE] The aggregate attestation's epoch is either the current or previous epoch + attestation_epoch = compute_epoch_at_slot(aggregate.data.slot) + if not is_current_or_previous_epoch(store, attestation_epoch, current_time_ms): + raise GossipIgnore("aggregate epoch is not current or previous epoch") + + # [REJECT] The aggregate attestation's epoch matches its target + if aggregate.data.target.epoch != compute_epoch_at_slot(aggregate.data.slot): + raise GossipReject("attestation epoch does not match target epoch") + + # [REJECT] The number of aggregation bits matches the committee size + committee = get_beacon_committee(state, aggregate.data.slot, index) + if len(aggregation_bits) != len(committee): + raise GossipReject("aggregation bits length does not match committee size") + + # [REJECT] The aggregate attestation has participants + attesting_indices = get_attesting_indices(state, aggregate) + if len(attesting_indices) < 1: + raise GossipReject("aggregate has no participants") + + # [IGNORE] A valid aggregate with a superset of aggregation bits has not already been seen + aggregate_data_root = hash_tree_root(aggregate.data) + aggregate_cache_key = (aggregate_data_root, index) + aggregate_bits = tuple(bool(bit) for bit in aggregation_bits) + seen_bits = seen.aggregate_data_roots.get(aggregate_cache_key, set()) + if is_non_strict_superset(seen_bits, aggregate_bits): + raise GossipIgnore("already seen aggregate for this data") + + # [IGNORE] This is the first valid aggregate for this epoch and aggregator + aggregator_index = aggregate_and_proof.aggregator_index + target_epoch = aggregate.data.target.epoch + aggregator_epoch_key = (target_epoch, aggregator_index) + if aggregator_epoch_key in seen.aggregator_epochs: + raise GossipIgnore("already seen aggregate for this epoch and aggregator") + + # [REJECT] The selection proof selects the validator as an aggregator + if not is_aggregator(state, aggregate.data.slot, index, aggregate_and_proof.selection_proof): + raise GossipReject("validator is not selected as aggregator") + + # [REJECT] The aggregator's validator index is within the committee + if aggregator_index not in committee: + raise GossipReject("aggregator index not in committee") + + # [REJECT] The selection proof signature is valid + aggregator = state.validators[aggregator_index] + domain = get_domain(state, DOMAIN_SELECTION_PROOF, target_epoch) + signing_root = compute_signing_root(aggregate.data.slot, domain) + if not bls.Verify(aggregator.pubkey, signing_root, aggregate_and_proof.selection_proof): + raise GossipReject("invalid selection proof signature") + + # [REJECT] The aggregator signature is valid + domain = get_domain(state, DOMAIN_AGGREGATE_AND_PROOF, target_epoch) + signing_root = compute_signing_root(aggregate_and_proof, domain) + if not bls.Verify(aggregator.pubkey, signing_root, signed_aggregate_and_proof.signature): + raise GossipReject("invalid aggregator signature") + + # [REJECT] The aggregate signature is valid + if not is_valid_indexed_attestation(state, get_indexed_attestation(state, aggregate)): + raise GossipReject("invalid aggregate signature") + + # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + block_root = aggregate.data.beacon_block_root + if block_root not in store.blocks: + raise GossipIgnore("block being voted for has not been seen") + + # [REJECT] The block being voted for passes validation + if block_root not in store.block_states: + raise GossipReject("block being voted for failed validation") + + # [REJECT] The target block is an ancestor of the LMD vote block + checkpoint_block = get_checkpoint_block(store, block_root, aggregate.data.target.epoch) + if checkpoint_block != aggregate.data.target.root: + raise GossipReject("target block is not an ancestor of LMD vote block") + + # [IGNORE] The finalized checkpoint is an ancestor of the block + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipIgnore("finalized checkpoint is not an ancestor of block") + # [New in Gloas:EIP7732] + # The attested payload status is consistent with the block's execution payload + verify_attestation_payload_status(store, aggregate.data, block_payload_statuses) + # Mark this aggregate as seen - seen.aggregator_epochs.add((aggregator_index, target_epoch)) + seen.aggregator_epochs.add(aggregator_epoch_key) if aggregate_cache_key not in seen.aggregate_data_roots: seen.aggregate_data_roots[aggregate_cache_key] = set() seen.aggregate_data_roots[aggregate_cache_key].add(aggregate_bits) @@ -13542,13 +14127,13 @@ - name: validate_beacon_attestation_gossip#phase0 sources: [] spec: | - + def validate_beacon_attestation_gossip( seen: Seen, store: Store, state: BeaconState, attestation: Attestation, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -13575,7 +14160,7 @@ # [IGNORE] The attestation slot is within the propagation range # (MAY be queued for processing at the appropriate slot) if not is_within_slot_range( - state, data.slot, ATTESTATION_PROPAGATION_SLOT_RANGE, current_time_ms + store, data.slot, ATTESTATION_PROPAGATION_SLOT_RANGE, current_time_ms ): raise GossipIgnore("attestation slot not within propagation range") @@ -13584,7 +14169,7 @@ raise GossipReject("attestation epoch does not match target epoch") # [REJECT] The attestation is unaggregated (exactly one bit set) - num_bits_set = sum(1 for bit in aggregation_bits if bit) + num_bits_set = get_set_bit_count(aggregation_bits) if num_bits_set != 1: raise GossipReject("attestation is not unaggregated") @@ -13593,10 +14178,11 @@ if len(aggregation_bits) != len(committee): raise GossipReject("aggregation bits length does not match committee size") - # [IGNORE] No other valid attestation seen for this validator and target epoch + # [IGNORE] No other valid attestation seen for this target epoch and validator participant_index = committee[aggregation_bits.index(True)] - if (participant_index, target_epoch) in seen.attestation_validator_epochs: - raise GossipIgnore("already seen attestation from this validator for this epoch") + attestation_epoch_key = (target_epoch, participant_index) + if attestation_epoch_key in seen.attestation_validator_epochs: + raise GossipIgnore("already seen attestation for this epoch and validator") # [REJECT] The attestation signature is valid indexed_attestation = get_indexed_attestation(state, attestation) @@ -13605,40 +14191,39 @@ # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) # (MAY be queued until block is retrieved) - beacon_block_root = data.beacon_block_root - if beacon_block_root not in store.blocks: + block_root = data.beacon_block_root + if block_root not in store.blocks: raise GossipIgnore("block being voted for has not been seen") # [REJECT] The block being voted for passes validation - if beacon_block_root not in store.block_states: + if block_root not in store.block_states: raise GossipReject("block being voted for failed validation") # [REJECT] The attestation's target block is an ancestor of the LMD vote block - target_checkpoint_block = get_checkpoint_block(store, beacon_block_root, target_epoch) + target_checkpoint_block = get_checkpoint_block(store, block_root, target_epoch) if target_checkpoint_block != data.target.root: raise GossipReject("target block is not an ancestor of LMD vote block") # [IGNORE] The current finalized_checkpoint is an ancestor of the block - finalized_checkpoint_block = get_checkpoint_block( - store, beacon_block_root, store.finalized_checkpoint.epoch - ) + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipIgnore("finalized checkpoint is not an ancestor of block") # Mark this attestation as seen - seen.attestation_validator_epochs.add((participant_index, target_epoch)) + seen.attestation_validator_epochs.add(attestation_epoch_key) - name: validate_beacon_attestation_gossip#deneb sources: [] spec: | - + def validate_beacon_attestation_gossip( seen: Seen, store: Store, state: BeaconState, attestation: Attestation, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -13665,33 +14250,21 @@ # [Modified in Deneb:EIP7045] # [IGNORE] The attestation's slot is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, data.slot, current_time_ms): + if is_future_slot(store, data.slot, current_time_ms): raise GossipIgnore("attestation slot is from a future slot") # [Modified in Deneb:EIP7045] # [IGNORE] The attestation's epoch is either the current or previous epoch attestation_epoch = compute_epoch_at_slot(data.slot) - is_previous_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(Epoch(attestation_epoch + 1)), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - is_current_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(attestation_epoch), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - if not (is_previous_epoch_attestation or is_current_epoch_attestation): - raise GossipIgnore("attestation epoch is not previous or current epoch") + if not is_current_or_previous_epoch(store, attestation_epoch, current_time_ms): + raise GossipIgnore("attestation epoch is not current or previous epoch") # [REJECT] The attestation's epoch matches its target if target_epoch != compute_epoch_at_slot(data.slot): raise GossipReject("attestation epoch does not match target epoch") # [REJECT] The attestation is unaggregated (exactly one bit set) - num_bits_set = sum(1 for bit in aggregation_bits if bit) + num_bits_set = get_set_bit_count(aggregation_bits) if num_bits_set != 1: raise GossipReject("attestation is not unaggregated") @@ -13700,10 +14273,11 @@ if len(aggregation_bits) != len(committee): raise GossipReject("aggregation bits length does not match committee size") - # [IGNORE] No other valid attestation seen for this validator and target epoch + # [IGNORE] No other valid attestation seen for this target epoch and validator participant_index = committee[aggregation_bits.index(True)] - if (participant_index, target_epoch) in seen.attestation_validator_epochs: - raise GossipIgnore("already seen attestation from this validator for this epoch") + attestation_epoch_key = (target_epoch, participant_index) + if attestation_epoch_key in seen.attestation_validator_epochs: + raise GossipIgnore("already seen attestation for this epoch and validator") # [REJECT] The attestation signature is valid indexed_attestation = get_indexed_attestation(state, attestation) @@ -13712,41 +14286,40 @@ # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) # (MAY be queued until block is retrieved) - beacon_block_root = data.beacon_block_root - if beacon_block_root not in store.blocks: + block_root = data.beacon_block_root + if block_root not in store.blocks: raise GossipIgnore("block being voted for has not been seen") # [REJECT] The block being voted for passes validation - if beacon_block_root not in store.block_states: + if block_root not in store.block_states: raise GossipReject("block being voted for failed validation") # [REJECT] The attestation's target block is an ancestor of the LMD vote block - target_checkpoint_block = get_checkpoint_block(store, beacon_block_root, target_epoch) + target_checkpoint_block = get_checkpoint_block(store, block_root, target_epoch) if target_checkpoint_block != data.target.root: raise GossipReject("target block is not an ancestor of LMD vote block") # [IGNORE] The current finalized_checkpoint is an ancestor of the block - finalized_checkpoint_block = get_checkpoint_block( - store, beacon_block_root, store.finalized_checkpoint.epoch - ) + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipIgnore("finalized checkpoint is not an ancestor of block") # Mark this attestation as seen - seen.attestation_validator_epochs.add((participant_index, target_epoch)) + seen.attestation_validator_epochs.add(attestation_epoch_key) - name: validate_beacon_attestation_gossip#electra sources: [] spec: | - + def validate_beacon_attestation_gossip( seen: Seen, store: Store, state: BeaconState, # [Modified in Electra:EIP7549] attestation: SingleAttestation, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -13778,25 +14351,13 @@ # [IGNORE] The attestation's slot is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, data.slot, current_time_ms): + if is_future_slot(store, data.slot, current_time_ms): raise GossipIgnore("attestation slot is from a future slot") # [IGNORE] The attestation's epoch is either the current or previous epoch attestation_epoch = compute_epoch_at_slot(data.slot) - is_previous_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(Epoch(attestation_epoch + 1)), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - is_current_epoch_attestation = is_within_slot_range( - state, - compute_start_slot_at_epoch(attestation_epoch), - SLOTS_PER_EPOCH - 1, - current_time_ms, - ) - if not (is_previous_epoch_attestation or is_current_epoch_attestation): - raise GossipIgnore("attestation epoch is not previous or current epoch") + if not is_current_or_previous_epoch(store, attestation_epoch, current_time_ms): + raise GossipIgnore("attestation epoch is not current or previous epoch") # [REJECT] The attestation's epoch matches its target if target_epoch != compute_epoch_at_slot(data.slot): @@ -13809,9 +14370,10 @@ raise GossipReject("attester is not a member of the committee") # [Modified in Electra:EIP7549] - # [IGNORE] No other valid attestation seen for this validator and target epoch - if (attester_index, target_epoch) in seen.attestation_validator_epochs: - raise GossipIgnore("already seen attestation from this validator for this epoch") + # [IGNORE] No other valid attestation seen for this target epoch and validator + attestation_epoch_key = (target_epoch, attester_index) + if attestation_epoch_key in seen.attestation_validator_epochs: + raise GossipIgnore("already seen attestation for this epoch and validator") # [Modified in Electra:EIP7549] # [REJECT] The attestation signature is valid @@ -13823,40 +14385,139 @@ # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) # (MAY be queued until block is retrieved) - beacon_block_root = data.beacon_block_root - if beacon_block_root not in store.blocks: + block_root = data.beacon_block_root + if block_root not in store.blocks: raise GossipIgnore("block being voted for has not been seen") # [REJECT] The block being voted for passes validation - if beacon_block_root not in store.block_states: + if block_root not in store.block_states: raise GossipReject("block being voted for failed validation") # [REJECT] The attestation's target block is an ancestor of the LMD vote block - target_checkpoint_block = get_checkpoint_block(store, beacon_block_root, target_epoch) + target_checkpoint_block = get_checkpoint_block(store, block_root, target_epoch) if target_checkpoint_block != data.target.root: raise GossipReject("target block is not an ancestor of LMD vote block") # [IGNORE] The current finalized_checkpoint is an ancestor of the block - finalized_checkpoint_block = get_checkpoint_block( - store, beacon_block_root, store.finalized_checkpoint.epoch + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: + raise GossipIgnore("finalized checkpoint is not an ancestor of block") + + # Mark this attestation as seen + seen.attestation_validator_epochs.add(attestation_epoch_key) + + +- name: validate_beacon_attestation_gossip#gloas + sources: [] + spec: | + + def validate_beacon_attestation_gossip( + seen: Seen, + store: Store, + state: BeaconState, + attestation: SingleAttestation, + current_time_ms: Uint64, + subnet_id: SubnetID, + # [New in Gloas:EIP7732] + block_payload_statuses: Dict[Root, PayloadValidationStatus], + ) -> None: + """ + Validate a SingleAttestation for gossip propagation on a subnet. + Raises GossipIgnore or GossipReject on validation failure. + """ + data = attestation.data + committee_index = attestation.committee_index + attester_index = attestation.attester_index + target_epoch = data.target.epoch + + # [New in Gloas:EIP7732] + # [REJECT] The attestation's data index is 0 or 1 + if data.index > 1: + raise GossipReject("attestation data index must be 0 or 1") + + # [REJECT] The committee index is within the expected range + committees_per_slot = get_committee_count_per_slot(state, target_epoch) + if committee_index >= committees_per_slot: + raise GossipReject("committee index out of range") + + # [REJECT] The attestation is for the correct subnet + expected_subnet = compute_subnet_for_attestation( + committees_per_slot, data.slot, committee_index ) + if expected_subnet != subnet_id: + raise GossipReject("attestation is for wrong subnet") + + # [IGNORE] The attestation's slot is not from a future slot + # (MAY be queued for processing at the appropriate slot) + if is_future_slot(store, data.slot, current_time_ms): + raise GossipIgnore("attestation slot is from a future slot") + + # [IGNORE] The attestation's epoch is either the current or previous epoch + attestation_epoch = compute_epoch_at_slot(data.slot) + if not is_current_or_previous_epoch(store, attestation_epoch, current_time_ms): + raise GossipIgnore("attestation epoch is not current or previous epoch") + + # [REJECT] The attestation's epoch matches its target + if target_epoch != compute_epoch_at_slot(data.slot): + raise GossipReject("attestation epoch does not match target epoch") + + # [REJECT] The attester is a member of the committee + committee = get_beacon_committee(state, data.slot, committee_index) + if attester_index not in committee: + raise GossipReject("attester is not a member of the committee") + + # [IGNORE] No other valid attestation seen for this target epoch and validator + attestation_epoch_key = (target_epoch, attester_index) + if attestation_epoch_key in seen.attestation_validator_epochs: + raise GossipIgnore("already seen attestation for this epoch and validator") + + # [REJECT] The attestation signature is valid + attester = state.validators[attester_index] + domain = get_domain(state, DOMAIN_BEACON_ATTESTER, target_epoch) + signing_root = compute_signing_root(data, domain) + if not bls.Verify(attester.pubkey, signing_root, attestation.signature): + raise GossipReject("invalid attestation signature") + + # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + block_root = data.beacon_block_root + if block_root not in store.blocks: + raise GossipIgnore("block being voted for has not been seen") + + # [REJECT] The block being voted for passes validation + if block_root not in store.block_states: + raise GossipReject("block being voted for failed validation") + + # [REJECT] The attestation's target block is an ancestor of the LMD vote block + target_checkpoint_block = get_checkpoint_block(store, block_root, target_epoch) + if target_checkpoint_block != data.target.root: + raise GossipReject("target block is not an ancestor of LMD vote block") + + # [IGNORE] The current finalized checkpoint is an ancestor of the block + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block_root, finalized_epoch) if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipIgnore("finalized checkpoint is not an ancestor of block") + # [New in Gloas:EIP7732] + # The attested payload status is consistent with the block's execution payload + verify_attestation_payload_status(store, data, block_payload_statuses) + # Mark this attestation as seen - seen.attestation_validator_epochs.add((attester_index, target_epoch)) + seen.attestation_validator_epochs.add(attestation_epoch_key) - name: validate_beacon_block_gossip#phase0 sources: [] spec: | - + def validate_beacon_block_gossip( seen: Seen, store: Store, state: BeaconState, signed_beacon_block: SignedBeaconBlock, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> None: """ Validate a SignedBeaconBlock for gossip propagation. @@ -13866,7 +14527,7 @@ # [IGNORE] The block is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block.slot, current_time_ms): + if is_future_slot(store, block.slot, current_time_ms): raise GossipIgnore("block is from a future slot") # [IGNORE] The block is from a slot greater than the latest finalized slot @@ -13876,9 +14537,10 @@ if block.slot <= finalized_slot: raise GossipIgnore("block is not from a slot greater than the latest finalized slot") - # [IGNORE] The block is the first block with valid signature received for the proposer for the slot - if (block.proposer_index, block.slot) in seen.proposer_slots: - raise GossipIgnore("block is not the first valid block for this proposer and slot") + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") # [REJECT] The proposer index is a valid validator index if block.proposer_index >= len(state.validators): @@ -13905,10 +14567,9 @@ raise GossipReject("block is not from a higher slot than its parent") # [REJECT] The current finalized checkpoint is an ancestor of the block - checkpoint_block = get_checkpoint_block( - store, block.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of block") # [REJECT] The block is proposed by the expected proposer for the slot @@ -13920,19 +14581,19 @@ raise GossipReject("block proposer_index does not match expected proposer") # Mark this block as seen - seen.proposer_slots.add((block.proposer_index, block.slot)) + seen.proposer_slots.add(proposer_slot_key) - name: validate_beacon_block_gossip#bellatrix sources: [] spec: | - + def validate_beacon_block_gossip( seen: Seen, store: Store, state: BeaconState, signed_beacon_block: SignedBeaconBlock, - current_time_ms: uint64, + current_time_ms: Uint64, # [New in Bellatrix] block_payload_statuses: Dict[Root, PayloadValidationStatus], ) -> None: @@ -13945,7 +14606,7 @@ # [IGNORE] The block is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block.slot, current_time_ms): + if is_future_slot(store, block.slot, current_time_ms): raise GossipIgnore("block is from a future slot") # [IGNORE] The block is from a slot greater than the latest finalized slot @@ -13955,9 +14616,10 @@ if block.slot <= finalized_slot: raise GossipIgnore("block is not from a slot greater than the latest finalized slot") - # [IGNORE] The block is the first block with valid signature received for the proposer for the slot - if (block.proposer_index, block.slot) in seen.proposer_slots: - raise GossipIgnore("block is not the first valid block for this proposer and slot") + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") # [REJECT] The proposer index is a valid validator index if block.proposer_index >= len(state.validators): @@ -13987,15 +14649,15 @@ if block.parent_root not in store.block_states: if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED: - # [REJECT] The block's parent passes validation - raise GossipReject("block's parent is invalid and EL result is unknown") + # [REJECT] The block's parent failed validation and its execution payload is optimistic + raise GossipReject("block's parent is invalid and its payload is optimistic") - # [IGNORE] The block's parent passes validation - raise GossipIgnore("block's parent is invalid and EL result is known") + # [IGNORE] The block's parent failed validation and its execution payload is processed + raise GossipIgnore("block's parent is invalid and its payload is processed") - # [IGNORE] The block's parent's execution payload passes validation + # [IGNORE] The block's parent passed validation but its execution payload is invalid if parent_payload_status == PAYLOAD_STATUS_INVALIDATED: - raise GossipIgnore("block's parent is valid and EL result is invalid") + raise GossipIgnore("block's parent is valid and its payload is invalid") # [REJECT] The block's parent passes validation elif block.parent_root not in store.block_states: @@ -14007,10 +14669,9 @@ raise GossipReject("block is not from a higher slot than its parent") # [REJECT] The current finalized checkpoint is an ancestor of the block - checkpoint_block = get_checkpoint_block( - store, block.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of block") # [REJECT] The block is proposed by the expected proposer for the slot @@ -14022,19 +14683,19 @@ raise GossipReject("block proposer_index does not match expected proposer") # Mark this block as seen - seen.proposer_slots.add((block.proposer_index, block.slot)) + seen.proposer_slots.add(proposer_slot_key) - name: validate_beacon_block_gossip#capella sources: [] spec: | - + def validate_beacon_block_gossip( seen: Seen, store: Store, state: BeaconState, signed_beacon_block: SignedBeaconBlock, - current_time_ms: uint64, + current_time_ms: Uint64, block_payload_statuses: Dict[Root, PayloadValidationStatus], ) -> None: """ @@ -14046,7 +14707,7 @@ # [IGNORE] The block is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block.slot, current_time_ms): + if is_future_slot(store, block.slot, current_time_ms): raise GossipIgnore("block is from a future slot") # [IGNORE] The block is from a slot greater than the latest finalized slot @@ -14056,9 +14717,10 @@ if block.slot <= finalized_slot: raise GossipIgnore("block is not from a slot greater than the latest finalized slot") - # [IGNORE] The block is the first block with valid signature received for the proposer for the slot - if (block.proposer_index, block.slot) in seen.proposer_slots: - raise GossipIgnore("block is not the first valid block for this proposer and slot") + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") # [REJECT] The proposer index is a valid validator index if block.proposer_index >= len(state.validators): @@ -14086,25 +14748,24 @@ if block.parent_root not in store.block_states: if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED: - # [REJECT] The block's parent passes validation - raise GossipReject("block's parent is invalid and EL result is unknown") + # [REJECT] The block's parent failed validation and its execution payload is optimistic + raise GossipReject("block's parent is invalid and its payload is optimistic") - # [IGNORE] The block's parent passes validation - raise GossipIgnore("block's parent is invalid and EL result is known") + # [IGNORE] The block's parent failed validation and its execution payload is processed + raise GossipIgnore("block's parent is invalid and its payload is processed") - # [IGNORE] The block's parent's execution payload passes validation + # [IGNORE] The block's parent passed validation but its execution payload is invalid if parent_payload_status == PAYLOAD_STATUS_INVALIDATED: - raise GossipIgnore("block's parent is valid and EL result is invalid") + raise GossipIgnore("block's parent is valid and its payload is invalid") # [REJECT] The block is from a higher slot than its parent if block.slot <= store.blocks[block.parent_root].slot: raise GossipReject("block is not from a higher slot than its parent") # [REJECT] The current finalized checkpoint is an ancestor of the block - checkpoint_block = get_checkpoint_block( - store, block.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of block") # [REJECT] The block is proposed by the expected proposer for the slot @@ -14116,19 +14777,19 @@ raise GossipReject("block proposer_index does not match expected proposer") # Mark this block as seen - seen.proposer_slots.add((block.proposer_index, block.slot)) + seen.proposer_slots.add(proposer_slot_key) - name: validate_beacon_block_gossip#deneb sources: [] spec: | - + def validate_beacon_block_gossip( seen: Seen, store: Store, state: BeaconState, signed_beacon_block: SignedBeaconBlock, - current_time_ms: uint64, + current_time_ms: Uint64, block_payload_statuses: Dict[Root, PayloadValidationStatus], ) -> None: """ @@ -14140,7 +14801,7 @@ # [IGNORE] The block is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block.slot, current_time_ms): + if is_future_slot(store, block.slot, current_time_ms): raise GossipIgnore("block is from a future slot") # [IGNORE] The block is from a slot greater than the latest finalized slot @@ -14150,9 +14811,10 @@ if block.slot <= finalized_slot: raise GossipIgnore("block is not from a slot greater than the latest finalized slot") - # [IGNORE] The block is the first block with valid signature received for the proposer for the slot - if (block.proposer_index, block.slot) in seen.proposer_slots: - raise GossipIgnore("block is not the first valid block for this proposer and slot") + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") # [REJECT] The proposer index is a valid validator index if block.proposer_index >= len(state.validators): @@ -14180,25 +14842,24 @@ if block.parent_root not in store.block_states: if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED: - # [REJECT] The block's parent passes validation - raise GossipReject("block's parent is invalid and EL result is unknown") + # [REJECT] The block's parent failed validation and its execution payload is optimistic + raise GossipReject("block's parent is invalid and its payload is optimistic") - # [IGNORE] The block's parent passes validation - raise GossipIgnore("block's parent is invalid and EL result is known") + # [IGNORE] The block's parent failed validation and its execution payload is processed + raise GossipIgnore("block's parent is invalid and its payload is processed") - # [IGNORE] The block's parent's execution payload passes validation + # [IGNORE] The block's parent passed validation but its execution payload is invalid if parent_payload_status == PAYLOAD_STATUS_INVALIDATED: - raise GossipIgnore("block's parent is valid and EL result is invalid") + raise GossipIgnore("block's parent is valid and its payload is invalid") # [REJECT] The block is from a higher slot than its parent if block.slot <= store.blocks[block.parent_root].slot: raise GossipReject("block is not from a higher slot than its parent") # [REJECT] The current finalized checkpoint is an ancestor of the block - checkpoint_block = get_checkpoint_block( - store, block.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of block") # [New in Deneb:EIP4844] @@ -14215,19 +14876,19 @@ raise GossipReject("block proposer_index does not match expected proposer") # Mark this block as seen - seen.proposer_slots.add((block.proposer_index, block.slot)) + seen.proposer_slots.add(proposer_slot_key) - name: validate_beacon_block_gossip#electra sources: [] spec: | - + def validate_beacon_block_gossip( seen: Seen, store: Store, state: BeaconState, signed_beacon_block: SignedBeaconBlock, - current_time_ms: uint64, + current_time_ms: Uint64, block_payload_statuses: Dict[Root, PayloadValidationStatus], ) -> None: """ @@ -14239,7 +14900,7 @@ # [IGNORE] The block is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block.slot, current_time_ms): + if is_future_slot(store, block.slot, current_time_ms): raise GossipIgnore("block is from a future slot") # [IGNORE] The block is from a slot greater than the latest finalized slot @@ -14249,9 +14910,10 @@ if block.slot <= finalized_slot: raise GossipIgnore("block is not from a slot greater than the latest finalized slot") - # [IGNORE] The block is the first block with valid signature received for the proposer for the slot - if (block.proposer_index, block.slot) in seen.proposer_slots: - raise GossipIgnore("block is not the first valid block for this proposer and slot") + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") # [REJECT] The proposer index is a valid validator index if block.proposer_index >= len(state.validators): @@ -14279,25 +14941,24 @@ if block.parent_root not in store.block_states: if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED: - # [REJECT] The block's parent passes validation - raise GossipReject("block's parent is invalid and EL result is unknown") + # [REJECT] The block's parent failed validation and its execution payload is optimistic + raise GossipReject("block's parent is invalid and its payload is optimistic") - # [IGNORE] The block's parent passes validation - raise GossipIgnore("block's parent is invalid and EL result is known") + # [IGNORE] The block's parent failed validation and its execution payload is processed + raise GossipIgnore("block's parent is invalid and its payload is processed") - # [IGNORE] The block's parent's execution payload passes validation + # [IGNORE] The block's parent passed validation but its execution payload is invalid if parent_payload_status == PAYLOAD_STATUS_INVALIDATED: - raise GossipIgnore("block's parent is valid and EL result is invalid") + raise GossipIgnore("block's parent is valid and its payload is invalid") # [REJECT] The block is from a higher slot than its parent if block.slot <= store.blocks[block.parent_root].slot: raise GossipReject("block is not from a higher slot than its parent") # [REJECT] The current finalized checkpoint is an ancestor of the block - checkpoint_block = get_checkpoint_block( - store, block.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of block") # [Modified in Electra:EIP7691] @@ -14314,33 +14975,31 @@ raise GossipReject("block proposer_index does not match expected proposer") # Mark this block as seen - seen.proposer_slots.add((block.proposer_index, block.slot)) + seen.proposer_slots.add(proposer_slot_key) - name: validate_beacon_block_gossip#fulu sources: [] spec: | - + def validate_beacon_block_gossip( seen: Seen, store: Store, state: BeaconState, signed_beacon_block: SignedBeaconBlock, - current_time_ms: uint64, - block_payload_statuses: Optional[Dict[Root, PayloadValidationStatus]] = None, + current_time_ms: Uint64, + block_payload_statuses: Dict[Root, PayloadValidationStatus], ) -> None: """ Validate a SignedBeaconBlock for gossip propagation. Raises GossipIgnore or GossipReject on validation failure. """ - if block_payload_statuses is None: - block_payload_statuses = {} block = signed_beacon_block.message execution_payload = block.body.execution_payload # [IGNORE] The block is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block.slot, current_time_ms): + if is_future_slot(store, block.slot, current_time_ms): raise GossipIgnore("block is from a future slot") # [IGNORE] The block is from a slot greater than the latest finalized slot @@ -14350,9 +15009,10 @@ if block.slot <= finalized_slot: raise GossipIgnore("block is not from a slot greater than the latest finalized slot") - # [IGNORE] The block is the first block with valid signature received for the proposer for the slot - if (block.proposer_index, block.slot) in seen.proposer_slots: - raise GossipIgnore("block is not the first valid block for this proposer and slot") + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") # [REJECT] The proposer index is a valid validator index if block.proposer_index >= len(state.validators): @@ -14380,55 +15040,164 @@ if block.parent_root not in store.block_states: if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED: - # [REJECT] The block's parent passes validation - raise GossipReject("block's parent is invalid and EL result is unknown") + # [REJECT] The block's parent failed validation and its execution payload is optimistic + raise GossipReject("block's parent is invalid and its payload is optimistic") + + # [IGNORE] The block's parent failed validation and its execution payload is processed + raise GossipIgnore("block's parent is invalid and its payload is processed") + + # [IGNORE] The block's parent passed validation but its execution payload is invalid + if parent_payload_status == PAYLOAD_STATUS_INVALIDATED: + raise GossipIgnore("block's parent is valid and its payload is invalid") + + # [REJECT] The block is from a higher slot than its parent + if block.slot <= store.blocks[block.parent_root].slot: + raise GossipReject("block is not from a higher slot than its parent") - # [IGNORE] The block's parent passes validation - raise GossipIgnore("block's parent is invalid and EL result is known") + # [REJECT] The current finalized checkpoint is an ancestor of the block + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: + raise GossipReject("finalized checkpoint is not an ancestor of block") + + # [Modified in Fulu:EIP7892] + # [REJECT] The length of KZG commitments is less than or equal to the limit + max_blobs = get_blob_parameters(get_current_epoch(state)).max_blobs_per_block + if len(block.body.blob_kzg_commitments) > max_blobs: + raise GossipReject("too many blob kzg commitments") + + # [REJECT] The block is proposed by the expected proposer for the slot + # (if shuffling is not available, IGNORE instead and MAY be queued for later) + parent_state = store.block_states[block.parent_root].copy() + process_slots(parent_state, block.slot) + expected_proposer = get_beacon_proposer_index(parent_state) + if block.proposer_index != expected_proposer: + raise GossipReject("block proposer_index does not match expected proposer") + + # Mark this block as seen + seen.proposer_slots.add(proposer_slot_key) + + +- name: validate_beacon_block_gossip#gloas + sources: [] + spec: | + + def validate_beacon_block_gossip( + seen: Seen, + store: Store, + state: BeaconState, + signed_beacon_block: SignedBeaconBlock, + current_time_ms: Uint64, + # [Modified in Gloas:EIP7732] + # Removed `block_payload_statuses` + ) -> None: + """ + Validate a SignedBeaconBlock for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + block = signed_beacon_block.message + bid = block.body.signed_execution_payload_bid.message + + # [IGNORE] The block is not from a future slot + # (MAY be queued for processing at the appropriate slot) + if is_future_slot(store, block.slot, current_time_ms): + raise GossipIgnore("block is from a future slot") + + # [IGNORE] The block is from a slot greater than the latest finalized slot + # (MAY choose to validate and store such blocks for additional purposes + # -- e.g. slashing detection, archive nodes, etc) + finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + if block.slot <= finalized_slot: + raise GossipIgnore("block is not from a slot greater than the latest finalized slot") + + # [IGNORE] The block is the first block with valid signature received for the slot and proposer + proposer_slot_key = (block.slot, block.proposer_index) + if proposer_slot_key in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this slot and proposer") + + # [New in Gloas:EIP7688] + # [REJECT] The block body operation counts are within their limits + verify_block_body_operation_limits(block.body) + + # [New in Gloas:EIP7688] + # [REJECT] The parent execution request counts are within their limits + verify_execution_requests_limits(block.body.parent_execution_requests) + + # [REJECT] The proposer index is a valid validator index + if block.proposer_index >= len(state.validators): + raise GossipReject("proposer index out of range") + + # [REJECT] The proposer signature is valid + proposer = state.validators[block.proposer_index] + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block.slot)) + signing_root = compute_signing_root(block, domain) + if not bls.Verify(proposer.pubkey, signing_root, signed_beacon_block.signature): + raise GossipReject("invalid proposer signature") + + # [IGNORE] The block's parent has been seen (via gossip or non-gossip sources) + # (MAY be queued until parent is retrieved) + if block.parent_root not in store.blocks: + raise GossipIgnore("block's parent has not been seen") - # [IGNORE] The block's parent's execution payload passes validation - if parent_payload_status == PAYLOAD_STATUS_INVALIDATED: - raise GossipIgnore("block's parent is valid and EL result is invalid") + # [New in Gloas:EIP7732] + # [IGNORE] If the parent block is full, the parent payload is valid + # (MAY be queued until the parent payload is verified) + if is_parent_node_full(store, block): + if not is_payload_verified(store, block.parent_root): + raise GossipIgnore("parent payload is not verified") # [REJECT] The block is from a higher slot than its parent if block.slot <= store.blocks[block.parent_root].slot: raise GossipReject("block is not from a higher slot than its parent") # [REJECT] The current finalized checkpoint is an ancestor of the block - checkpoint_block = get_checkpoint_block( - store, block.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, block.parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of block") - # [Modified in Fulu:EIP7892] - # [REJECT] The length of KZG commitments is less than or equal to the limit + # [Modified in Gloas:EIP7732] + # [REJECT] The bid's blob KZG commitment count is within the per-epoch limit max_blobs = get_blob_parameters(get_current_epoch(state)).max_blobs_per_block - if len(block.body.blob_kzg_commitments) > max_blobs: + if len(bid.blob_kzg_commitments) > max_blobs: raise GossipReject("too many blob kzg commitments") + # [Modified in Gloas:EIP7732] + # [REJECT] The bid's parent equals the block's parent + if bid.parent_block_root != block.parent_root: + raise GossipReject("bid's parent does not equal block's parent") + + # [REJECT] The block's parent passes validation + if block.parent_root not in store.block_states: + raise GossipReject("block's parent is invalid") + # [REJECT] The block is proposed by the expected proposer for the slot - # (if shuffling is not available, IGNORE instead and MAY be queued for later) parent_state = store.block_states[block.parent_root].copy() process_slots(parent_state, block.slot) expected_proposer = get_beacon_proposer_index(parent_state) if block.proposer_index != expected_proposer: raise GossipReject("block proposer_index does not match expected proposer") + # [New in Gloas:EIP7732] + # [REJECT] If the parent is not full, the bid builds on the parent's execution head + if not is_parent_node_full(store, block): + if bid.parent_block_hash != parent_state.latest_block_hash: + raise GossipReject("bid does not build on the parent's execution head") + # Mark this block as seen - seen.proposer_slots.add((block.proposer_index, block.slot)) + seen.proposer_slots.add(proposer_slot_key) - name: validate_blob_sidecar_gossip#deneb sources: [] spec: | - + def validate_blob_sidecar_gossip( seen: Seen, store: Store, state: BeaconState, blob_sidecar: BlobSidecar, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -14447,7 +15216,7 @@ # [IGNORE] The sidecar is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block_header.slot, current_time_ms): + if is_future_slot(store, block_header.slot, current_time_ms): raise GossipIgnore("blob sidecar is from a future slot") # [IGNORE] The sidecar is from a slot greater than the latest finalized slot @@ -14468,22 +15237,22 @@ # [IGNORE] The sidecar's block's parent has been seen # (MAY be queued for processing once the parent block is retrieved) - if block_header.parent_root not in store.blocks: + parent_root = block_header.parent_root + if parent_root not in store.blocks: raise GossipIgnore("blob sidecar's parent has not been seen") # [REJECT] The sidecar's block's parent passes validation - if block_header.parent_root not in store.block_states: + if parent_root not in store.block_states: raise GossipReject("blob sidecar's parent failed validation") # [REJECT] The sidecar is from a higher slot than the sidecar's block's parent - if block_header.slot <= store.blocks[block_header.parent_root].slot: + if block_header.slot <= store.blocks[parent_root].slot: raise GossipReject("blob sidecar is not from a higher slot than its parent") # [REJECT] The current finalized_checkpoint is an ancestor of the sidecar's block - checkpoint_block = get_checkpoint_block( - store, block_header.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of blob sidecar's block") # [REJECT] The sidecar's inclusion proof is valid as verified by verify_blob_sidecar_inclusion_proof @@ -14491,7 +15260,7 @@ raise GossipReject("invalid blob sidecar inclusion proof") # [REJECT] The sidecar's blob is valid as verified by verify_blob_kzg_proof - if not verify_blob_kzg_proof( + if not kzg.verify_blob_kzg_proof( blob_sidecar.blob, blob_sidecar.kzg_commitment, blob_sidecar.kzg_proof ): raise GossipReject("invalid blob kzg proof") @@ -14504,7 +15273,7 @@ # [REJECT] The sidecar is proposed by the expected proposer_index # (if shuffling is not available, IGNORE instead and MAY be queued for later) - parent_state = store.block_states[block_header.parent_root].copy() + parent_state = store.block_states[parent_root].copy() process_slots(parent_state, block_header.slot) expected_proposer = get_beacon_proposer_index(parent_state) if block_header.proposer_index != expected_proposer: @@ -14517,13 +15286,13 @@ - name: validate_blob_sidecar_gossip#electra sources: [] spec: | - + def validate_blob_sidecar_gossip( seen: Seen, store: Store, state: BeaconState, blob_sidecar: BlobSidecar, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -14543,7 +15312,7 @@ # [IGNORE] The sidecar is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block_header.slot, current_time_ms): + if is_future_slot(store, block_header.slot, current_time_ms): raise GossipIgnore("blob sidecar is from a future slot") # [IGNORE] The sidecar is from a slot greater than the latest finalized slot @@ -14564,22 +15333,22 @@ # [IGNORE] The sidecar's block's parent has been seen # (MAY be queued for processing once the parent block is retrieved) - if block_header.parent_root not in store.blocks: + parent_root = block_header.parent_root + if parent_root not in store.blocks: raise GossipIgnore("blob sidecar's parent has not been seen") # [REJECT] The sidecar's block's parent passes validation - if block_header.parent_root not in store.block_states: + if parent_root not in store.block_states: raise GossipReject("blob sidecar's parent failed validation") # [REJECT] The sidecar is from a higher slot than the sidecar's block's parent - if block_header.slot <= store.blocks[block_header.parent_root].slot: + if block_header.slot <= store.blocks[parent_root].slot: raise GossipReject("blob sidecar is not from a higher slot than its parent") # [REJECT] The current finalized_checkpoint is an ancestor of the sidecar's block - checkpoint_block = get_checkpoint_block( - store, block_header.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of blob sidecar's block") # [REJECT] The sidecar's inclusion proof is valid as verified by verify_blob_sidecar_inclusion_proof @@ -14587,7 +15356,7 @@ raise GossipReject("invalid blob sidecar inclusion proof") # [REJECT] The sidecar's blob is valid as verified by verify_blob_kzg_proof - if not verify_blob_kzg_proof( + if not kzg.verify_blob_kzg_proof( blob_sidecar.blob, blob_sidecar.kzg_commitment, blob_sidecar.kzg_proof ): raise GossipReject("invalid blob kzg proof") @@ -14600,7 +15369,7 @@ # [REJECT] The sidecar is proposed by the expected proposer_index # (if shuffling is not available, IGNORE instead and MAY be queued for later) - parent_state = store.block_states[block_header.parent_root].copy() + parent_state = store.block_states[parent_root].copy() process_slots(parent_state, block_header.slot) expected_proposer = get_beacon_proposer_index(parent_state) if block_header.proposer_index != expected_proposer: @@ -14613,12 +15382,12 @@ - name: validate_bls_to_execution_change_gossip#capella sources: [] spec: | - + def validate_bls_to_execution_change_gossip( seen: Seen, state: BeaconState, signed_bls_to_execution_change: SignedBLSToExecutionChange, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> None: """ Validate a SignedBLSToExecutionChange for gossip propagation. @@ -14672,13 +15441,13 @@ - name: validate_data_column_sidecar_gossip#fulu sources: [] spec: | - + def validate_data_column_sidecar_gossip( seen: Seen, store: Store, state: BeaconState, sidecar: DataColumnSidecar, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -14689,8 +15458,8 @@ # [IGNORE] The sidecar is the first sidecar for the tuple # (block_header.slot, block_header.proposer_index, sidecar.index) - sidecar_tuple = (block_header.slot, block_header.proposer_index, sidecar.index) - if sidecar_tuple in seen.data_column_sidecar_tuples: + sidecar_key = (block_header.slot, block_header.proposer_index, sidecar.index) + if sidecar_key in seen.data_column_sidecar_tuples: raise GossipIgnore("already seen sidecar from this proposer for this slot and index") # [REJECT] The sidecar is valid as verified by verify_data_column_sidecar @@ -14703,7 +15472,7 @@ # [IGNORE] The sidecar is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block_header.slot, current_time_ms): + if is_future_slot(store, block_header.slot, current_time_ms): raise GossipIgnore("sidecar is from a future slot") # [IGNORE] The sidecar is from a slot greater than the latest finalized slot @@ -14724,22 +15493,22 @@ # [IGNORE] The sidecar's block's parent has been seen # (MAY be queued for processing once the parent block is retrieved) - if block_header.parent_root not in store.blocks: + parent_root = block_header.parent_root + if parent_root not in store.blocks: raise GossipIgnore("sidecar's parent has not been seen") # [REJECT] The sidecar's block's parent passes validation - if block_header.parent_root not in store.block_states: + if parent_root not in store.block_states: raise GossipReject("sidecar's parent failed validation") # [REJECT] The sidecar is from a higher slot than the sidecar's block's parent - if block_header.slot <= store.blocks[block_header.parent_root].slot: + if block_header.slot <= store.blocks[parent_root].slot: raise GossipReject("sidecar is not from a higher slot than its parent") # [REJECT] The current finalized_checkpoint is an ancestor of the sidecar's block - checkpoint_block = get_checkpoint_block( - store, block_header.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of sidecar's block") # [REJECT] The sidecar is valid as verified by verify_data_column_sidecar_inclusion_proof @@ -14752,20 +15521,275 @@ # [REJECT] The sidecar is proposed by the expected proposer_index # (if shuffling is not available, IGNORE instead and MAY be queued for later) - parent_state = store.block_states[block_header.parent_root].copy() + parent_state = store.block_states[parent_root].copy() process_slots(parent_state, block_header.slot) expected_proposer = get_beacon_proposer_index(parent_state) if block_header.proposer_index != expected_proposer: raise GossipReject("sidecar proposer_index does not match expected proposer") # Mark this data column sidecar as seen - seen.data_column_sidecar_tuples.add(sidecar_tuple) + seen.data_column_sidecar_tuples.add(sidecar_key) + + +- name: validate_data_column_sidecar_gossip#gloas + sources: [] + spec: | + + def validate_data_column_sidecar_gossip( + seen: Seen, + store: Store, + # [Modified in Gloas:EIP7732] + # Removed `state` + sidecar: DataColumnSidecar, + current_time_ms: Uint64, + subnet_id: SubnetID, + ) -> None: + """ + Validate a DataColumnSidecar for gossip propagation on a subnet. + Raises GossipIgnore or GossipReject on validation failure. + """ + # [IGNORE] This is the first sidecar seen for this block root and column index + sidecar_key = (sidecar.beacon_block_root, sidecar.index) + if sidecar_key in seen.data_column_sidecar_tuples: + raise GossipIgnore("already seen sidecar for this block root and index") + + # [REJECT] The sidecar is for the correct subnet + if compute_subnet_for_data_column_sidecar(sidecar.index) != subnet_id: + raise GossipReject("sidecar is for wrong subnet") + + # [IGNORE] The sidecar is not from a future slot + # (MAY be queued for processing at the appropriate slot) + if is_future_slot(store, sidecar.slot, current_time_ms): + raise GossipIgnore("sidecar is from a future slot") + + # [IGNORE] A block for the sidecar has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + # (SHOULD queue at least one sidecar per peer per subnet) + if sidecar.beacon_block_root not in store.blocks: + raise GossipIgnore("block for sidecar's beacon block root has not been seen") + + # [REJECT] The block for the sidecar passes validation + if sidecar.beacon_block_root not in store.block_states: + raise GossipReject("block for sidecar's beacon block root failed validation") + + block = store.blocks[sidecar.beacon_block_root] + + # [REJECT] The sidecar's slot matches the slot of the block + if sidecar.slot != block.slot: + raise GossipReject("sidecar's slot does not match block's slot") + + bid = block.body.signed_execution_payload_bid.message + + # [REJECT] The sidecar passes structural validation + if not verify_data_column_sidecar(sidecar, bid.blob_kzg_commitments): + raise GossipReject("invalid sidecar") + + # [REJECT] The sidecar's column data passes KZG verification + if not verify_data_column_sidecar_kzg_proofs(sidecar, bid.blob_kzg_commitments): + raise GossipReject("invalid sidecar kzg proofs") + + # Mark this data column sidecar as seen + seen.data_column_sidecar_tuples.add(sidecar_key) + + +- name: validate_execution_payload_bid_gossip#gloas + sources: [] + spec: | + + def validate_execution_payload_bid_gossip( + seen: Seen, + store: Store, + state: BeaconState, + signed_execution_payload_bid: SignedExecutionPayloadBid, + current_time_ms: Uint64, + ) -> None: + """ + Validate a SignedExecutionPayloadBid for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + bid = signed_execution_payload_bid.message + + # [IGNORE] The bid's slot is the current slot or the next slot + if not is_current_or_next_slot(store, bid.slot, current_time_ms): + raise GossipIgnore("bid's slot is not the current or next slot") + + # [IGNORE] This is the first bid for this slot, parent, and builder + bid_key = (bid.slot, bid.parent_block_hash, bid.parent_block_root, bid.builder_index) + if bid_key in seen.execution_payload_bids: + raise GossipIgnore("already seen valid bid for this slot, parent, and builder") + + # [IGNORE] This is the highest value bid seen for the slot and parent + best_bid_key = (bid.slot, bid.parent_block_hash, bid.parent_block_root) + if best_bid_key in seen.best_execution_payload_bid: + if bid.value <= seen.best_execution_payload_bid[best_bid_key]: + raise GossipIgnore("bid is not the highest value bid seen for this slot and parent") + + # [REJECT] The bid is for a higher slot than its parent block + if bid.slot <= state.slot: + raise GossipReject("bid's slot is not higher than its parent's slot") + + # [REJECT] The bid's execution payment is zero + if bid.execution_payment != 0: + raise GossipReject("bid's execution payment must be zero") + + # [REJECT] The bid's blob KZG commitment count is within the per-epoch limit + proposal_epoch = compute_epoch_at_slot(bid.slot) + max_blobs = get_blob_parameters(proposal_epoch).max_blobs_per_block + if len(bid.blob_kzg_commitments) > max_blobs: + raise GossipReject("too many blob kzg commitments") + + # [IGNORE] The bid's parent block root is a known beacon block + # (MAY be queued until parent is retrieved) + if bid.parent_block_root not in store.blocks: + raise GossipIgnore("bid's parent block root is not a known beacon block") + + # [IGNORE] The state is the bid's parent block post-state + parent_block = store.blocks[bid.parent_block_root] + header = state.latest_block_header.copy() + header.state_root = parent_block.state_root + if hash_tree_root(header) != bid.parent_block_root: + raise GossipIgnore("state is not the bid's parent block post-state") + + # [IGNORE] The bid's slot is within the parent's proposer lookahead + if proposal_epoch > get_current_epoch(state) + Epoch(MIN_SEED_LOOKAHEAD): + raise GossipIgnore("bid's slot is past the parent's proposer lookahead") + + # [IGNORE] The matching proposer preferences have been seen + dependent_root = get_shuffling_dependent_root(store, bid.parent_block_root, proposal_epoch) + prefs_key = (dependent_root, bid.slot) + if prefs_key not in seen.proposer_preferences: + raise GossipIgnore("matching proposer preferences have not been seen") + + proposer_preferences = seen.proposer_preferences[prefs_key] + + # [IGNORE] The bid's fee recipient matches the proposer's preference + if bid.fee_recipient != proposer_preferences.fee_recipient: + raise GossipIgnore("bid's fee recipient does not match the proposer's preference") + + # [IGNORE] The bid's parent block hash is the hash of a known execution payload + if bid.parent_block_hash not in seen.execution_payloads: + raise GossipIgnore("bid's parent block hash is not a known execution payload") + + # [IGNORE] The bid's gas limit is compatible with the proposer's target gas limit + parent_gas_limit = seen.execution_payloads[bid.parent_block_hash].gas_limit + if not is_gas_limit_target_compatible( + parent_gas_limit, bid.gas_limit, proposer_preferences.target_gas_limit + ): + raise GossipIgnore("bid's gas limit is not compatible with the proposer's target") + + # [IGNORE] The bid is compatible with the current head branch + if not is_bid_compatible_with_head(store, bid): + raise GossipIgnore("bid is not compatible with the current head branch") + + # [REJECT] The bid's previous randao is correct + if bid.prev_randao != get_randao_mix(state, get_current_epoch(state)): + raise GossipReject("bid's previous randao is incorrect") + + # Advance state + state = state.copy() + process_slots(state, bid.slot) + + # [REJECT] The builder index is valid + if bid.builder_index >= len(state.builders): + raise GossipReject("builder index out of range") + + # [IGNORE] The builder can cover the bid + if not can_builder_cover_bid(state, bid.builder_index, bid.value): + raise GossipIgnore("builder cannot cover bid value") + + # [REJECT] The builder is active + if not is_active_builder(state, bid.builder_index): + raise GossipReject("builder is not active") + + # [REJECT] The builder is a payload builder + if state.builders[bid.builder_index].version != PAYLOAD_BUILDER_VERSION: + raise GossipReject("builder is not a payload builder") + + # [REJECT] The bid signature is valid + if not verify_execution_payload_bid_signature(state, signed_execution_payload_bid): + raise GossipReject("invalid bid signature") + + # Mark this bid as seen and update the highest-value bid for this slot/parent + seen.execution_payload_bids.add(bid_key) + seen.best_execution_payload_bid[best_bid_key] = bid.value + + +- name: validate_execution_payload_envelope_gossip#gloas + sources: [] + spec: | + + def validate_execution_payload_envelope_gossip( + seen: Seen, + store: Store, + state: BeaconState, + signed_execution_payload_envelope: SignedExecutionPayloadEnvelope, + ) -> None: + """ + Validate a SignedExecutionPayloadEnvelope for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + envelope = signed_execution_payload_envelope.message + payload = envelope.payload + block_root = envelope.beacon_block_root + + # [IGNORE] The envelope's block root has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + if block_root not in store.blocks: + raise GossipIgnore("envelope's block has not been seen") + + # [REJECT] The envelope's block passes validation + if block_root not in store.block_states: + raise GossipReject("envelope's block failed validation") + + # [IGNORE] The node has not seen another valid envelope for this block root from this builder + envelope_key = (block_root, envelope.builder_index) + if envelope_key in seen.execution_payload_envelopes: + raise GossipIgnore("already seen envelope for this block root from this builder") + + # [IGNORE] The envelope is from a slot greater than or equal to the latest finalized slot + finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + if payload.slot_number < finalized_slot: + raise GossipIgnore("envelope is from a slot before the latest finalized slot") + + block = store.blocks[block_root] + bid = block.body.signed_execution_payload_bid.message + + # [REJECT] The block's slot matches the payload's slot number + if block.slot != payload.slot_number: + raise GossipReject("block's slot does not match payload's slot number") + + # [REJECT] The envelope is from the builder committed to by the bid + if envelope.builder_index != bid.builder_index: + raise GossipReject("envelope's builder index does not match the bid's builder index") + + # [REJECT] The payload's block hash matches the bid's block hash + if payload.block_hash != bid.block_hash: + raise GossipReject("payload's block hash does not match the bid's block hash") + + # [REJECT] The envelope's execution requests root matches the bid's execution requests root + if hash_tree_root(envelope.execution_requests) != bid.execution_requests_root: + raise GossipReject("envelope's execution requests root does not match the bid's") + + # [REJECT] The execution request counts are within their limits + verify_execution_requests_limits(envelope.execution_requests) + + # [REJECT] The number of withdrawals is within the limit + if len(payload.withdrawals) > MAX_WITHDRAWALS_PER_PAYLOAD: + raise GossipReject("too many withdrawals") + + # [REJECT] The envelope signature is valid + if not verify_execution_payload_envelope_signature(state, signed_execution_payload_envelope): + raise GossipReject("invalid envelope signature") + + # Mark this envelope as seen and store its payload + seen.execution_payload_envelopes.add(envelope_key) + seen.execution_payloads[payload.block_hash] = payload - name: validate_light_client_update#altair sources: [] spec: | - + def validate_light_client_update( store: LightClientStore, update: LightClientUpdate, @@ -14774,7 +15798,7 @@ ) -> None: # Verify sync committee has sufficient participants sync_aggregate = update.sync_aggregate - assert sum(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS + assert get_set_bit_count(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS # Verify update does not skip a sync committee period assert is_valid_light_client_header(update.attested_header) @@ -14962,33 +15986,33 @@ - name: validate_partial_data_column_sidecar_gossip#fulu sources: [] spec: | - + def validate_partial_data_column_sidecar_gossip( seen: Seen, store: Store, state: BeaconState, sidecar: PartialDataColumnSidecar, - block_root: Root, + current_time_ms: Uint64, + group_id: PartialDataColumnGroupID, column_index: ColumnIndex, - current_time_ms: uint64, ) -> None: """ Validate a PartialDataColumnSidecar for gossip propagation on a subnet. Raises GossipIgnore or GossipReject on validation failure. """ has_header = len(sidecar.header) == 1 - num_cells_present = sum(1 for b in sidecar.cells_present_bitmap if b) + num_cells_present = get_set_bit_count(sidecar.cells_present_bitmap) has_cells = num_cells_present > 0 # [REJECT] A header and/or cells are present in the message if not (has_header or has_cells): raise GossipReject("partial message is semantically empty") - # [REJECT] The cell count equals the number of bits set in cells_present_bitmap + # [REJECT] The cell count equals the number of set bits in the bitmap if len(sidecar.partial_column) != num_cells_present: raise GossipReject("number of cells does not match number of set bits") - # [REJECT] The proof count equals the number of bits set in cells_present_bitmap + # [REJECT] The proof count equals the number of set bits in the bitmap if len(sidecar.kzg_proofs) != num_cells_present: raise GossipReject("number of proofs does not match number of set bits") @@ -14997,13 +16021,13 @@ block_header = header.signed_block_header.message # [REJECT] The received header MUST equal any previously validated header for this block - prior_header = seen.partial_data_column_headers.get(block_root) + prior_header = seen.partial_data_column_headers.get(group_id.beacon_block_root) if prior_header is not None and prior_header != header: raise GossipReject("header differs from previously validated header") # [REJECT] The signed_block_header hash matches the partial message's group id - if hash_tree_root(block_header) != block_root: - raise GossipReject("header's block root does not match partial message group id") + if hash_tree_root(block_header) != group_id.beacon_block_root: + raise GossipReject("header's block root does not match group id's block root") # [REJECT] The header's kzg_commitments list is non-empty if len(header.kzg_commitments) == 0: @@ -15011,7 +16035,7 @@ # [IGNORE] The header is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block_header.slot, current_time_ms): + if is_future_slot(store, block_header.slot, current_time_ms): raise GossipIgnore("header is from a future slot") # [IGNORE] The header is from a slot greater than the latest finalized slot @@ -15032,22 +16056,22 @@ # [IGNORE] The header's block's parent has been seen # (MAY be queued for processing once the parent block is retrieved) - if block_header.parent_root not in store.blocks: + parent_root = block_header.parent_root + if parent_root not in store.blocks: raise GossipIgnore("header's parent has not been seen") # [REJECT] The header's block's parent passes validation - if block_header.parent_root not in store.block_states: + if parent_root not in store.block_states: raise GossipReject("header's parent failed validation") # [REJECT] The header is from a higher slot than the header's block's parent - if block_header.slot <= store.blocks[block_header.parent_root].slot: + if block_header.slot <= store.blocks[parent_root].slot: raise GossipReject("header is not from a higher slot than its parent") # [REJECT] The current finalized_checkpoint is an ancestor of the header's block - checkpoint_block = get_checkpoint_block( - store, block_header.parent_root, store.finalized_checkpoint.epoch - ) - if checkpoint_block != store.finalized_checkpoint.root: + finalized_epoch = store.finalized_checkpoint.epoch + finalized_checkpoint_block = get_checkpoint_block(store, parent_root, finalized_epoch) + if finalized_checkpoint_block != store.finalized_checkpoint.root: raise GossipReject("finalized checkpoint is not an ancestor of header's block") # [REJECT] The header's kzg_commitments inclusion proof is valid @@ -15056,18 +16080,18 @@ # [REJECT] The header is proposed by the expected proposer_index # (if shuffling is not available, IGNORE instead and MAY be queued for later) - parent_state = store.block_states[block_header.parent_root].copy() + parent_state = store.block_states[parent_root].copy() process_slots(parent_state, block_header.slot) expected_proposer = get_beacon_proposer_index(parent_state) if block_header.proposer_index != expected_proposer: raise GossipReject("header proposer_index does not match expected proposer") # Mark this header as seen - seen.partial_data_column_headers[block_root] = header + seen.partial_data_column_headers[group_id.beacon_block_root] = header if has_cells: # [IGNORE] A valid corresponding PartialDataColumnHeader has been seen - header = seen.partial_data_column_headers.get(block_root) + header = seen.partial_data_column_headers.get(group_id.beacon_block_root) if header is None: raise GossipIgnore("valid corresponding header has not been seen") @@ -15075,7 +16099,7 @@ # [IGNORE] The corresponding header is not from a future slot # (MAY be queued for processing at the appropriate slot) - if not is_not_from_future_slot(state, block_header.slot, current_time_ms): + if is_future_slot(store, block_header.slot, current_time_ms): raise GossipIgnore("corresponding header is from a future slot") # [IGNORE] The corresponding header is from a slot greater than the latest finalized slot @@ -15085,17 +16109,212 @@ "corresponding header is not from a slot greater than the latest finalized slot" ) - # [REJECT] The cells_present_bitmap length equals the number of header kzg_commitments + # [REJECT] The cells present bitmap length equals the number of header commitments if len(sidecar.cells_present_bitmap) != len(header.kzg_commitments): raise GossipReject("bitmap length does not match commitments length") - # [REJECT] The sidecar's cell and proof data is valid + # [REJECT] The sidecar's cell and proof data passes KZG verification if not verify_partial_data_column_sidecar_kzg_proofs( sidecar, header.kzg_commitments, column_index ): raise GossipReject("invalid sidecar kzg proofs") +- name: validate_partial_data_column_sidecar_gossip#gloas + sources: [] + spec: | + + def validate_partial_data_column_sidecar_gossip( + # [Modified in Gloas:EIP7732] + # Removed `seen` + store: Store, + # [Modified in Gloas:EIP7732] + # Removed `state` + sidecar: PartialDataColumnSidecar, + # [Modified in Gloas:EIP7732] + # Removed `current_time_ms` + group_id: PartialDataColumnGroupID, + column_index: ColumnIndex, + ) -> None: + """ + Validate a PartialDataColumnSidecar for gossip propagation on a subnet. + Raises GossipIgnore or GossipReject on validation failure. + """ + num_cells_present = get_set_bit_count(sidecar.cells_present_bitmap) + + # [Modified in Gloas:EIP7732] + # [REJECT] The message contains at least one cell + if num_cells_present == 0: + raise GossipReject("partial message is semantically empty") + + # [REJECT] The cell count equals the number of set bits in the bitmap + if len(sidecar.partial_column) != num_cells_present: + raise GossipReject("number of cells does not match number of set bits") + + # [REJECT] The proof count equals the number of set bits in the bitmap + if len(sidecar.kzg_proofs) != num_cells_present: + raise GossipReject("number of proofs does not match number of set bits") + + # [New in Gloas:EIP7732] + # [IGNORE] The group ID's block has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + # (SHOULD queue at least one sidecar per peer per subnet) + if group_id.beacon_block_root not in store.blocks: + raise GossipIgnore("group id's block has not been seen") + + # [New in Gloas:EIP7732] + # [REJECT] The group ID's block passes validation + if group_id.beacon_block_root not in store.block_states: + raise GossipReject("group id's block failed validation") + + block = store.blocks[group_id.beacon_block_root] + + # [New in Gloas:EIP7732] + # [REJECT] The group ID's slot matches the slot of the block + if group_id.slot != block.slot: + raise GossipReject("group id's slot does not match the block's slot") + + bid = block.body.signed_execution_payload_bid.message + + # [Modified in Gloas:EIP7732] + # [REJECT] The cells present bitmap length equals the number of bid commitments + if len(sidecar.cells_present_bitmap) != len(bid.blob_kzg_commitments): + raise GossipReject("bitmap length does not match commitments length") + + # [Modified in Gloas:EIP7732] + # [REJECT] The sidecar's cell and proof data passes KZG verification + if not verify_partial_data_column_sidecar_kzg_proofs( + sidecar, bid.blob_kzg_commitments, column_index + ): + raise GossipReject("invalid sidecar kzg proofs") + + +- name: validate_payload_attestation_message_gossip#gloas + sources: [] + spec: | + + def validate_payload_attestation_message_gossip( + seen: Seen, + store: Store, + state: BeaconState, + payload_attestation_message: PayloadAttestationMessage, + current_time_ms: Uint64, + ) -> None: + """ + Validate a PayloadAttestationMessage for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + data = payload_attestation_message.data + validator_index = payload_attestation_message.validator_index + + # [IGNORE] The payload attestation's slot is the current slot + if not is_current_slot(store, data.slot, current_time_ms): + raise GossipIgnore("payload attestation's slot is not the current slot") + + # [IGNORE] This is the first valid payload attestation from this validator index + payload_attestation_key = (data.slot, validator_index) + if payload_attestation_key in seen.payload_attestation_validators: + raise GossipIgnore("already seen payload attestation from this validator") + + # [IGNORE] The payload attestation's block has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + if data.beacon_block_root not in store.blocks: + raise GossipIgnore("payload attestation's block has not been seen") + + # [REJECT] The payload attestation's block passes validation + if data.beacon_block_root not in store.block_states: + raise GossipReject("payload attestation's block failed validation") + + # [IGNORE] The payload attestation's block is at the assigned slot + if store.blocks[data.beacon_block_root].slot != data.slot: + raise GossipIgnore("payload attestation's block is not at the assigned slot") + + # [REJECT] The validator index is valid + if validator_index >= len(state.validators): + raise GossipReject("validator index out of range") + + # [REJECT] The validator is a member of the payload timeliness committee + if validator_index not in get_ptc(state, data.slot): + raise GossipReject("validator is not in the payload timeliness committee") + + # [REJECT] The signature is valid with respect to the validator's public key + validator = state.validators[validator_index] + domain = get_domain(state, DOMAIN_PTC_ATTESTER, compute_epoch_at_slot(data.slot)) + signing_root = compute_signing_root(data, domain) + if not bls.Verify(validator.pubkey, signing_root, payload_attestation_message.signature): + raise GossipReject("invalid payload attestation signature") + + # Mark this payload_attestation as seen + seen.payload_attestation_validators.add(payload_attestation_key) + + +- name: validate_proposer_preferences_gossip#gloas + sources: [] + spec: | + + def validate_proposer_preferences_gossip( + seen: Seen, + store: Store, + signed_proposer_preferences: SignedProposerPreferences, + current_time_ms: Uint64, + ) -> None: + """ + Validate a SignedProposerPreferences for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + preferences = signed_proposer_preferences.message + proposal_epoch = compute_epoch_at_slot(preferences.proposal_slot) + + # [IGNORE] The proposal slot has not started yet + if is_past_slot(store, preferences.proposal_slot, current_time_ms): + raise GossipIgnore("proposal slot has already started") + + # [IGNORE] The proposer for the proposal slot is known + lookahead_epoch = Epoch(proposal_epoch - MIN_SEED_LOOKAHEAD) + lookahead_epoch_start_slot = compute_start_slot_at_epoch(lookahead_epoch) + if is_future_slot(store, lookahead_epoch_start_slot, current_time_ms): + raise GossipIgnore("proposer for the proposal slot is not yet known") + + # [IGNORE] The dependent block has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + if preferences.dependent_root not in store.blocks: + raise GossipIgnore("dependent block has not been seen") + + # [IGNORE] These are the first valid preferences seen for this dependent root and slot + prefs_key = (preferences.dependent_root, preferences.proposal_slot) + if prefs_key in seen.proposer_preferences: + raise GossipIgnore("already seen preferences for this dependent root and proposal slot") + + # [IGNORE] The dependent block passes validation + if preferences.dependent_root not in store.block_states: + raise GossipIgnore("dependent block failed validation") + + # [REJECT] The dependent root is a valid dependent block for the proposal slot + if store.blocks[preferences.dependent_root].slot >= lookahead_epoch_start_slot: + raise GossipReject("dependent root is not before the proposer lookahead epoch") + + # [IGNORE] The dependent root is a possible dependent block for the lookahead epoch + if not is_valid_dependent_root(store, preferences.dependent_root, lookahead_epoch): + raise GossipIgnore("dependent root is not a possible dependent block") + + # [REJECT] The validator is the proposer for the given slot in the proposer lookahead + lookahead_state = store.block_states[preferences.dependent_root].copy() + process_slots(lookahead_state, lookahead_epoch_start_slot) + lookahead_index = preferences.proposal_slot - lookahead_epoch_start_slot + if lookahead_state.proposer_lookahead[lookahead_index] != preferences.validator_index: + raise GossipReject("validator is not the proposer for the given slot") + + # [REJECT] The signature is valid with respect to the validator's public key + validator = lookahead_state.validators[preferences.validator_index] + domain = get_domain(lookahead_state, DOMAIN_PROPOSER_PREFERENCES, proposal_epoch) + signing_root = compute_signing_root(preferences, domain) + if not bls.Verify(validator.pubkey, signing_root, signed_proposer_preferences.signature): + raise GossipReject("invalid proposer preferences signature") + + # Mark these preferences as seen + seen.proposer_preferences[prefs_key] = preferences + + - name: validate_proposer_slashing_gossip#phase0 sources: [] spec: | @@ -15154,12 +16373,13 @@ - name: validate_sync_committee_contribution_and_proof_gossip#altair sources: [] spec: | - + def validate_sync_committee_contribution_and_proof_gossip( seen: Seen, + store: Store, state: BeaconState, signed_contribution_and_proof: SignedContributionAndProof, - current_time_ms: uint64, + current_time_ms: Uint64, ) -> None: """ Validate a SignedContributionAndProof for gossip propagation. @@ -15169,7 +16389,7 @@ contribution = contribution_and_proof.contribution # [IGNORE] The contribution's slot is for the current slot - if not is_current_slot(state, contribution.slot, current_time_ms): + if not is_current_slot(store, contribution.slot, current_time_ms): raise GossipIgnore("contribution is not for the current slot") # [REJECT] The subcommittee index is in the allowed range @@ -15209,11 +16429,11 @@ raise GossipIgnore("already seen contribution for this data") # [IGNORE] The sync committee contribution is the first valid contribution received - # for the aggregator with index contribution_and_proof.aggregator_index - # for the slot contribution.slot and subcommittee index contribution.subcommittee_index + # for the slot contribution.slot, aggregator with index contribution_and_proof.aggregator_index, + # and subcommittee index contribution.subcommittee_index aggregator_key = ( - contribution_and_proof.aggregator_index, contribution.slot, + contribution_and_proof.aggregator_index, contribution.subcommittee_index, ) if aggregator_key in seen.sync_contribution_aggregator_slots: @@ -15262,12 +16482,13 @@ - name: validate_sync_committee_message_gossip#altair sources: [] spec: | - + def validate_sync_committee_message_gossip( seen: Seen, + store: Store, state: BeaconState, sync_committee_message: SyncCommitteeMessage, - current_time_ms: uint64, + current_time_ms: Uint64, subnet_id: SubnetID, ) -> None: """ @@ -15275,7 +16496,7 @@ Raises GossipIgnore or GossipReject on validation failure. """ # [IGNORE] The message's slot is for the current slot - if not is_current_slot(state, sync_committee_message.slot, current_time_ms): + if not is_current_slot(store, sync_committee_message.slot, current_time_ms): raise GossipIgnore("message is not for the current slot") # [REJECT] The validator index is valid @@ -15437,6 +16658,46 @@ seen.voluntary_exit_indices.add(validator_index) +- name: verify_attestation_payload_status#gloas + sources: [] + spec: | + + def verify_attestation_payload_status( + store: Store, + data: AttestationData, + block_payload_statuses: Dict[Root, PayloadValidationStatus], + ) -> None: + """ + Verify that the attested payload status is consistent with the block's payload. + Raises GossipIgnore or GossipReject on validation failure. + """ + block_root = data.beacon_block_root + block = store.blocks[block_root] + + # [REJECT] For same-slot attestations, the payload cannot yet be present + if block.slot == data.slot and data.index != 0: + raise GossipReject("same-slot attestation must attest with index 0") + + if data.index != 1: + return + + # [IGNORE] The corresponding execution payload envelope has been seen and verified + # (MAY queue attestations for processing once the payload is retrieved and + # SHOULD request the payload envelope via ExecutionPayloadEnvelopesByRoot + # using data.beacon_block_root) + if not is_payload_verified(store, block_root): + raise GossipIgnore("execution payload envelope has not been seen") + + # [IGNORE] The attested execution payload is optimistic + payload_status = block_payload_statuses.get(block_root, PAYLOAD_STATUS_NOT_VALIDATED) + if payload_status == PAYLOAD_STATUS_NOT_VALIDATED: + raise GossipIgnore("attested payload is optimistic") + + # [REJECT] The attested execution payload is processed and invalid + if payload_status == PAYLOAD_STATUS_INVALIDATED: + raise GossipReject("attested payload is invalid") + + - name: verify_blob_sidecar_inclusion_proof#deneb sources: - file: consensus-types/blocks/kzg.go @@ -15456,6 +16717,44 @@ ) +- name: verify_block_body_operation_limits#gloas + sources: [] + spec: | + + def verify_block_body_operation_limits(body: BeaconBlockBody) -> None: + """ + Verify that each block body operation count is within its limit. + Raises GossipReject on validation failure. + """ + # [REJECT] The proposer slashing count is within the limit + if len(body.proposer_slashings) > MAX_PROPOSER_SLASHINGS: + raise GossipReject("too many proposer slashings") + + # [REJECT] The attester slashing count is within the limit + if len(body.attester_slashings) > MAX_ATTESTER_SLASHINGS_ELECTRA: + raise GossipReject("too many attester slashings") + + # [REJECT] The attestation count is within the limit + if len(body.attestations) > MAX_ATTESTATIONS_ELECTRA: + raise GossipReject("too many attestations") + + # [REJECT] The block contains no deposits + if len(body.deposits) != 0: + raise GossipReject("block must not contain deposits") + + # [REJECT] The voluntary exit count is within the limit + if len(body.voluntary_exits) > MAX_VOLUNTARY_EXITS: + raise GossipReject("too many voluntary exits") + + # [REJECT] The BLS to execution change count is within the limit + if len(body.bls_to_execution_changes) > MAX_BLS_TO_EXECUTION_CHANGES: + raise GossipReject("too many bls to execution changes") + + # [REJECT] The payload attestation count is within the limit + if len(body.payload_attestations) > MAX_PAYLOAD_ATTESTATIONS: + raise GossipReject("too many payload attestations") + + - name: verify_block_signature#phase0 sources: - file: beacon-chain/core/blocks/signature.go @@ -15475,7 +16774,7 @@ - file: beacon-chain/core/peerdas/p2p_interface.go search: func VerifyDataColumnSidecar( spec: | - + def verify_data_column_sidecar(sidecar: DataColumnSidecar) -> bool: """ Verify if the data column sidecar is valid. @@ -15493,10 +16792,12 @@ if len(sidecar.kzg_commitments) > get_blob_parameters(epoch).max_blobs_per_block: return False - # The column length must be equal to the number of commitments/proofs - if len(sidecar.column) != len(sidecar.kzg_commitments) or len(sidecar.column) != len( - sidecar.kzg_proofs - ): + # The column length must be equal to the number of commitments + if len(sidecar.column) != len(sidecar.kzg_commitments): + return False + + # The column length must be equal to the number of proofs + if len(sidecar.column) != len(sidecar.kzg_proofs): return False return True @@ -15505,11 +16806,11 @@ - name: verify_data_column_sidecar#gloas sources: [] spec: | - + def verify_data_column_sidecar( sidecar: DataColumnSidecar, # [New in Gloas:EIP7732] - kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK], + kzg_commitments: BlobKZGCommitments, ) -> bool: """ Verify if the data column sidecar is valid. @@ -15524,10 +16825,12 @@ return False # [Modified in Gloas:EIP7732] - # The column length must be equal to the number of commitments/proofs - if len(sidecar.column) != len(kzg_commitments) or len(sidecar.column) != len( - sidecar.kzg_proofs - ): + # The column length must be equal to the number of commitments + if len(sidecar.column) != len(kzg_commitments): + return False + + # The column length must be equal to the number of proofs + if len(sidecar.column) != len(sidecar.kzg_proofs): return False return True @@ -15557,7 +16860,7 @@ - file: beacon-chain/core/peerdas/p2p_interface.go search: func VerifyDataColumnsCellsKZGProofs( spec: | - + def verify_data_column_sidecar_kzg_proofs(sidecar: DataColumnSidecar) -> bool: """ Verify if the KZG proofs are correct. @@ -15566,7 +16869,7 @@ cell_indices = [CellIndex(sidecar.index)] * len(sidecar.column) # Batch verify that the cells match the corresponding commitments and proofs - return verify_cell_kzg_proof_batch( + return kzg.verify_cell_kzg_proof_batch( commitments_bytes=sidecar.kzg_commitments, cell_indices=cell_indices, cells=sidecar.column, @@ -15657,6 +16960,32 @@ return bls.Verify(pubkey, signing_root, signed_envelope.signature) +- name: verify_execution_requests_limits#gloas + sources: [] + spec: | + + def verify_execution_requests_limits(execution_requests: ExecutionRequests) -> None: + """ + Verify that each execution request count is within its limit. + Raises GossipReject on validation failure. + """ + # [REJECT] The withdrawal request count is within the limit + if len(execution_requests.withdrawals) > MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: + raise GossipReject("too many withdrawal requests") + + # [REJECT] The consolidation request count is within the limit + if len(execution_requests.consolidations) > MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: + raise GossipReject("too many consolidation requests") + + # [REJECT] The builder deposit request count is within the limit + if len(execution_requests.builder_deposits) > MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD: + raise GossipReject("too many builder deposit requests") + + # [REJECT] The builder exit request count is within the limit + if len(execution_requests.builder_exits) > MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD: + raise GossipReject("too many builder exit requests") + + - name: verify_partial_data_column_header_inclusion_proof#fulu sources: [] spec: | @@ -15677,10 +17006,10 @@ - name: verify_partial_data_column_sidecar_kzg_proofs#fulu sources: [] spec: | - + def verify_partial_data_column_sidecar_kzg_proofs( sidecar: PartialDataColumnSidecar, - all_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK], + all_commitments: BlobKZGCommitments, column_index: ColumnIndex, ) -> bool: """ @@ -15693,7 +17022,7 @@ cell_indices = [CellIndex(column_index)] * len(blob_indices) # Batch verify that the cells match the corresponding commitments and proofs - return verify_cell_kzg_proof_batch( + return kzg.verify_cell_kzg_proof_batch( commitments_bytes=[all_commitments[i] for i in blob_indices], cell_indices=cell_indices, cells=sidecar.partial_column, @@ -15706,8 +17035,8 @@ - file: time/slots/slottime.go search: func VotingPeriodStartTime( spec: | - - def voting_period_start_time(state: BeaconState) -> uint64: + + def voting_period_start_time(state: BeaconState) -> Uint64: eth1_voting_period_start_slot = Slot( state.slot - state.slot % (EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH) ) diff --git a/specrefs/presets.yml b/specrefs/presets.yml index c26f025218eb..5a768246cd11 100644 --- a/specrefs/presets.yml +++ b/specrefs/presets.yml @@ -4,22 +4,8 @@ search: BaseRewardFactor\s+.*yaml:"BASE_REWARD_FACTOR" regex: true spec: | - - BASE_REWARD_FACTOR: uint64 = 64 - - -- name: BUILDER_PENDING_WITHDRAWALS_LIMIT#gloas - sources: [] - spec: | - - BUILDER_PENDING_WITHDRAWALS_LIMIT: uint64 = 1048576 - - -- name: BUILDER_REGISTRY_LIMIT#gloas - sources: [] - spec: | - - BUILDER_REGISTRY_LIMIT: uint64 = 1099511627776 + + BASE_REWARD_FACTOR: Uint64 = 64 - name: BYTES_PER_LOGS_BLOOM#bellatrix @@ -28,8 +14,8 @@ search: BytesPerLogsBloom\s+.*yaml:"BYTES_PER_LOGS_BLOOM" regex: true spec: | - - BYTES_PER_LOGS_BLOOM: uint64 = 256 + + BYTES_PER_LOGS_BLOOM: Uint64 = 256 - name: CELLS_PER_EXT_BLOB#fulu @@ -58,8 +44,8 @@ search: EpochsPerEth1VotingPeriod\s+.*yaml:"EPOCHS_PER_ETH1_VOTING_PERIOD" regex: true spec: | - - EPOCHS_PER_ETH1_VOTING_PERIOD: uint64 = 64 + + EPOCHS_PER_ETH1_VOTING_PERIOD: Epoch = 64 - name: EPOCHS_PER_HISTORICAL_VECTOR#phase0 @@ -68,8 +54,8 @@ search: RandaoMixesLength\s*= regex: true spec: | - - EPOCHS_PER_HISTORICAL_VECTOR: uint64 = 65536 + + EPOCHS_PER_HISTORICAL_VECTOR: Epoch = 65536 - name: EPOCHS_PER_SLASHINGS_VECTOR#phase0 @@ -78,8 +64,8 @@ search: SlashingsLength\s*= regex: true spec: | - - EPOCHS_PER_SLASHINGS_VECTOR: uint64 = 8192 + + EPOCHS_PER_SLASHINGS_VECTOR: Epoch = 8192 - name: EPOCHS_PER_SYNC_COMMITTEE_PERIOD#altair @@ -88,8 +74,8 @@ search: EpochsPerSyncCommitteePeriod\s+.*yaml:"EPOCHS_PER_SYNC_COMMITTEE_PERIOD" regex: true spec: | - - EPOCHS_PER_SYNC_COMMITTEE_PERIOD: uint64 = 256 + + EPOCHS_PER_SYNC_COMMITTEE_PERIOD: Epoch = 256 - name: FIELD_ELEMENTS_PER_BLOB#deneb @@ -98,8 +84,8 @@ search: FieldElementsPerBlob\s+.*yaml:"FIELD_ELEMENTS_PER_BLOB" regex: true spec: | - - FIELD_ELEMENTS_PER_BLOB: uint64 = 4096 + + FIELD_ELEMENTS_PER_BLOB: Uint64 = 4096 - name: FIELD_ELEMENTS_PER_CELL#fulu @@ -108,8 +94,8 @@ search: CellsPerBlob\s*= regex: true spec: | - - FIELD_ELEMENTS_PER_CELL: uint64 = 64 + + FIELD_ELEMENTS_PER_CELL: Uint64 = 64 - name: FIELD_ELEMENTS_PER_EXT_BLOB#fulu @@ -128,8 +114,8 @@ search: HistoricalRootsLength\s*= regex: true spec: | - - HISTORICAL_ROOTS_LIMIT: uint64 = 16777216 + + HISTORICAL_ROOTS_LIMIT: Uint64 = 16777216 - name: HYSTERESIS_DOWNWARD_MULTIPLIER#phase0 @@ -138,8 +124,8 @@ search: HysteresisDownwardMultiplier\s+.*yaml:"HYSTERESIS_DOWNWARD_MULTIPLIER" regex: true spec: | - - HYSTERESIS_DOWNWARD_MULTIPLIER: uint64 = 1 + + HYSTERESIS_DOWNWARD_MULTIPLIER: Uint64 = 1 - name: HYSTERESIS_QUOTIENT#phase0 @@ -148,8 +134,8 @@ search: HysteresisQuotient\s+.*yaml:"HYSTERESIS_QUOTIENT" regex: true spec: | - - HYSTERESIS_QUOTIENT: uint64 = 4 + + HYSTERESIS_QUOTIENT: Uint64 = 4 - name: HYSTERESIS_UPWARD_MULTIPLIER#phase0 @@ -158,8 +144,8 @@ search: HysteresisUpwardMultiplier\s+.*yaml:"HYSTERESIS_UPWARD_MULTIPLIER" regex: true spec: | - - HYSTERESIS_UPWARD_MULTIPLIER: uint64 = 5 + + HYSTERESIS_UPWARD_MULTIPLIER: Uint64 = 5 - name: INACTIVITY_PENALTY_QUOTIENT#phase0 @@ -168,8 +154,8 @@ search: InactivityPenaltyQuotient\s+.*yaml:"INACTIVITY_PENALTY_QUOTIENT" regex: true spec: | - - INACTIVITY_PENALTY_QUOTIENT: uint64 = 67108864 + + INACTIVITY_PENALTY_QUOTIENT: Uint64 = 67108864 - name: INACTIVITY_PENALTY_QUOTIENT_ALTAIR#altair @@ -178,8 +164,8 @@ search: InactivityPenaltyQuotientAltair\s+.*yaml:"INACTIVITY_PENALTY_QUOTIENT_ALTAIR" regex: true spec: | - - INACTIVITY_PENALTY_QUOTIENT_ALTAIR: uint64 = 50331648 + + INACTIVITY_PENALTY_QUOTIENT_ALTAIR: Uint64 = 50331648 - name: INACTIVITY_PENALTY_QUOTIENT_BELLATRIX#bellatrix @@ -188,15 +174,15 @@ search: InactivityPenaltyQuotientBellatrix\s+.*yaml:"INACTIVITY_PENALTY_QUOTIENT_BELLATRIX" regex: true spec: | - - INACTIVITY_PENALTY_QUOTIENT_BELLATRIX: uint64 = 16777216 + + INACTIVITY_PENALTY_QUOTIENT_BELLATRIX: Uint64 = 16777216 - name: INCLUSION_LIST_COMMITTEE_SIZE#heze sources: [] spec: | - - INCLUSION_LIST_COMMITTEE_SIZE: uint64 = 16 + + INCLUSION_LIST_COMMITTEE_SIZE: Uint64 = 16 - name: KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH#fulu @@ -205,8 +191,8 @@ search: mainnet\s*=\s*\{[^}]*"kzg_commitments_inclusion_proof_depth\.size":.*[^}]*\} regex: true spec: | - - KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: uint64 = 4 + + KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: Uint64 = 4 - name: KZG_COMMITMENT_INCLUSION_PROOF_DEPTH#deneb @@ -215,8 +201,8 @@ search: KzgCommitmentInclusionProofDepth\s*= regex: true spec: | - - KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: uint64 = 17 + + KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: Uint64 = 17 - name: MAX_ATTESTATIONS#phase0 @@ -225,8 +211,8 @@ search: MaxAttestations\s+.*yaml:"MAX_ATTESTATIONS" regex: true spec: | - - MAX_ATTESTATIONS = 128 + + MAX_ATTESTATIONS: Uint64 = 128 - name: MAX_ATTESTATIONS_ELECTRA#electra @@ -235,8 +221,8 @@ search: MaxAttestationsElectra\s+.*yaml:"MAX_ATTESTATIONS_ELECTRA" regex: true spec: | - - MAX_ATTESTATIONS_ELECTRA = 8 + + MAX_ATTESTATIONS_ELECTRA: Uint64 = 8 - name: MAX_ATTESTER_SLASHINGS#phase0 @@ -245,8 +231,8 @@ search: MaxAttesterSlashings\s+.*yaml:"MAX_ATTESTER_SLASHINGS" regex: true spec: | - - MAX_ATTESTER_SLASHINGS = 2 + + MAX_ATTESTER_SLASHINGS: Uint64 = 2 - name: MAX_ATTESTER_SLASHINGS_ELECTRA#electra @@ -255,8 +241,15 @@ search: MaxAttesterSlashingsElectra\s+.*yaml:"MAX_ATTESTER_SLASHINGS_ELECTRA" regex: true spec: | - - MAX_ATTESTER_SLASHINGS_ELECTRA = 1 + + MAX_ATTESTER_SLASHINGS_ELECTRA: Uint64 = 1 + + +- name: MAX_ATTESTER_SLASHING_SIZE#gloas + sources: [] + spec: | + + MAX_ATTESTER_SLASHING_SIZE: Uint64 = 2097616 - name: MAX_BLOB_COMMITMENTS_PER_BLOCK#deneb @@ -265,8 +258,8 @@ search: MaxBlobCommitmentsPerBlock\s*= regex: true spec: | - - MAX_BLOB_COMMITMENTS_PER_BLOCK: uint64 = 4096 + + MAX_BLOB_COMMITMENTS_PER_BLOCK: Uint64 = 4096 - name: MAX_BLS_TO_EXECUTION_CHANGES#capella @@ -275,29 +268,29 @@ search: MaxBlsToExecutionChanges\s+.*yaml:"MAX_BLS_TO_EXECUTION_CHANGES" regex: true spec: | - - MAX_BLS_TO_EXECUTION_CHANGES = 16 + + MAX_BLS_TO_EXECUTION_CHANGES: Uint64 = 16 - name: MAX_BUILDERS_PER_WITHDRAWALS_SWEEP#gloas sources: [] spec: | - - MAX_BUILDERS_PER_WITHDRAWALS_SWEEP = 16384 + + MAX_BUILDERS_PER_WITHDRAWALS_SWEEP: Uint64 = 16384 - name: MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD#gloas sources: [] spec: | - - MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD: uint64 = 256 + + MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD: Uint64 = 64 - name: MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD#gloas sources: [] spec: | - - MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD: uint64 = 16 + + MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD: Uint64 = 16 - name: MAX_BYTES_PER_TRANSACTION#bellatrix @@ -306,8 +299,8 @@ search: MaxBytesPerTransaction\s+.*yaml:"MAX_BYTES_PER_TRANSACTION" regex: true spec: | - - MAX_BYTES_PER_TRANSACTION: uint64 = 1073741824 + + MAX_BYTES_PER_TRANSACTION: Uint64 = 1073741824 - name: MAX_COMMITTEES_PER_SLOT#phase0 @@ -316,8 +309,8 @@ search: MaxCommitteesPerSlot\s+.*yaml:"MAX_COMMITTEES_PER_SLOT" regex: true spec: | - - MAX_COMMITTEES_PER_SLOT: uint64 = 64 + + MAX_COMMITTEES_PER_SLOT: Uint64 = 64 - name: MAX_COMMITTEES_PER_SLOT#electra @@ -326,8 +319,8 @@ search: MaxCommitteesPerSlot\s+.*yaml:"MAX_COMMITTEES_PER_SLOT" regex: true spec: | - - MAX_COMMITTEES_PER_SLOT: uint64 = 64 + + MAX_COMMITTEES_PER_SLOT: Uint64 = 64 - name: MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD#electra @@ -336,8 +329,15 @@ search: MaxConsolidationsRequestsPerPayload\s+.*yaml:"MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD" regex: true spec: | - - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: uint64 = 2 + + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: Uint64 = 2 + + +- name: MAX_DATA_COLUMN_SIDECAR_SIZE#gloas + sources: [] + spec: | + + MAX_DATA_COLUMN_SIDECAR_SIZE: Uint64 = 8585272 - name: MAX_DEPOSITS#phase0 @@ -346,8 +346,8 @@ search: MaxDeposits\s+.*yaml:"MAX_DEPOSITS" regex: true spec: | - - MAX_DEPOSITS = 16 + + MAX_DEPOSITS: Uint64 = 16 - name: MAX_DEPOSIT_REQUESTS_PER_PAYLOAD#electra @@ -356,8 +356,8 @@ search: MaxDepositRequestsPerPayload\s+.*yaml:"MAX_DEPOSIT_REQUESTS_PER_PAYLOAD" regex: true spec: | - - MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: uint64 = 8192 + + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: Uint64 = 8192 - name: MAX_EFFECTIVE_BALANCE#phase0 @@ -386,15 +386,22 @@ search: MaxExtraDataBytes\s+.*yaml:"MAX_EXTRA_DATA_BYTES" regex: true spec: | - - MAX_EXTRA_DATA_BYTES = 32 + + MAX_EXTRA_DATA_BYTES: Uint64 = 32 + + +- name: MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE#gloas + sources: [] + spec: | + + MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: Uint64 = 8585741 - name: MAX_PAYLOAD_ATTESTATIONS#gloas sources: [] spec: | - - MAX_PAYLOAD_ATTESTATIONS = 4 + + MAX_PAYLOAD_ATTESTATIONS: Uint64 = 4 - name: MAX_PENDING_DEPOSITS_PER_EPOCH#electra @@ -403,8 +410,8 @@ search: MaxPendingDepositsPerEpoch\s+.*yaml:"MAX_PENDING_DEPOSITS_PER_EPOCH" regex: true spec: | - - MAX_PENDING_DEPOSITS_PER_EPOCH: uint64 = 16 + + MAX_PENDING_DEPOSITS_PER_EPOCH: Uint64 = 16 - name: MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP#electra @@ -413,8 +420,8 @@ search: MaxPendingPartialsPerWithdrawalsSweep\s+.*yaml:"MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP" regex: true spec: | - - MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: uint64 = 8 + + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: Uint64 = 8 - name: MAX_PROPOSER_SLASHINGS#phase0 @@ -423,8 +430,8 @@ search: MaxProposerSlashings\s+.*yaml:"MAX_PROPOSER_SLASHINGS" regex: true spec: | - - MAX_PROPOSER_SLASHINGS = 16 + + MAX_PROPOSER_SLASHINGS: Uint64 = 16 - name: MAX_SEED_LOOKAHEAD#phase0 @@ -433,8 +440,36 @@ search: MaxSeedLookahead\s+.*yaml:"MAX_SEED_LOOKAHEAD" regex: true spec: | - - MAX_SEED_LOOKAHEAD: uint64 = 4 + + MAX_SEED_LOOKAHEAD: Epoch = 4 + + +- name: MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE#gloas + sources: [] + spec: | + + MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE: Uint64 = 16829 + + +- name: MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE#gloas + sources: [] + spec: | + + MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: Uint64 = 196932 + + +- name: MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE_HEZE#heze + sources: [] + spec: | + + MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE_HEZE: Uint64 = 196934 + + +- name: MAX_SIGNED_INCLUSION_LIST_SIZE#heze + sources: [] + spec: | + + MAX_SIGNED_INCLUSION_LIST_SIZE: Uint64 = 8348 - name: MAX_TRANSACTIONS_PER_PAYLOAD#bellatrix @@ -443,8 +478,8 @@ search: MaxTransactionsPerPayload\s+.*yaml:"MAX_TRANSACTIONS_PER_PAYLOAD" regex: true spec: | - - MAX_TRANSACTIONS_PER_PAYLOAD: uint64 = 1048576 + + MAX_TRANSACTIONS_PER_PAYLOAD: Uint64 = 1048576 - name: MAX_VALIDATORS_PER_COMMITTEE#phase0 @@ -453,8 +488,8 @@ search: MaxValidatorsPerCommittee\s+.*yaml:"MAX_VALIDATORS_PER_COMMITTEE" regex: true spec: | - - MAX_VALIDATORS_PER_COMMITTEE: uint64 = 2048 + + MAX_VALIDATORS_PER_COMMITTEE: Uint64 = 2048 - name: MAX_VALIDATORS_PER_COMMITTEE#electra @@ -463,8 +498,8 @@ search: MaxValidatorsPerCommittee\s+.*yaml:"MAX_VALIDATORS_PER_COMMITTEE" regex: true spec: | - - MAX_VALIDATORS_PER_COMMITTEE: uint64 = 2048 + + MAX_VALIDATORS_PER_COMMITTEE: Uint64 = 2048 - name: MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP#capella @@ -473,8 +508,8 @@ search: MaxValidatorsPerWithdrawalsSweep\s+.*yaml:"MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP" regex: true spec: | - - MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP = 16384 + + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: Uint64 = 16384 - name: MAX_VOLUNTARY_EXITS#phase0 @@ -483,8 +518,8 @@ search: MaxVoluntaryExits\s+.*yaml:"MAX_VOLUNTARY_EXITS" regex: true spec: | - - MAX_VOLUNTARY_EXITS = 16 + + MAX_VOLUNTARY_EXITS: Uint64 = 16 - name: MAX_WITHDRAWALS_PER_PAYLOAD#capella @@ -493,8 +528,8 @@ search: MaxWithdrawalsPerPayload\s*= regex: true spec: | - - MAX_WITHDRAWALS_PER_PAYLOAD: uint64 = 16 + + MAX_WITHDRAWALS_PER_PAYLOAD: Uint64 = 16 - name: MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD#electra @@ -503,8 +538,8 @@ search: MaxWithdrawalRequestsPerPayload\s+.*yaml:"MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD" regex: true spec: | - - MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: uint64 = 16 + + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: Uint64 = 16 - name: MIN_ACTIVATION_BALANCE#electra @@ -523,8 +558,8 @@ search: MinAttestationInclusionDelay\s+.*yaml:"MIN_ATTESTATION_INCLUSION_DELAY" regex: true spec: | - - MIN_ATTESTATION_INCLUSION_DELAY: uint64 = 1 + + MIN_ATTESTATION_INCLUSION_DELAY: Slot = 1 - name: MIN_DEPOSIT_AMOUNT#phase0 @@ -543,8 +578,8 @@ search: MinEpochsToInactivityPenalty\s+.*yaml:"MIN_EPOCHS_TO_INACTIVITY_PENALTY" regex: true spec: | - - MIN_EPOCHS_TO_INACTIVITY_PENALTY: uint64 = 4 + + MIN_EPOCHS_TO_INACTIVITY_PENALTY: Epoch = 4 - name: MIN_SEED_LOOKAHEAD#phase0 @@ -553,8 +588,8 @@ search: MinSeedLookahead\s+.*yaml:"MIN_SEED_LOOKAHEAD" regex: true spec: | - - MIN_SEED_LOOKAHEAD: uint64 = 1 + + MIN_SEED_LOOKAHEAD: Epoch = 1 - name: MIN_SLASHING_PENALTY_QUOTIENT#phase0 @@ -563,8 +598,8 @@ search: MinSlashingPenaltyQuotient\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT" regex: true spec: | - - MIN_SLASHING_PENALTY_QUOTIENT: uint64 = 128 + + MIN_SLASHING_PENALTY_QUOTIENT: Uint64 = 128 - name: MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR#altair @@ -573,8 +608,8 @@ search: MinSlashingPenaltyQuotientAltair\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR" regex: true spec: | - - MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: uint64 = 64 + + MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: Uint64 = 64 - name: MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX#bellatrix @@ -583,8 +618,8 @@ search: MinSlashingPenaltyQuotientBellatrix\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX" regex: true spec: | - - MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX: uint64 = 32 + + MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX: Uint64 = 32 - name: MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA#electra @@ -593,8 +628,8 @@ search: MinSlashingPenaltyQuotientElectra\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA" regex: true spec: | - - MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: uint64 = 4096 + + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: Uint64 = 4096 - name: MIN_SYNC_COMMITTEE_PARTICIPANTS#altair @@ -603,8 +638,8 @@ search: MinSyncCommitteeParticipants\s+.*yaml:"MIN_SYNC_COMMITTEE_PARTICIPANTS" regex: true spec: | - - MIN_SYNC_COMMITTEE_PARTICIPANTS = 1 + + MIN_SYNC_COMMITTEE_PARTICIPANTS: Uint64 = 1 - name: NUMBER_OF_COLUMNS#fulu @@ -613,8 +648,8 @@ search: NumberOfColumns\s*= regex: true spec: | - - NUMBER_OF_COLUMNS: uint64 = 128 + + NUMBER_OF_COLUMNS: Uint64 = 128 - name: PENDING_CONSOLIDATIONS_LIMIT#electra @@ -623,8 +658,8 @@ search: PendingConsolidationsLimit\s*= regex: true spec: | - - PENDING_CONSOLIDATIONS_LIMIT: uint64 = 262144 + + PENDING_CONSOLIDATIONS_LIMIT: Uint64 = 262144 - name: PENDING_DEPOSITS_LIMIT#electra @@ -633,8 +668,8 @@ search: PendingDepositsLimit\s*= regex: true spec: | - - PENDING_DEPOSITS_LIMIT: uint64 = 134217728 + + PENDING_DEPOSITS_LIMIT: Uint64 = 134217728 - name: PENDING_PARTIAL_WITHDRAWALS_LIMIT#electra @@ -643,8 +678,8 @@ search: PendingPartialWithdrawalsLimit\s*= regex: true spec: | - - PENDING_PARTIAL_WITHDRAWALS_LIMIT: uint64 = 134217728 + + PENDING_PARTIAL_WITHDRAWALS_LIMIT: Uint64 = 134217728 - name: PROPORTIONAL_SLASHING_MULTIPLIER#phase0 @@ -653,8 +688,8 @@ search: ProportionalSlashingMultiplier\s+.*yaml:"PROPORTIONAL_SLASHING_MULTIPLIER" regex: true spec: | - - PROPORTIONAL_SLASHING_MULTIPLIER: uint64 = 1 + + PROPORTIONAL_SLASHING_MULTIPLIER: Uint64 = 1 - name: PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR#altair @@ -663,8 +698,8 @@ search: ProportionalSlashingMultiplierAltair\s+.*yaml:"PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR" regex: true spec: | - - PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: uint64 = 2 + + PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: Uint64 = 2 - name: PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX#bellatrix @@ -673,8 +708,8 @@ search: ProportionalSlashingMultiplierBellatrix\s+.*yaml:"PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX" regex: true spec: | - - PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX: uint64 = 3 + + PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX: Uint64 = 3 - name: PROPOSER_REWARD_QUOTIENT#phase0 @@ -683,15 +718,15 @@ search: ProposerRewardQuotient\s+.*yaml:"PROPOSER_REWARD_QUOTIENT" regex: true spec: | - - PROPOSER_REWARD_QUOTIENT: uint64 = 8 + + PROPOSER_REWARD_QUOTIENT: Uint64 = 8 - name: PTC_SIZE#gloas sources: [] spec: | - - PTC_SIZE: uint64 = 512 + + PTC_SIZE: Uint64 = 512 - name: SHUFFLE_ROUND_COUNT#phase0 @@ -700,8 +735,8 @@ search: ShuffleRoundCount\s+.*yaml:"SHUFFLE_ROUND_COUNT" regex: true spec: | - - SHUFFLE_ROUND_COUNT: uint64 = 90 + + SHUFFLE_ROUND_COUNT: Uint64 = 90 - name: SLOTS_PER_EPOCH#phase0 @@ -710,8 +745,8 @@ search: SlotsPerEpoch\s*= regex: true spec: | - - SLOTS_PER_EPOCH: uint64 = 32 + + SLOTS_PER_EPOCH: Slot = 32 - name: SLOTS_PER_HISTORICAL_ROOT#phase0 @@ -720,8 +755,8 @@ search: BlockRootsLength\s*= regex: true spec: | - - SLOTS_PER_HISTORICAL_ROOT: uint64 = 8192 + + SLOTS_PER_HISTORICAL_ROOT: Slot = 8192 - name: SYNC_COMMITTEE_SIZE#altair @@ -730,8 +765,8 @@ search: SyncCommitteeLength\s*= regex: true spec: | - - SYNC_COMMITTEE_SIZE: uint64 = 512 + + SYNC_COMMITTEE_SIZE: Uint64 = 512 - name: TARGET_COMMITTEE_SIZE#phase0 @@ -740,8 +775,8 @@ search: TargetCommitteeSize\s+.*yaml:"TARGET_COMMITTEE_SIZE" regex: true spec: | - - TARGET_COMMITTEE_SIZE: uint64 = 128 + + TARGET_COMMITTEE_SIZE: Uint64 = 128 - name: UPDATE_TIMEOUT#altair @@ -750,8 +785,8 @@ search: data\["UPDATE_TIMEOUT"\] regex: true spec: | - - UPDATE_TIMEOUT = 8192 + + UPDATE_TIMEOUT: Slot = 8192 - name: VALIDATOR_REGISTRY_LIMIT#phase0 @@ -760,8 +795,8 @@ search: ValidatorRegistryLimit\s*= regex: true spec: | - - VALIDATOR_REGISTRY_LIMIT: uint64 = 1099511627776 + + VALIDATOR_REGISTRY_LIMIT: Uint64 = 1099511627776 - name: WHISTLEBLOWER_REWARD_QUOTIENT#phase0 @@ -770,8 +805,8 @@ search: WhistleBlowerRewardQuotient\s+.*yaml:"WHISTLEBLOWER_REWARD_QUOTIENT" regex: true spec: | - - WHISTLEBLOWER_REWARD_QUOTIENT: uint64 = 512 + + WHISTLEBLOWER_REWARD_QUOTIENT: Uint64 = 512 - name: WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA#electra @@ -780,6 +815,6 @@ search: WhistleBlowerRewardQuotientElectra\s+.*yaml:"WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA" regex: true spec: | - - WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: uint64 = 4096 + + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: Uint64 = 4096 diff --git a/testing/spectest/general/BUILD.bazel b/testing/spectest/general/BUILD.bazel index 37106d8075b4..e4ab9aba2707 100644 --- a/testing/spectest/general/BUILD.bazel +++ b/testing/spectest/general/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "fulu__kzg__recover_cells_and_kzg_proofs_test.go", "fulu__kzg__verify_cell_kzg_proof_batch_test.go", ], - data = ["@consensus_spec_tests//:test_data"], + data = ["@cryptography_spec_tests//:test_data"], tags = ["spectest"], deps = [ "//beacon-chain/blockchain/kzg:go_default_library", diff --git a/testing/spectest/general/deneb__kzg__verify_blob_kzg_proof_batch_test.go b/testing/spectest/general/deneb__kzg__verify_blob_kzg_proof_batch_test.go index a1a556881306..bb67d49e5f70 100644 --- a/testing/spectest/general/deneb__kzg__verify_blob_kzg_proof_batch_test.go +++ b/testing/spectest/general/deneb__kzg__verify_blob_kzg_proof_batch_test.go @@ -27,9 +27,9 @@ type KZGTestData struct { func TestVerifyBlobKZGProofBatch(t *testing.T) { require.NoError(t, kzgPrysm.Start()) - testFolders, testFolderPath := utils.TestFolders(t, "general", "deneb", "kzg/verify_blob_kzg_proof_batch/kzg-mainnet") + testFolders, testFolderPath := utils.TestFolders(t, "kzg", "verify_blob_kzg_proof_batch", "") if len(testFolders) == 0 { - t.Fatalf("No test folders found for %s/%s/%s", "general", "deneb", "kzg/verify_blob_kzg_proof_batch/kzg-mainnet") + t.Fatalf("No test folders found for kzg/verify_blob_kzg_proof_batch") } for _, folder := range testFolders { t.Run(folder.Name(), func(t *testing.T) { diff --git a/testing/spectest/general/fulu__kzg__compute_cells_and_kzg_proofs_test.go b/testing/spectest/general/fulu__kzg__compute_cells_and_kzg_proofs_test.go index 1cc1927706dd..53c0fd8a9470 100644 --- a/testing/spectest/general/fulu__kzg__compute_cells_and_kzg_proofs_test.go +++ b/testing/spectest/general/fulu__kzg__compute_cells_and_kzg_proofs_test.go @@ -23,9 +23,9 @@ func TestComputeCellsAndKzgProofs(t *testing.T) { Output [][]string `json:"output"` } require.NoError(t, kzgPrysm.Start()) - testFolders, testFolderPath := utils.TestFolders(t, "general", "fulu", "kzg/compute_cells_and_kzg_proofs/kzg-mainnet") + testFolders, testFolderPath := utils.TestFolders(t, "kzg", "compute_cells_and_kzg_proofs", "") if len(testFolders) == 0 { - t.Fatalf("No test folders found for %s/%s/%s", "general", "fulu", "kzg/compute_cells_and_kzg_proofs/kzg-mainnet") + t.Fatalf("No test folders found for kzg/compute_cells_and_kzg_proofs") } for _, folder := range testFolders { t.Run(folder.Name(), func(t *testing.T) { diff --git a/testing/spectest/general/fulu__kzg__compute_cells_test.go b/testing/spectest/general/fulu__kzg__compute_cells_test.go index 2a6a58fe3236..b6c0f64e08e5 100644 --- a/testing/spectest/general/fulu__kzg__compute_cells_test.go +++ b/testing/spectest/general/fulu__kzg__compute_cells_test.go @@ -24,9 +24,9 @@ func TestComputeCells(t *testing.T) { } require.NoError(t, kzgPrysm.Start()) - testFolders, testFolderPath := utils.TestFolders(t, "general", "fulu", "kzg/compute_cells/kzg-mainnet") + testFolders, testFolderPath := utils.TestFolders(t, "kzg", "compute_cells", "") if len(testFolders) == 0 { - t.Fatalf("No test folders found for %s/%s/%s", "general", "fulu", "kzg/compute_cells/kzg-mainnet") + t.Fatalf("No test folders found for kzg/compute_cells") } for _, folder := range testFolders { t.Run(folder.Name(), func(t *testing.T) { diff --git a/testing/spectest/general/fulu__kzg__recover_cells_and_kzg_proofs_test.go b/testing/spectest/general/fulu__kzg__recover_cells_and_kzg_proofs_test.go index 4d5da8ba15cc..9fe7a792094b 100644 --- a/testing/spectest/general/fulu__kzg__recover_cells_and_kzg_proofs_test.go +++ b/testing/spectest/general/fulu__kzg__recover_cells_and_kzg_proofs_test.go @@ -24,9 +24,9 @@ func TestRecoverCellsAndKzgProofs(t *testing.T) { Output [][]string `json:"output"` } require.NoError(t, kzgPrysm.Start()) - testFolders, testFolderPath := utils.TestFolders(t, "general", "fulu", "kzg/recover_cells_and_kzg_proofs/kzg-mainnet") + testFolders, testFolderPath := utils.TestFolders(t, "kzg", "recover_cells_and_kzg_proofs", "") if len(testFolders) == 0 { - t.Fatalf("No test folders found for %s/%s/%s", "general", "fulu", "kzg/recover_cells_and_kzg_proofs/kzg-mainnet") + t.Fatalf("No test folders found for kzg/recover_cells_and_kzg_proofs") } for _, folder := range testFolders { t.Run(folder.Name(), func(t *testing.T) { diff --git a/testing/spectest/general/fulu__kzg__verify_cell_kzg_proof_batch_test.go b/testing/spectest/general/fulu__kzg__verify_cell_kzg_proof_batch_test.go index e6362e937545..92b372ae238f 100644 --- a/testing/spectest/general/fulu__kzg__verify_cell_kzg_proof_batch_test.go +++ b/testing/spectest/general/fulu__kzg__verify_cell_kzg_proof_batch_test.go @@ -26,9 +26,9 @@ func TestVerifyCellKZGProofBatch(t *testing.T) { Output bool `json:"output"` } require.NoError(t, kzgPrysm.Start()) - testFolders, testFolderPath := utils.TestFolders(t, "general", "fulu", "kzg/verify_cell_kzg_proof_batch/kzg-mainnet") + testFolders, testFolderPath := utils.TestFolders(t, "kzg", "verify_cell_kzg_proof_batch", "") if len(testFolders) == 0 { - t.Fatalf("No test folders found for %s/%s/%s", "general", "fulu", "kzg/verify_cell_kzg_proof_batch/kzg-mainnet") + t.Fatalf("No test folders found for kzg/verify_cell_kzg_proof_batch") } for _, folder := range testFolders { t.Run(folder.Name(), func(t *testing.T) { diff --git a/testing/spectest/shared/common/forkchoice/builder.go b/testing/spectest/shared/common/forkchoice/builder.go index 3445650f653a..660d2c21746a 100644 --- a/testing/spectest/shared/common/forkchoice/builder.go +++ b/testing/spectest/shared/common/forkchoice/builder.go @@ -119,6 +119,20 @@ func (bb *Builder) ValidBlock(t testing.TB, b interfaces.ReadOnlySignedBeaconBlo ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) defer cancel() require.NoError(t, bb.service.ReceiveBlock(ctx, b, r, nil)) + bb.recordIfEarly(b, r) +} + +func (bb *Builder) recordIfEarly(b interfaces.ReadOnlySignedBeaconBlock, root [32]byte) { + cfg := params.BeaconConfig() + slot := b.Block().Slot() + if uint64(bb.lastTick)/cfg.SecondsPerSlot != uint64(slot) { + return + } + slotStart := int64(uint64(slot) * cfg.SecondsPerSlot) + if time.Duration(bb.lastTick-slotStart)*time.Second >= cfg.SlotComponentDuration(cfg.EquivocationEarlyDueBPS) { + return + } + bb.service.RecordBlockForEquivocation(slot, b.Block().ProposerIndex(), root) } // ExecutionPayloadEnvelope receives an envelope and notifies the chain service. diff --git a/testing/spectest/shared/fulu/ssz_static/ssz_static.go b/testing/spectest/shared/fulu/ssz_static/ssz_static.go index 8c2297ac1ee3..9bb91aec2463 100644 --- a/testing/spectest/shared/fulu/ssz_static/ssz_static.go +++ b/testing/spectest/shared/fulu/ssz_static/ssz_static.go @@ -67,9 +67,6 @@ func UnmarshalledSSZ(t *testing.T, serializedBytes []byte, folderName string) (a obj = ðpb.Deposit_Data{} case "Eth1Data": obj = ðpb.Eth1Data{} - case "Eth1Block": - t.Skip("Unused type") - return nil, nil case "Fork": obj = ðpb.Fork{} case "ForkData": @@ -154,10 +151,8 @@ func UnmarshalledSSZ(t *testing.T, serializedBytes []byte, folderName string) (a obj = ðpb.DataColumnSidecar{} case "DataColumnsByRootIdentifier": obj = ðpb.DataColumnsByRootIdentifier{} - case "MatrixEntry": + case "MatrixEntry", "Eth1Block", "PartialDataColumnHeader", "PartialDataColumnPartsMetadata", "PartialDataColumnSidecar", "PartialDataColumnGroupID": t.Skip("Unused type") - case "PartialDataColumnHeader", "PartialDataColumnPartsMetadata", "PartialDataColumnSidecar": - t.Skip("Not yet implemented") default: return nil, errors.New("type not found") } diff --git a/testing/spectest/shared/gloas/fork/upgrade_to_gloas.go b/testing/spectest/shared/gloas/fork/upgrade_to_gloas.go index 76c0e7e0573a..d39f01191108 100644 --- a/testing/spectest/shared/gloas/fork/upgrade_to_gloas.go +++ b/testing/spectest/shared/gloas/fork/upgrade_to_gloas.go @@ -38,7 +38,7 @@ func RunUpgradeToGloas(t *testing.T, config string) { } preState, err := state_native.InitializeFromProtoFulu(preStateBase) require.NoError(t, err) - postState, err := gloas.UpgradeToGloas(preState) + postState, err := gloas.UpgradeToGloas(t.Context(), preState) require.NoError(t, err) postStateFromFunction, err := state_native.ProtobufBeaconStateGloas(postState.ToProtoUnsafe()) require.NoError(t, err) diff --git a/testing/spectest/shared/gloas/ssz_static/ssz_static.go b/testing/spectest/shared/gloas/ssz_static/ssz_static.go index bdef5cae9dec..34acae1baaf2 100644 --- a/testing/spectest/shared/gloas/ssz_static/ssz_static.go +++ b/testing/spectest/shared/gloas/ssz_static/ssz_static.go @@ -20,7 +20,7 @@ import ( // RunSSZStaticTests executes "ssz_static" tests. // // The native-state (`custom`) HashTreeRoot uses progressive merkleization only -// when features.EnableProgressiveSSZ is set (and version >= Gloas). That runtime +// for Gloas types unless features.DisableProgressiveSSZ is set. That runtime // flag is independent of the --//tools:disable_progressive_merkleization codegen // flag, so when running gloas against progressive fixtures set PROGRESSIVE_SSZ=1 // to align the native-state root with the generated one. Leave it unset for the @@ -28,7 +28,7 @@ import ( func RunSSZStaticTests(t *testing.T, config string) { if os.Getenv("PROGRESSIVE_SSZ") != "" { cfg := *features.Get() // nil-safe; copy so other flags are preserved - cfg.EnableProgressiveSSZ = true + cfg.DisableProgressiveSSZ = false reset := features.InitWithReset(&cfg) defer reset() } @@ -89,7 +89,7 @@ func unmarshalledSSZ(t *testing.T, serializedBytes []byte, folderName string) (a t.Skip("Not a consensus type") case "DataColumnSidecar": obj = ðpb.DataColumnSidecarGloas{} - case "SignedProposerPreferences", "ProposerPreferences": + case "SignedProposerPreferences", "ProposerPreferences", "PartialDataColumnGroupID": t.Skip("p2p-only type; not part of the consensus state transition") // Standard types that also exist in gloas @@ -199,7 +199,7 @@ func unmarshalledSSZ(t *testing.T, serializedBytes []byte, folderName string) (a obj = ðpb.DataColumnsByRootIdentifier{} case "MatrixEntry": t.Skip("Unused type") - case "PartialDataColumnHeader", "PartialDataColumnPartsMetadata", "PartialDataColumnSidecar", "PartialDataColumnGroupID": + case "PartialDataColumnHeader", "PartialDataColumnPartsMetadata", "PartialDataColumnSidecar": t.Skip("Not yet implemented") default: return nil, errors.New("type not found") diff --git a/testing/util/gloas_state.go b/testing/util/gloas_state.go index c431235ba3ff..805154d9d47c 100644 --- a/testing/util/gloas_state.go +++ b/testing/util/gloas_state.go @@ -15,7 +15,7 @@ func DeterministicGenesisStateGloas(t testing.TB, numValidators uint64) (state.B t.Helper() fuluState, privKeys := DeterministicGenesisStateFulu(t, numValidators) - beaconState, err := gloas.UpgradeToGloas(fuluState) + beaconState, err := gloas.UpgradeToGloas(t.Context(), fuluState) if err != nil { t.Fatal(errors.Wrapf(err, "failed to upgrade genesis beacon state of %d validators to gloas", numValidators)) }