diff --git a/.github/workflows/check-specrefs.yml b/.github/workflows/check-specrefs.yml
new file mode 100644
index 000000000000..fb4007e8d726
--- /dev/null
+++ b/.github/workflows/check-specrefs.yml
@@ -0,0 +1,43 @@
+name: Check Spec References
+on: [push, pull_request]
+
+jobs:
+ check-specrefs:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Check version consistency
+ run: |
+ WORKSPACE_VERSION=$(grep 'consensus_spec_version = ' WORKSPACE | sed 's/.*"\(.*\)"/\1/')
+ ETHSPECIFY_VERSION=$(grep '^version:' specrefs/.ethspecify.yml | sed 's/version: //')
+ if [ "$WORKSPACE_VERSION" != "$ETHSPECIFY_VERSION" ]; then
+ echo "Version mismatch between WORKSPACE and ethspecify"
+ echo " WORKSPACE: $WORKSPACE_VERSION"
+ echo " specrefs/.ethspecify.yml: $ETHSPECIFY_VERSION"
+ exit 1
+ else
+ echo "Versions match: $WORKSPACE_VERSION"
+ fi
+
+ - name: Install ethspecify
+ run: python3 -mpip install ethspecify
+
+ - name: Update spec references
+ run: ethspecify process --path=specrefs
+
+ - name: Check for differences
+ run: |
+ if ! git diff --exit-code specrefs >/dev/null; then
+ echo "Spec references are out-of-date!"
+ echo ""
+ git --no-pager diff specrefs
+ exit 1
+ else
+ echo "Spec references are up-to-date!"
+ fi
+
+ - name: Check spec references
+ run: ethspecify check --path=specrefs
diff --git a/changelog/jtraglia_specrefs.md b/changelog/jtraglia_specrefs.md
new file mode 100644
index 000000000000..cb4ead972fb2
--- /dev/null
+++ b/changelog/jtraglia_specrefs.md
@@ -0,0 +1,3 @@
+### Added
+
+- Added specification references which map spec to implementation
diff --git a/consensus-types/blocks/get_payload.go b/consensus-types/blocks/get_payload.go
index 5853f090a667..16d186b983ea 100644
--- a/consensus-types/blocks/get_payload.go
+++ b/consensus-types/blocks/get_payload.go
@@ -10,7 +10,7 @@ import (
)
// GetPayloadResponse represents the result of unmarshaling an execution engine
-// GetPayloadResponseV(1|2|3|4) value.
+// GetPayloadResponseV(1|2|3|4|5) value.
type GetPayloadResponse struct {
ExecutionData interfaces.ExecutionData
BlobsBundler pb.BlobsBundler
diff --git a/specrefs/.ethspecify.yml b/specrefs/.ethspecify.yml
new file mode 100644
index 000000000000..207a9950e09f
--- /dev/null
+++ b/specrefs/.ethspecify.yml
@@ -0,0 +1,229 @@
+version: v1.6.0-alpha.4
+style: full
+
+specrefs:
+ search_root: ..
+ files:
+ - configs.yml
+ - constants.yml
+ - containers.yml
+ - dataclasses.yml
+ - functions.yml
+ - presets.yml
+
+exceptions:
+ presets:
+ # Not implemented
+ - CELLS_PER_EXT_BLOB#fulu
+ - UPDATE_TIMEOUT#altair
+
+ constants:
+ # Constants in the KZG library
+ - 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
+
+ # Not implemented
+ - ENDIANNESS#phase0
+ - MAX_CONCURRENT_REQUESTS#phase0
+ - PARTICIPATION_FLAG_WEIGHTS#altair
+ - SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY#bellatrix
+ - UINT256_MAX#fulu
+ - UINT64_MAX#phase0
+ - UINT64_MAX_SQRT#phase0
+
+ ssz_objects:
+ # Not implemented
+ - Eth1Block#phase0
+ - MatrixEntry#fulu
+
+ dataclasses:
+ # Not implemented
+ - BlobParameters#fulu
+ - LatestMessage#phase0
+ - LightClientStore#altair
+ - OptimisticStore#bellatrix
+ - Store#phase0
+
+ 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
+ - multi_exp#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
+
+ # Not implemented: phase0
+ - calculate_committee_fraction#phase0
+ - compute_pulled_up_tip#phase0
+ - filter_block_tree#phase0
+ - get_aggregate_and_proof#phase0
+ - get_attestation_component_deltas#phase0
+ - get_attesting_balance#phase0
+ - get_base_reward#phase0
+ - get_checkpoint_block#phase0
+ - get_current_store_epoch#phase0
+ - get_eligible_validator_indices#phase0
+ - get_epoch_signature#phase0
+ - get_eth1_vote#phase0
+ - get_filtered_block_tree#phase0
+ - get_forkchoice_store#phase0
+ - get_matching_head_attestations#phase0
+ - get_matching_source_attestations#phase0
+ - get_matching_target_attestations#phase0
+ - get_proposer_head#phase0
+ - get_proposer_score#phase0
+ - get_slot_signature#phase0
+ - get_unslashed_attesting_indices#phase0
+ - get_voting_source#phase0
+ - is_candidate_block#phase0
+ - is_ffg_competitive#phase0
+ - is_finalization_ok#phase0
+ - is_head_late#phase0
+ - is_head_weak#phase0
+ - is_parent_strong#phase0
+ - is_proposer#phase0
+ - is_proposing_on_time#phase0
+ - is_shuffling_stable#phase0
+ - is_valid_merkle_branch#phase0
+ - on_tick#phase0
+ - on_tick_per_slot#phase0
+ - store_target_checkpoint_state#phase0
+ - update_latest_messages#phase0
+ - validate_on_attestation#phase0
+ - validate_target_epoch_against_current_time#phase0
+ - xor#phase0
+
+ # Not implemented: altair
+ - compute_sync_committee_period_at_slot#altair
+ - compute_timestamp_at_slot#bellatrix
+ - get_contribution_and_proof#altair
+ - get_index_for_new_validator#altair
+ - get_safety_threshold#altair
+ - get_subtree_index#altair
+ - get_sync_committee_message#altair
+ - get_sync_committee_selection_proof#altair
+ - get_unslashed_participating_indices#altair
+ - is_assigned_to_sync_committee#altair
+ - is_finality_update#altair
+ - is_next_sync_committee_known#altair
+ - is_valid_light_client_header#altair
+ - is_valid_normalized_merkle_branch#altair
+ - process_light_client_store_force_update#altair
+ - process_light_client_update#altair
+ - process_sync_committee_contributions#altair
+ - set_or_append_list#altair
+ - validate_light_client_update#altair
+
+ # Not implemented: bellatrix
+ - get_execution_payload#bellatrix
+ - is_merge_transition_block#bellatrix
+ - is_optimistic_candidate_block#bellatrix
+ - latest_verified_ancestor#bellatrix
+ - prepare_execution_payload#bellatrix
+
+ # Not implemented: capella
+ - get_lc_execution_root#capella
+ - is_valid_light_client_header#capella
+ - prepare_execution_payload#capella
+ - process_epoch#capella
+ - upgrade_lc_bootstrap_to_capella#capella
+ - upgrade_lc_finality_update_to_capella#capella
+ - upgrade_lc_header_to_capella#capella
+ - upgrade_lc_optimistic_update_to_capella#capella
+ - upgrade_lc_store_to_capella#capella
+ - upgrade_lc_update_to_capella#capella
+
+ # Not implemented: deneb
+ - get_lc_execution_root#deneb
+ - is_valid_light_client_header#deneb
+ - prepare_execution_payload#deneb
+ - upgrade_lc_bootstrap_to_deneb#deneb
+ - upgrade_lc_finality_update_to_deneb#deneb
+ - upgrade_lc_header_to_deneb#deneb
+ - upgrade_lc_optimistic_update_to_deneb#deneb
+ - upgrade_lc_store_to_deneb#deneb
+ - upgrade_lc_update_to_deneb#deneb
+
+ # Not implemented: electra
+ - compute_weak_subjectivity_period#electra
+ - current_sync_committee_gindex_at_slot#electra
+ - finalized_root_gindex_at_slot#electra
+ - get_eth1_vote#electra
+ - get_lc_execution_root#electra
+ - is_compounding_withdrawal_credential#electra
+ - is_within_weak_subjectivity_period#electra
+ - next_sync_committee_gindex_at_slot#electra
+ - normalize_merkle_branch#electra
+ - prepare_execution_payload#electra
+ - upgrade_lc_bootstrap_to_electra#electra
+ - upgrade_lc_finality_update_to_electra#electra
+ - upgrade_lc_header_to_electra#electra
+ - upgrade_lc_optimistic_update_to_electra#electra
+ - upgrade_lc_store_to_electra#electra
+ - upgrade_lc_update_to_electra#electra
+
+ # Not implemented: fulu
+ - compute_fork_digest#fulu
+ - compute_matrix#fulu
+ - get_blob_parameters#fulu
+ - get_data_column_sidecars_from_column_sidecar#fulu
+ - get_extended_sample_count#fulu
+ - recover_matrix#fulu
diff --git a/specrefs/configs.yml b/specrefs/configs.yml
new file mode 100644
index 000000000000..27d0cd24730d
--- /dev/null
+++ b/specrefs/configs.yml
@@ -0,0 +1,650 @@
+- name: ALTAIR_FORK_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: AltairForkEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ ALTAIR_FORK_EPOCH: Epoch = 74240
+
+
+- name: ALTAIR_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: AltairForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ ALTAIR_FORK_VERSION: Version = '0x01000000'
+
+
+- name: ATTESTATION_PROPAGATION_SLOT_RANGE
+ sources:
+ - file: config/params/config.go
+ search: AttestationPropagationSlotRange\s+primitives.Slot
+ regex: true
+ spec: |
+
+ ATTESTATION_PROPAGATION_SLOT_RANGE = 32
+
+
+- name: ATTESTATION_SUBNET_COUNT
+ sources:
+ - file: config/params/config.go
+ search: AttestationSubnetCount\s+uint64
+ regex: true
+ spec: |
+
+ ATTESTATION_SUBNET_COUNT = 64
+
+
+- name: ATTESTATION_SUBNET_EXTRA_BITS
+ sources:
+ - file: config/params/config.go
+ search: AttestationSubnetExtraBits\s+uint64
+ regex: true
+ spec: |
+
+ ATTESTATION_SUBNET_EXTRA_BITS = 0
+
+
+- name: ATTESTATION_SUBNET_PREFIX_BITS
+ sources:
+ - file: config/params/config.go
+ search: AttestationSubnetPrefixBits\s+uint64
+ regex: true
+ spec: |
+
+ ATTESTATION_SUBNET_PREFIX_BITS: int = 6
+
+
+- name: BALANCE_PER_ADDITIONAL_CUSTODY_GROUP
+ sources:
+ - file: config/params/config.go
+ search: BalancePerAdditionalCustodyGroup\s+uint64
+ regex: true
+ spec: |
+
+ BALANCE_PER_ADDITIONAL_CUSTODY_GROUP: Gwei = 32000000000
+
+
+- name: BELLATRIX_FORK_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: BellatrixForkEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ BELLATRIX_FORK_EPOCH: Epoch = 144896
+
+
+- name: BELLATRIX_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: BellatrixForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ BELLATRIX_FORK_VERSION: Version = '0x02000000'
+
+
+- name: BLOB_SCHEDULE
+ sources:
+ - file: config/params/config.go
+ search: BlobSchedule\s+\[]BlobScheduleEntry
+ regex: true
+ spec: |
+
+ BLOB_SCHEDULE: tuple[frozendict[str, Any], ...] = (
+ )
+
+
+- name: BLOB_SIDECAR_SUBNET_COUNT
+ sources:
+ - file: config/params/config.go
+ search: BlobsidecarSubnetCount\s+uint64
+ regex: true
+ spec: |
+
+ BLOB_SIDECAR_SUBNET_COUNT = 6
+
+
+- name: BLOB_SIDECAR_SUBNET_COUNT_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: BlobsidecarSubnetCountElectra\s+uint64
+ regex: true
+ spec: |
+
+ BLOB_SIDECAR_SUBNET_COUNT_ELECTRA = 9
+
+
+- name: CAPELLA_FORK_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: CapellaForkEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ CAPELLA_FORK_EPOCH: Epoch = 194048
+
+
+- name: CAPELLA_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: CapellaForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ CAPELLA_FORK_VERSION: Version = '0x03000000'
+
+
+- name: CHURN_LIMIT_QUOTIENT
+ sources:
+ - file: config/params/config.go
+ search: ChurnLimitQuotient\s+uint64
+ regex: true
+ spec: |
+
+ CHURN_LIMIT_QUOTIENT: uint64 = 65536
+
+
+- name: CUSTODY_REQUIREMENT
+ sources:
+ - file: config/params/config.go
+ search: CustodyRequirement\s+uint64.*yaml:"CUSTODY_REQUIREMENT"
+ regex: true
+ spec: |
+
+ CUSTODY_REQUIREMENT = 4
+
+
+- name: DATA_COLUMN_SIDECAR_SUBNET_COUNT
+ sources:
+ - file: config/params/config.go
+ search: DataColumnSidecarSubnetCount\s+uint64
+ regex: true
+ spec: |
+
+ DATA_COLUMN_SIDECAR_SUBNET_COUNT = 128
+
+
+- name: DENEB_FORK_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: DenebForkEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ DENEB_FORK_EPOCH: Epoch = 269568
+
+
+- name: DENEB_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: DenebForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ DENEB_FORK_VERSION: Version = '0x04000000'
+
+
+- name: EJECTION_BALANCE
+ sources:
+ - file: config/params/config.go
+ search: EjectionBalance\s+uint64
+ regex: true
+ spec: |
+
+ EJECTION_BALANCE: Gwei = 16000000000
+
+
+- name: ELECTRA_FORK_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: ElectraForkEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ ELECTRA_FORK_EPOCH: Epoch = 364032
+
+
+- name: ELECTRA_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: ElectraForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ ELECTRA_FORK_VERSION: Version = '0x05000000'
+
+
+- name: EPOCHS_PER_SUBNET_SUBSCRIPTION
+ sources:
+ - file: config/params/config.go
+ search: EpochsPerSubnetSubscription\s+uint64
+ regex: true
+ spec: |
+
+ EPOCHS_PER_SUBNET_SUBSCRIPTION = 256
+
+
+- name: ETH1_FOLLOW_DISTANCE
+ sources:
+ - file: config/params/config.go
+ search: Eth1FollowDistance\s+uint64
+ regex: true
+ spec: |
+
+ ETH1_FOLLOW_DISTANCE: uint64 = 2048
+
+
+- name: FULU_FORK_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: FuluForkEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ FULU_FORK_EPOCH: Epoch = 18446744073709551615
+
+
+- name: FULU_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: FuluForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ FULU_FORK_VERSION: Version = '0x06000000'
+
+
+- name: GENESIS_DELAY
+ sources:
+ - file: config/params/config.go
+ search: GenesisDelay\s+uint64
+ regex: true
+ spec: |
+
+ GENESIS_DELAY: uint64 = 604800
+
+
+- name: GENESIS_FORK_VERSION
+ sources:
+ - file: config/params/config.go
+ search: GenesisForkVersion\s+\[]byte
+ regex: true
+ spec: |
+
+ GENESIS_FORK_VERSION: Version = '0x00000000'
+
+
+- name: INACTIVITY_SCORE_BIAS
+ sources:
+ - file: config/params/config.go
+ search: InactivityScoreBias\s+uint64
+ regex: true
+ spec: |
+
+ INACTIVITY_SCORE_BIAS: uint64 = 4
+
+
+- name: INACTIVITY_SCORE_RECOVERY_RATE
+ sources:
+ - file: config/params/config.go
+ search: InactivityScoreRecoveryRate\s+uint64
+ regex: true
+ spec: |
+
+ INACTIVITY_SCORE_RECOVERY_RATE: uint64 = 16
+
+
+- name: MAXIMUM_GOSSIP_CLOCK_DISPARITY
+ sources:
+ - file: config/params/config.go
+ search: MaximumGossipClockDisparity\s+uint64
+ regex: true
+ spec: |
+
+ MAXIMUM_GOSSIP_CLOCK_DISPARITY = 500
+
+
+- name: MAX_BLOBS_PER_BLOCK
+ sources:
+ - file: config/params/config.go
+ search: DeprecatedMaxBlobsPerBlock\s+int
+ regex: true
+ spec: |
+
+ MAX_BLOBS_PER_BLOCK: uint64 = 6
+
+
+- name: MAX_BLOBS_PER_BLOCK_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: DeprecatedMaxBlobsPerBlockElectra\s+int
+ regex: true
+ spec: |
+
+ MAX_BLOBS_PER_BLOCK_ELECTRA: uint64 = 9
+
+
+- name: MAX_PAYLOAD_SIZE
+ sources:
+ - file: config/params/config.go
+ search: MaxPayloadSize\s+uint64
+ regex: true
+ spec: |
+
+ MAX_PAYLOAD_SIZE = 10485760
+
+
+- name: MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
+ sources:
+ - file: config/params/config.go
+ search: MaxPerEpochActivationChurnLimit\s+uint64
+ regex: true
+ spec: |
+
+ MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: uint64 = 8
+
+
+- name: MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT
+ sources:
+ - file: config/params/config.go
+ search: MaxPerEpochActivationExitChurnLimit\s+uint64
+ regex: true
+ spec: |
+
+ MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: Gwei = 256000000000
+
+
+- name: MAX_REQUEST_BLOB_SIDECARS
+ sources:
+ - file: config/params/config.go
+ search: MaxRequestBlobSidecars\s+uint64
+ regex: true
+ spec: |
+
+ MAX_REQUEST_BLOB_SIDECARS = 768
+
+
+- name: MAX_REQUEST_BLOB_SIDECARS_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: MaxRequestBlobSidecarsElectra\s+uint64
+ regex: true
+ spec: |
+
+ MAX_REQUEST_BLOB_SIDECARS_ELECTRA = 1152
+
+
+- name: MAX_REQUEST_BLOCKS
+ sources:
+ - file: config/params/config.go
+ search: MaxRequestBlocks\s+uint64
+ regex: true
+ spec: |
+
+ MAX_REQUEST_BLOCKS = 1024
+
+
+- name: MAX_REQUEST_BLOCKS_DENEB
+ sources:
+ - file: config/params/config.go
+ search: MaxRequestBlocksDeneb\s+uint64
+ regex: true
+ spec: |
+
+ MAX_REQUEST_BLOCKS_DENEB = 128
+
+
+- name: MAX_REQUEST_DATA_COLUMN_SIDECARS
+ sources:
+ - file: config/params/config.go
+ search: MaxRequestDataColumnSidecars\s+uint64
+ regex: true
+ spec: |
+
+ MAX_REQUEST_DATA_COLUMN_SIDECARS = 16384
+
+
+- name: MESSAGE_DOMAIN_INVALID_SNAPPY
+ sources:
+ - file: config/params/config.go
+ search: MessageDomainInvalidSnappy\s+\[4\]byte
+ regex: true
+ spec: |
+
+ MESSAGE_DOMAIN_INVALID_SNAPPY: DomainType = '0x00000000'
+
+
+- name: MESSAGE_DOMAIN_VALID_SNAPPY
+ sources:
+ - file: config/params/config.go
+ search: MessageDomainValidSnappy\s+\[4\]byte
+ regex: true
+ spec: |
+
+ MESSAGE_DOMAIN_VALID_SNAPPY: DomainType = '0x01000000'
+
+
+- name: MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS
+ sources:
+ - file: config/params/config.go
+ search: MinEpochsForBlobsSidecarsRequest\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS = 4096
+
+
+- name: MIN_EPOCHS_FOR_BLOCK_REQUESTS
+ sources:
+ - file: config/params/config.go
+ search: MinEpochsForBlockRequests\s+uint64
+ regex: true
+ spec: |
+
+ MIN_EPOCHS_FOR_BLOCK_REQUESTS = 33024
+
+
+- name: MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS
+ sources:
+ - file: config/params/config.go
+ search: MinEpochsForDataColumnSidecarsRequest\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS = 4096
+
+
+- name: MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
+ sources:
+ - file: config/params/config.go
+ search: MinGenesisActiveValidatorCount\s+uint64
+ regex: true
+ spec: |
+
+ MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: uint64 = 16384
+
+
+- name: MIN_GENESIS_TIME
+ sources:
+ - file: config/params/config.go
+ search: MinGenesisTime\s+uint64
+ regex: true
+ spec: |
+
+ MIN_GENESIS_TIME: uint64 = 1606824000
+
+
+- name: MIN_PER_EPOCH_CHURN_LIMIT
+ sources:
+ - file: config/params/config.go
+ search: MinPerEpochChurnLimit\s+uint64
+ regex: true
+ spec: |
+
+ MIN_PER_EPOCH_CHURN_LIMIT: uint64 = 4
+
+
+- name: MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: MinPerEpochChurnLimitElectra\s+uint64
+ regex: true
+ spec: |
+
+ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: Gwei = 128000000000
+
+
+- name: MIN_VALIDATOR_WITHDRAWABILITY_DELAY
+ sources:
+ - file: config/params/config.go
+ search: MinValidatorWithdrawabilityDelay\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ MIN_VALIDATOR_WITHDRAWABILITY_DELAY: uint64 = 256
+
+
+- name: NUMBER_OF_CUSTODY_GROUPS
+ sources:
+ - file: config/params/config.go
+ search: NumberOfCustodyGroups\s+uint64
+ regex: true
+ spec: |
+
+ NUMBER_OF_CUSTODY_GROUPS = 128
+
+
+- name: PROPOSER_SCORE_BOOST
+ sources:
+ - file: config/params/config.go
+ search: ProposerScoreBoost\s+uint64
+ regex: true
+ spec: |
+
+ PROPOSER_SCORE_BOOST: uint64 = 40
+
+
+- name: REORG_HEAD_WEIGHT_THRESHOLD
+ sources:
+ - file: config/params/config.go
+ search: ReorgHeadWeightThreshold\s+uint64
+ regex: true
+ spec: |
+
+ REORG_HEAD_WEIGHT_THRESHOLD: uint64 = 20
+
+
+- name: REORG_MAX_EPOCHS_SINCE_FINALIZATION
+ sources:
+ - file: config/params/config.go
+ search: ReorgMaxEpochsSinceFinalization\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ REORG_MAX_EPOCHS_SINCE_FINALIZATION: Epoch = 2
+
+
+- name: REORG_PARENT_WEIGHT_THRESHOLD
+ sources:
+ - file: config/params/config.go
+ search: ReorgParentWeightThreshold\s+uint64
+ regex: true
+ spec: |
+
+ REORG_PARENT_WEIGHT_THRESHOLD: uint64 = 160
+
+
+- name: SAMPLES_PER_SLOT
+ sources:
+ - file: config/params/config.go
+ search: SamplesPerSlot\s+uint64
+ regex: true
+ spec: |
+
+ SAMPLES_PER_SLOT = 8
+
+
+- name: SECONDS_PER_ETH1_BLOCK
+ sources:
+ - file: config/params/config.go
+ search: SecondsPerETH1Block\s+uint64
+ regex: true
+ spec: |
+
+ SECONDS_PER_ETH1_BLOCK: uint64 = 14
+
+
+- name: SECONDS_PER_SLOT
+ sources:
+ - file: config/params/config.go
+ search: SecondsPerSlot\s+uint64
+ regex: true
+ spec: |
+
+ SECONDS_PER_SLOT: uint64 = 12
+
+
+- name: SHARD_COMMITTEE_PERIOD
+ sources:
+ - file: config/params/config.go
+ search: ShardCommitteePeriod\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ SHARD_COMMITTEE_PERIOD: uint64 = 256
+
+
+- name: SUBNETS_PER_NODE
+ sources:
+ - file: config/params/config.go
+ search: SubnetsPerNode\s+uint64
+ regex: true
+ spec: |
+
+ SUBNETS_PER_NODE = 2
+
+
+- name: TERMINAL_BLOCK_HASH
+ sources:
+ - file: config/params/config.go
+ search: TerminalBlockHash\s+common.Hash
+ regex: true
+ spec: |
+
+ TERMINAL_BLOCK_HASH: Hash32 = '0x0000000000000000000000000000000000000000000000000000000000000000'
+
+
+- name: TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: TerminalBlockHashActivationEpoch\s+primitives.Epoch
+ regex: true
+ spec: |
+
+ TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH = 18446744073709551615
+
+
+- name: TERMINAL_TOTAL_DIFFICULTY
+ sources:
+ - file: config/params/config.go
+ search: TerminalTotalDifficulty\s+string
+ regex: true
+ spec: |
+
+ TERMINAL_TOTAL_DIFFICULTY = 58750000000000000000000
+
+
+- name: VALIDATOR_CUSTODY_REQUIREMENT
+ sources:
+ - file: config/params/config.go
+ search: ValidatorCustodyRequirement\s+uint64
+ regex: true
+ spec: |
+
+ VALIDATOR_CUSTODY_REQUIREMENT = 8
+
diff --git a/specrefs/constants.yml b/specrefs/constants.yml
new file mode 100644
index 000000000000..085ba59b876a
--- /dev/null
+++ b/specrefs/constants.yml
@@ -0,0 +1,583 @@
+
+- name: BASE_REWARDS_PER_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: BaseRewardsPerEpoch\s+.*yaml:"BASE_REWARDS_PER_EPOCH"
+ regex: true
+ spec: |
+
+ BASE_REWARDS_PER_EPOCH: uint64 = 4
+
+
+- name: BLS_MODULUS
+ sources: []
+ spec: |
+
+ BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513
+
+
+- name: BLS_WITHDRAWAL_PREFIX
+ sources:
+ - file: config/params/config.go
+ search: BLSWithdrawalPrefixByte\s+.*yaml:"BLS_WITHDRAWAL_PREFIX"
+ regex: true
+ spec: |
+
+ BLS_WITHDRAWAL_PREFIX: Bytes1 = '0x00'
+
+
+- name: BYTES_PER_COMMITMENT
+ sources: []
+ spec: |
+
+ BYTES_PER_COMMITMENT: uint64 = 48
+
+
+- name: BYTES_PER_FIELD_ELEMENT
+ sources: []
+ spec: |
+
+ BYTES_PER_FIELD_ELEMENT: uint64 = 32
+
+
+- name: BYTES_PER_PROOF
+ sources: []
+ spec: |
+
+ BYTES_PER_PROOF: uint64 = 48
+
+
+- name: COMPOUNDING_WITHDRAWAL_PREFIX
+ sources:
+ - file: config/params/config.go
+ search: CompoundingWithdrawalPrefixByte\s+.*yaml:"COMPOUNDING_WITHDRAWAL_PREFIX"
+ regex: true
+ spec: |
+
+ COMPOUNDING_WITHDRAWAL_PREFIX: Bytes1 = '0x02'
+
+
+- name: CONSOLIDATION_REQUEST_TYPE
+ sources:
+ - file: proto/engine/v1/electra.go
+ search: ConsolidationRequestType\s*$
+ regex: true
+ spec: |
+
+ CONSOLIDATION_REQUEST_TYPE: Bytes1 = '0x02'
+
+
+- name: DEPOSIT_CONTRACT_TREE_DEPTH
+ sources:
+ - file: config/params/config.go
+ search: DepositContractTreeDepth\s+.*yaml:"DEPOSIT_CONTRACT_TREE_DEPTH"
+ regex: true
+ spec: |
+
+ DEPOSIT_CONTRACT_TREE_DEPTH: uint64 = 2**5
+
+
+- name: DEPOSIT_REQUEST_TYPE
+ sources:
+ - file: proto/engine/v1/electra.go
+ search: DepositRequestType\s*=\s*iota
+ regex: true
+ spec: |
+
+ DEPOSIT_REQUEST_TYPE: Bytes1 = '0x00'
+
+
+- name: DOMAIN_AGGREGATE_AND_PROOF
+ sources:
+ - file: config/params/config.go
+ search: DomainAggregateAndProof\s+.*yaml:"DOMAIN_AGGREGATE_AND_PROOF"
+ regex: true
+ spec: |
+
+ DOMAIN_AGGREGATE_AND_PROOF: DomainType = '0x06000000'
+
+
+- name: DOMAIN_APPLICATION_MASK
+ sources:
+ - file: config/params/config.go
+ search: DomainApplicationMask\s+.*yaml:"DOMAIN_APPLICATION_MASK"
+ regex: true
+ spec: |
+
+ DOMAIN_APPLICATION_MASK: DomainType = '0x00000001'
+
+
+- name: DOMAIN_BEACON_ATTESTER
+ sources:
+ - file: config/params/config.go
+ search: DomainBeaconAttester\s+.*yaml:"DOMAIN_BEACON_ATTESTER"
+ regex: true
+ spec: |
+
+ DOMAIN_BEACON_ATTESTER: DomainType = '0x01000000'
+
+
+- name: DOMAIN_BEACON_PROPOSER
+ sources:
+ - file: config/params/config.go
+ search: DomainBeaconProposer\s+.*yaml:"DOMAIN_BEACON_PROPOSER"
+ regex: true
+ spec: |
+
+ DOMAIN_BEACON_PROPOSER: DomainType = '0x00000000'
+
+
+- name: DOMAIN_BLS_TO_EXECUTION_CHANGE
+ sources:
+ - file: config/params/config.go
+ search: DomainBLSToExecutionChange\s+.*yaml:"DOMAIN_BLS_TO_EXECUTION_CHANGE"
+ regex: true
+ spec: |
+
+ DOMAIN_BLS_TO_EXECUTION_CHANGE: DomainType = '0x0A000000'
+
+
+- name: DOMAIN_CONTRIBUTION_AND_PROOF
+ sources:
+ - file: config/params/config.go
+ search: DomainContributionAndProof\s+.*yaml:"DOMAIN_CONTRIBUTION_AND_PROOF"
+ regex: true
+ spec: |
+
+ DOMAIN_CONTRIBUTION_AND_PROOF: DomainType = '0x09000000'
+
+
+- name: DOMAIN_DEPOSIT
+ sources:
+ - file: config/params/config.go
+ search: DomainDeposit\s+.*yaml:"DOMAIN_DEPOSIT"
+ regex: true
+ spec: |
+
+ DOMAIN_DEPOSIT: DomainType = '0x03000000'
+
+
+- name: DOMAIN_RANDAO
+ sources:
+ - file: config/params/config.go
+ search: DomainRandao\s+.*yaml:"DOMAIN_RANDAO"
+ regex: true
+ spec: |
+
+ DOMAIN_RANDAO: DomainType = '0x02000000'
+
+
+- name: DOMAIN_SELECTION_PROOF
+ sources:
+ - file: config/params/config.go
+ search: DomainSelectionProof\s+.*yaml:"DOMAIN_SELECTION_PROOF"
+ regex: true
+ spec: |
+
+ DOMAIN_SELECTION_PROOF: DomainType = '0x05000000'
+
+
+- name: DOMAIN_SYNC_COMMITTEE
+ sources:
+ - file: config/params/config.go
+ search: DomainSyncCommittee\s+.*yaml:"DOMAIN_SYNC_COMMITTEE"
+ regex: true
+ spec: |
+
+ DOMAIN_SYNC_COMMITTEE: DomainType = '0x07000000'
+
+
+- name: DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF
+ sources:
+ - file: config/params/config.go
+ search: DomainSyncCommitteeSelectionProof\s+.*yaml:"DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF"
+ regex: true
+ spec: |
+
+ DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: DomainType = '0x08000000'
+
+
+- name: DOMAIN_VOLUNTARY_EXIT
+ sources:
+ - file: config/params/config.go
+ search: DomainVoluntaryExit\s+.*yaml:"DOMAIN_VOLUNTARY_EXIT"
+ regex: true
+ spec: |
+
+ DOMAIN_VOLUNTARY_EXIT: DomainType = '0x04000000'
+
+
+- name: ENDIANNESS
+ sources: []
+ spec: |
+
+ ENDIANNESS = 'little'
+
+
+- name: ETH1_ADDRESS_WITHDRAWAL_PREFIX
+ sources:
+ - file: config/params/config.go
+ search: ETH1AddressWithdrawalPrefixByte\s+.*yaml:"ETH1_ADDRESS_WITHDRAWAL_PREFIX"
+ regex: true
+ spec: |
+
+ ETH1_ADDRESS_WITHDRAWAL_PREFIX: Bytes1 = '0x01'
+
+
+- name: ETH_TO_GWEI
+ sources:
+ - file: config/params/config.go
+ search: GweiPerEth\s+uint64
+ regex: true
+ spec: |
+
+ ETH_TO_GWEI: uint64 = 10**9
+
+
+- name: FAR_FUTURE_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: FarFutureEpoch\s+.*yaml:"FAR_FUTURE_EPOCH"
+ regex: true
+ spec: |
+
+ FAR_FUTURE_EPOCH: Epoch = 2**64 - 1
+
+
+- name: FIAT_SHAMIR_PROTOCOL_DOMAIN
+ sources: []
+ spec: |
+
+ FIAT_SHAMIR_PROTOCOL_DOMAIN = b'FSBLOBVERIFY_V1_'
+
+
+- name: FULL_EXIT_REQUEST_AMOUNT
+ 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
+ sources: []
+ spec: |
+
+ G1_POINT_AT_INFINITY: Bytes48 = b'\xc0' + b'\x00' * 47
+
+
+- name: G2_POINT_AT_INFINITY
+ sources:
+ - file: crypto/bls/common/constants.go
+ search: InfiniteSignature\s*=
+ regex: true
+ spec: |
+
+ G2_POINT_AT_INFINITY: BLSSignature = b'\xc0' + b'\x00' * 95
+
+
+- name: GENESIS_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: GenesisEpoch\s+.*yaml:"GENESIS_EPOCH"
+ regex: true
+ spec: |
+
+ GENESIS_EPOCH: Epoch = 0
+
+
+- name: GENESIS_SLOT
+ sources:
+ - file: config/params/config.go
+ search: GenesisSlot\s+.*yaml:"GENESIS_SLOT"
+ regex: true
+ spec: |
+
+ GENESIS_SLOT: Slot = 0
+
+
+- name: INTERVALS_PER_SLOT
+ sources:
+ - file: config/params/config.go
+ search: IntervalsPerSlot\s+.*yaml:"INTERVALS_PER_SLOT"
+ regex: true
+ spec: |
+
+ INTERVALS_PER_SLOT: uint64 = 3
+
+
+- name: JUSTIFICATION_BITS_LENGTH
+ sources:
+ - file: config/params/config.go
+ search: JustificationBitsLength\s+.*yaml:"JUSTIFICATION_BITS_LENGTH"
+ regex: true
+ spec: |
+
+ JUSTIFICATION_BITS_LENGTH: uint64 = 4
+
+
+- name: KZG_ENDIANNESS
+ sources: []
+ spec: |
+
+ KZG_ENDIANNESS = 'big'
+
+
+- name: KZG_SETUP_G2_LENGTH
+ sources: []
+ spec: |
+
+ KZG_SETUP_G2_LENGTH = 65
+
+
+- name: KZG_SETUP_G2_MONOMIAL
+ 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']
+
+
+- name: MAX_CONCURRENT_REQUESTS
+ sources: []
+ spec: |
+
+ MAX_CONCURRENT_REQUESTS = 2
+
+
+- name: MAX_REQUEST_LIGHT_CLIENT_UPDATES
+ sources:
+ - file: config/params/config.go
+ search: MaxRequestLightClientUpdates\s+.*yaml:"MAX_REQUEST_LIGHT_CLIENT_UPDATES"
+ regex: true
+ spec: |
+
+ MAX_REQUEST_LIGHT_CLIENT_UPDATES = 2**7
+
+
+- name: NODE_ID_BITS
+ sources:
+ - file: config/params/config.go
+ search: NodeIdBits\s+.*yaml:"NODE_ID_BITS"
+ regex: true
+ spec: |
+
+ NODE_ID_BITS = 256
+
+
+- name: PARTICIPATION_FLAG_WEIGHTS
+ sources: []
+ spec: |
+
+ PARTICIPATION_FLAG_WEIGHTS = [TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_WEIGHT, TIMELY_HEAD_WEIGHT]
+
+
+- name: PRIMITIVE_ROOT_OF_UNITY
+ sources: []
+ spec: |
+
+ PRIMITIVE_ROOT_OF_UNITY = 7
+
+
+- name: PROPOSER_WEIGHT
+ sources:
+ - file: config/params/config.go
+ search: ProposerWeight\s+.*yaml:"PROPOSER_WEIGHT"
+ regex: true
+ spec: |
+
+ PROPOSER_WEIGHT: uint64 = 8
+
+
+- name: RANDOM_CHALLENGE_KZG_BATCH_DOMAIN
+ sources: []
+ spec: |
+
+ RANDOM_CHALLENGE_KZG_BATCH_DOMAIN = b'RCKZGBATCH___V1_'
+
+
+- name: RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN
+ sources: []
+ spec: |
+
+ RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN = b'RCKZGCBATCH__V1_'
+
+
+- name: SAFETY_DECAY
+ sources:
+ - file: config/params/config.go
+ search: SafetyDecay\s+uint64
+ regex: true
+ spec: |
+
+ SAFETY_DECAY: uint64 = 10
+
+
+- name: SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY
+ sources: []
+ spec: |
+
+ SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY = 128
+
+
+- name: SYNC_COMMITTEE_SUBNET_COUNT
+ sources:
+ - file: config/params/config.go
+ search: SyncCommitteeSubnetCount\s+.*yaml:"SYNC_COMMITTEE_SUBNET_COUNT"
+ regex: true
+ spec: |
+
+ SYNC_COMMITTEE_SUBNET_COUNT = 4
+
+
+- name: SYNC_REWARD_WEIGHT
+ sources:
+ - file: config/params/config.go
+ search: SyncRewardWeight\s+.*yaml:"SYNC_REWARD_WEIGHT"
+ regex: true
+ spec: |
+
+ SYNC_REWARD_WEIGHT: uint64 = 2
+
+
+- name: TARGET_AGGREGATORS_PER_COMMITTEE
+ sources:
+ - file: config/params/config.go
+ search: TargetAggregatorsPerCommittee\s+.*yaml:"TARGET_AGGREGATORS_PER_COMMITTEE"
+ regex: true
+ spec: |
+
+ TARGET_AGGREGATORS_PER_COMMITTEE = 2**4
+
+
+- name: TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE
+ sources:
+ - file: config/params/config.go
+ search: TargetAggregatorsPerSyncSubcommittee\s+.*yaml:"TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE"
+ regex: true
+ spec: |
+
+ TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE = 2**4
+
+
+- name: TIMELY_HEAD_FLAG_INDEX
+ sources:
+ - file: config/params/config.go
+ search: TimelyHeadFlagIndex\s+.*yaml:"TIMELY_HEAD_FLAG_INDEX"
+ regex: true
+ spec: |
+
+ TIMELY_HEAD_FLAG_INDEX = 2
+
+
+- name: TIMELY_HEAD_WEIGHT
+ sources:
+ - file: config/params/config.go
+ search: TimelyHeadWeight\s+.*yaml:"TIMELY_HEAD_WEIGHT"
+ regex: true
+ spec: |
+
+ TIMELY_HEAD_WEIGHT: uint64 = 14
+
+
+- name: TIMELY_SOURCE_FLAG_INDEX
+ sources:
+ - file: config/params/config.go
+ search: TimelySourceFlagIndex\s+.*yaml:"TIMELY_SOURCE_FLAG_INDEX"
+ regex: true
+ spec: |
+
+ TIMELY_SOURCE_FLAG_INDEX = 0
+
+
+- name: TIMELY_SOURCE_WEIGHT
+ sources:
+ - file: config/params/config.go
+ search: TimelySourceWeight\s+.*yaml:"TIMELY_SOURCE_WEIGHT"
+ regex: true
+ spec: |
+
+ TIMELY_SOURCE_WEIGHT: uint64 = 14
+
+
+- name: TIMELY_TARGET_FLAG_INDEX
+ sources:
+ - file: config/params/config.go
+ search: TimelyTargetFlagIndex\s+.*yaml:"TIMELY_TARGET_FLAG_INDEX"
+ regex: true
+ spec: |
+
+ TIMELY_TARGET_FLAG_INDEX = 1
+
+
+- name: TIMELY_TARGET_WEIGHT
+ sources:
+ - file: config/params/config.go
+ search: TimelyTargetWeight\s+.*yaml:"TIMELY_TARGET_WEIGHT"
+ regex: true
+ spec: |
+
+ TIMELY_TARGET_WEIGHT: uint64 = 26
+
+
+- name: UINT256_MAX
+ sources: []
+ spec: |
+
+ UINT256_MAX: uint256 = 2**256 - 1
+
+
+- name: UINT64_MAX
+ sources: []
+ spec: |
+
+ UINT64_MAX: uint64 = 2**64 - 1
+
+
+- name: UINT64_MAX_SQRT
+ sources: []
+ spec: |
+
+ UINT64_MAX_SQRT: uint64 = 4294967295
+
+
+- name: UNSET_DEPOSIT_REQUESTS_START_INDEX
+ sources:
+ - file: config/params/config.go
+ search: UnsetDepositRequestsStartIndex\s+.*yaml:"UNSET_DEPOSIT_REQUESTS_START_INDEX"
+ regex: true
+ spec: |
+
+ UNSET_DEPOSIT_REQUESTS_START_INDEX: uint64 = 2**64 - 1
+
+
+- name: VERSIONED_HASH_VERSION_KZG
+ sources:
+ - file: consensus-types/primitives/kzg.go
+ search: blobCommitmentVersionKZG\s+uint8\s+=\s+0x01
+ regex: true
+ spec: |
+
+ VERSIONED_HASH_VERSION_KZG: Bytes1 = '0x01'
+
+
+- name: WEIGHT_DENOMINATOR
+ sources:
+ - file: config/params/config.go
+ search: WeightDenominator\s+.*yaml:"WEIGHT_DENOMINATOR"
+ regex: true
+ spec: |
+
+ WEIGHT_DENOMINATOR: uint64 = 64
+
+
+- name: WITHDRAWAL_REQUEST_TYPE
+ sources:
+ - file: proto/engine/v1/electra.go
+ search: WithdrawalRequestType\s*$
+ regex: true
+ spec: |
+
+ WITHDRAWAL_REQUEST_TYPE: Bytes1 = '0x01'
+
diff --git a/specrefs/containers.yml b/specrefs/containers.yml
new file mode 100644
index 000000000000..a1583041c5cb
--- /dev/null
+++ b/specrefs/containers.yml
@@ -0,0 +1,1305 @@
+- name: AggregateAndProof#phase0
+ sources:
+ - file: proto/prysm/v1alpha1/attestation.proto
+ search: message AggregateAttestationAndProof {
+ spec: |
+
+ class AggregateAndProof(Container):
+ aggregator_index: ValidatorIndex
+ aggregate: Attestation
+ selection_proof: BLSSignature
+
+
+- name: AggregateAndProof#electra
+ sources:
+ - file: proto/prysm/v1alpha1/attestation.proto
+ search: message AggregateAttestationAndProofElectra {
+ spec: |
+
+ class AggregateAndProof(Container):
+ aggregator_index: ValidatorIndex
+ # [Modified in Electra:EIP7549]
+ aggregate: Attestation
+ selection_proof: BLSSignature
+
+
+- name: Attestation#phase0
+ sources:
+ - file: proto/prysm/v1alpha1/attestation.proto
+ search: message Attestation {
+ spec: |
+
+ class Attestation(Container):
+ aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
+ data: AttestationData
+ signature: BLSSignature
+
+
+- name: Attestation#electra
+ sources:
+ - 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]
+ data: AttestationData
+ signature: BLSSignature
+ # [New in Electra:EIP7549]
+ committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT]
+
+
+- name: AttestationData
+ sources:
+ - file: proto/eth/v1/attestation.proto
+ search: message AttestationData {
+ spec: |
+
+ class AttestationData(Container):
+ slot: Slot
+ index: CommitteeIndex
+ beacon_block_root: Root
+ source: Checkpoint
+ target: Checkpoint
+
+
+- name: AttesterSlashing#phase0
+ sources:
+ - file: proto/eth/v1/beacon_block.proto
+ search: message AttesterSlashing {
+ spec: |
+
+ class AttesterSlashing(Container):
+ attestation_1: IndexedAttestation
+ attestation_2: IndexedAttestation
+
+
+- name: AttesterSlashing#electra
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message AttesterSlashingElectra {
+ spec: |
+
+ class AttesterSlashing(Container):
+ # [Modified in Electra:EIP7549]
+ attestation_1: IndexedAttestation
+ # [Modified in Electra:EIP7549]
+ attestation_2: IndexedAttestation
+
+
+- name: BLSToExecutionChange
+ sources:
+ - file: proto/prysm/v1alpha1/withdrawals.proto
+ search: message BLSToExecutionChange {
+ spec: |
+
+ class BLSToExecutionChange(Container):
+ validator_index: ValidatorIndex
+ from_bls_pubkey: BLSPubkey
+ to_execution_address: ExecutionAddress
+
+
+- name: BeaconBlock
+ sources:
+ - file: proto/eth/v1/beacon_block.proto
+ search: message BeaconBlock {
+ spec: |
+
+ class BeaconBlock(Container):
+ slot: Slot
+ proposer_index: ValidatorIndex
+ parent_root: Root
+ state_root: Root
+ body: BeaconBlockBody
+
+
+- name: BeaconBlockBody#phase0
+ sources:
+ - 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]
+
+
+- name: BeaconBlockBody#altair
+ sources:
+ - 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]
+ # [New in Altair]
+ sync_aggregate: SyncAggregate
+
+
+- name: BeaconBlockBody#bellatrix
+ sources:
+ - 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]
+ sync_aggregate: SyncAggregate
+ # [New in Bellatrix]
+ execution_payload: ExecutionPayload
+
+
+- name: BeaconBlockBody#capella
+ sources:
+ - 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]
+ sync_aggregate: SyncAggregate
+ execution_payload: ExecutionPayload
+ # [New in Capella]
+ bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
+
+
+- name: BeaconBlockBody#deneb
+ sources:
+ - 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]
+ sync_aggregate: SyncAggregate
+ # [Modified in Deneb:EIP4844]
+ execution_payload: ExecutionPayload
+ bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
+ # [New in Deneb:EIP4844]
+ blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
+
+
+- name: BeaconBlockBody#electra
+ sources:
+ - 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]
+ # [Modified in Electra:EIP7549]
+ attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA]
+ # [Modified in Electra:EIP7549]
+ attestations: List[Attestation, MAX_ATTESTATIONS_ELECTRA]
+ deposits: List[Deposit, MAX_DEPOSITS]
+ voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
+ 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]
+ # [New in Electra]
+ execution_requests: ExecutionRequests
+
+
+- name: BeaconBlockHeader
+ sources:
+ - file: proto/eth/v1/beacon_block.proto
+ search: message BeaconBlockHeader {
+ spec: |
+
+ class BeaconBlockHeader(Container):
+ slot: Slot
+ proposer_index: ValidatorIndex
+ parent_root: Root
+ state_root: Root
+ body_root: Root
+
+
+- name: BeaconState#phase0
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconState {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+
+
+- name: BeaconState#altair
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconStateAltair {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ # [Modified in Altair]
+ previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT]
+ # [Modified in Altair]
+ current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT]
+ justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+ # [New in Altair]
+ inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
+ # [New in Altair]
+ current_sync_committee: SyncCommittee
+ # [New in Altair]
+ next_sync_committee: SyncCommittee
+
+
+- name: BeaconState#bellatrix
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconStateBellatrix {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+ inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
+ current_sync_committee: SyncCommittee
+ next_sync_committee: SyncCommittee
+ # [New in Bellatrix]
+ latest_execution_payload_header: ExecutionPayloadHeader
+
+
+- name: BeaconState#capella
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconStateCapella {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+ inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
+ current_sync_committee: SyncCommittee
+ next_sync_committee: SyncCommittee
+ # [Modified in Capella]
+ latest_execution_payload_header: ExecutionPayloadHeader
+ # [New in Capella]
+ next_withdrawal_index: WithdrawalIndex
+ # [New in Capella]
+ next_withdrawal_validator_index: ValidatorIndex
+ # [New in Capella]
+ historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT]
+
+
+- name: BeaconState#deneb
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconStateDeneb {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+ inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
+ 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]
+
+
+- name: BeaconState#electra
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconStateElectra {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+ inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
+ 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]
+ # [New in Electra:EIP6110]
+ deposit_requests_start_index: uint64
+ # [New in Electra:EIP7251]
+ deposit_balance_to_consume: Gwei
+ # [New in Electra:EIP7251]
+ exit_balance_to_consume: Gwei
+ # [New in Electra:EIP7251]
+ earliest_exit_epoch: Epoch
+ # [New in Electra:EIP7251]
+ consolidation_balance_to_consume: Gwei
+ # [New in Electra:EIP7251]
+ earliest_consolidation_epoch: Epoch
+ # [New in Electra:EIP7251]
+ pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT]
+ # [New in Electra:EIP7251]
+ pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT]
+ # [New in Electra:EIP7251]
+ pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT]
+
+
+- name: BeaconState#fulu
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message BeaconStateFulu {
+ spec: |
+
+ class BeaconState(Container):
+ 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]
+ 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]
+ previous_justified_checkpoint: Checkpoint
+ current_justified_checkpoint: Checkpoint
+ finalized_checkpoint: Checkpoint
+ inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
+ 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
+ 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]
+ # [New in Fulu:EIP7917]
+ proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]
+
+
+- name: BlobIdentifier
+ sources:
+ - file: proto/prysm/v1alpha1/blobs.proto
+ search: message BlobIdentifier {
+ spec: |
+
+ class BlobIdentifier(Container):
+ block_root: Root
+ index: BlobIndex
+
+
+- name: BlobSidecar
+ 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]
+
+
+- name: Checkpoint
+ sources:
+ - file: proto/eth/v1/attestation.proto
+ search: message Checkpoint {
+ spec: |
+
+ class Checkpoint(Container):
+ epoch: Epoch
+ root: Root
+
+
+- name: ConsolidationRequest
+ sources:
+ - file: proto/engine/v1/electra.proto
+ search: message ConsolidationRequest {
+ spec: |
+
+ class ConsolidationRequest(Container):
+ source_address: ExecutionAddress
+ source_pubkey: BLSPubkey
+ target_pubkey: BLSPubkey
+
+
+- name: ContributionAndProof
+ sources:
+ - file: proto/prysm/v1alpha1/sync_committee.proto
+ search: message ContributionAndProof {
+ spec: |
+
+ class ContributionAndProof(Container):
+ aggregator_index: ValidatorIndex
+ contribution: SyncCommitteeContribution
+ selection_proof: BLSSignature
+
+
+- name: DataColumnSidecar
+ 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]
+ signed_block_header: SignedBeaconBlockHeader
+ kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH]
+
+
+- name: DataColumnsByRootIdentifier
+ sources:
+ - file: proto/prysm/v1alpha1/data_columns.proto
+ search: message DataColumnsByRootIdentifier {
+ spec: |
+
+ class DataColumnsByRootIdentifier(Container):
+ block_root: Root
+ columns: List[ColumnIndex, NUMBER_OF_COLUMNS]
+
+
+- name: Deposit
+ sources:
+ - file: proto/eth/v1/beacon_block.proto
+ search: message Deposit {
+ spec: |
+
+ class Deposit(Container):
+ proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH + 1]
+ data: DepositData
+
+
+- name: DepositData
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message Data {
+ spec: |
+
+ class DepositData(Container):
+ pubkey: BLSPubkey
+ withdrawal_credentials: Bytes32
+ amount: Gwei
+ signature: BLSSignature
+
+
+- name: DepositMessage
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message DepositMessage {
+ spec: |
+
+ class DepositMessage(Container):
+ pubkey: BLSPubkey
+ withdrawal_credentials: Bytes32
+ amount: Gwei
+
+
+- name: DepositRequest
+ 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
+
+
+- name: Eth1Data
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message Eth1Data {
+ spec: |
+
+ class Eth1Data(Container):
+ deposit_root: Root
+ deposit_count: uint64
+ block_hash: Hash32
+
+
+- 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]
+ 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_hash: Hash32
+ transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
+
+
+- name: ExecutionPayload#capella
+ sources:
+ - 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]
+ 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_hash: Hash32
+ transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
+ # [New in Capella]
+ withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
+
+
+- name: ExecutionPayload#deneb
+ sources:
+ - 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]
+ 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_hash: Hash32
+ transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
+ withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
+ # [New in Deneb:EIP4844]
+ blob_gas_used: uint64
+ # [New in Deneb:EIP4844]
+ excess_blob_gas: uint64
+
+
+- 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]
+ 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_hash: Hash32
+ transactions_root: Root
+
+
+- name: ExecutionPayloadHeader#capella
+ sources:
+ - 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]
+ 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_hash: Hash32
+ transactions_root: Root
+ # [New in Capella]
+ withdrawals_root: Root
+
+
+- name: ExecutionPayloadHeader#deneb
+ sources:
+ - 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]
+ 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_hash: Hash32
+ transactions_root: Root
+ withdrawals_root: Root
+ # [New in Deneb:EIP4844]
+ blob_gas_used: uint64
+ # [New in Deneb:EIP4844]
+ excess_blob_gas: uint64
+
+
+- name: ExecutionRequests
+ sources:
+ - 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]
+ # [New in Electra:EIP7002:EIP7251]
+ withdrawals: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD]
+ # [New in Electra:EIP7251]
+ consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD]
+
+
+- name: Fork
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message Fork {
+ spec: |
+
+ class Fork(Container):
+ previous_version: Version
+ current_version: Version
+ epoch: Epoch
+
+
+- name: ForkData
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message ForkData {
+ spec: |
+
+ class ForkData(Container):
+ current_version: Version
+ genesis_validators_root: Root
+
+
+- name: HistoricalBatch
+ sources:
+ - 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]
+
+
+- name: HistoricalSummary
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message HistoricalSummary {
+ spec: |
+
+ class HistoricalSummary(Container):
+ block_summary_root: Root
+ state_summary_root: Root
+
+
+- name: IndexedAttestation#phase0
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message IndexedAttestation {
+ spec: |
+
+ class IndexedAttestation(Container):
+ attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]
+ data: AttestationData
+ signature: BLSSignature
+
+
+- name: IndexedAttestation#electra
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message IndexedAttestationElectra {
+ spec: |
+
+ class IndexedAttestation(Container):
+ # [Modified in Electra:EIP7549]
+ attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT]
+ data: AttestationData
+ signature: BLSSignature
+
+
+- name: LightClientBootstrap
+ sources:
+ - file: proto/prysm/v1alpha1/light_client.proto
+ search: message LightClientBootstrapAltair {
+ spec: |
+
+ class LightClientBootstrap(Container):
+ # Header matching the requested beacon block root
+ header: LightClientHeader
+ # Current sync committee corresponding to `header.beacon.state_root`
+ current_sync_committee: SyncCommittee
+ current_sync_committee_branch: CurrentSyncCommitteeBranch
+
+
+- name: LightClientFinalityUpdate
+ sources:
+ - file: proto/prysm/v1alpha1/light_client.proto
+ search: message LightClientFinalityUpdateAltair {
+ spec: |
+
+ class LightClientFinalityUpdate(Container):
+ # Header attested to by the sync committee
+ attested_header: LightClientHeader
+ # Finalized header corresponding to `attested_header.beacon.state_root`
+ finalized_header: LightClientHeader
+ finality_branch: FinalityBranch
+ # Sync committee aggregate signature
+ sync_aggregate: SyncAggregate
+ # Slot at which the aggregate signature was created (untrusted)
+ signature_slot: Slot
+
+
+- name: LightClientHeader#altair
+ sources:
+ - file: proto/prysm/v1alpha1/light_client.proto
+ search: message LightClientHeaderAltair {
+ spec: |
+
+ class LightClientHeader(Container):
+ beacon: BeaconBlockHeader
+
+
+- name: LightClientHeader#capella
+ sources:
+ - file: proto/prysm/v1alpha1/light_client.proto
+ search: message LightClientHeaderCapella {
+ spec: |
+
+ class LightClientHeader(Container):
+ # Beacon block header
+ beacon: BeaconBlockHeader
+ # Execution payload header corresponding to `beacon.body_root` (from Capella onward)
+ execution: ExecutionPayloadHeader
+ execution_branch: ExecutionBranch
+
+
+- name: LightClientOptimisticUpdate
+ sources:
+ - file: proto/prysm/v1alpha1/light_client.proto
+ search: message LightClientOptimisticUpdateAltair {
+ spec: |
+
+ class LightClientOptimisticUpdate(Container):
+ # Header attested to by the sync committee
+ attested_header: LightClientHeader
+ # Sync committee aggregate signature
+ sync_aggregate: SyncAggregate
+ # Slot at which the aggregate signature was created (untrusted)
+ signature_slot: Slot
+
+
+- name: LightClientUpdate
+ sources:
+ - file: proto/prysm/v1alpha1/light_client.proto
+ search: message LightClientUpdateAltair {
+ spec: |
+
+ class LightClientUpdate(Container):
+ # Header attested to by the sync committee
+ attested_header: LightClientHeader
+ # Next sync committee corresponding to `attested_header.beacon.state_root`
+ next_sync_committee: SyncCommittee
+ next_sync_committee_branch: NextSyncCommitteeBranch
+ # Finalized header corresponding to `attested_header.beacon.state_root`
+ finalized_header: LightClientHeader
+ finality_branch: FinalityBranch
+ # Sync committee aggregate signature
+ sync_aggregate: SyncAggregate
+ # Slot at which the aggregate signature was created (untrusted)
+ signature_slot: Slot
+
+
+- name: PendingAttestation
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message PendingAttestation {
+ spec: |
+
+ class PendingAttestation(Container):
+ aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
+ data: AttestationData
+ inclusion_delay: Slot
+ proposer_index: ValidatorIndex
+
+
+- name: PendingConsolidation
+ sources:
+ - file: proto/prysm/v1alpha1/eip_7251.proto
+ search: message PendingConsolidation {
+ spec: |
+
+ class PendingConsolidation(Container):
+ source_index: ValidatorIndex
+ target_index: ValidatorIndex
+
+
+- name: PendingDeposit
+ sources:
+ - file: proto/prysm/v1alpha1/eip_7251.proto
+ search: message PendingDeposit {
+ spec: |
+
+ class PendingDeposit(Container):
+ pubkey: BLSPubkey
+ withdrawal_credentials: Bytes32
+ amount: Gwei
+ signature: BLSSignature
+ slot: Slot
+
+
+- name: PendingPartialWithdrawal
+ sources:
+ - file: proto/prysm/v1alpha1/eip_7251.proto
+ search: message PendingPartialWithdrawal {
+ spec: |
+
+ class PendingPartialWithdrawal(Container):
+ validator_index: ValidatorIndex
+ amount: Gwei
+ withdrawable_epoch: Epoch
+
+
+- name: PowBlock
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message PowBlock {
+ spec: |
+
+ class PowBlock(Container):
+ block_hash: Hash32
+ parent_hash: Hash32
+ total_difficulty: uint256
+
+
+- name: ProposerSlashing
+ sources:
+ - file: proto/eth/v1/beacon_block.proto
+ search: message ProposerSlashing {
+ spec: |
+
+ class ProposerSlashing(Container):
+ signed_header_1: SignedBeaconBlockHeader
+ signed_header_2: SignedBeaconBlockHeader
+
+
+- name: SignedAggregateAndProof#phase0
+ sources:
+ - file: proto/prysm/v1alpha1/attestation.proto
+ search: message SignedAggregateAttestationAndProof {
+ spec: |
+
+ class SignedAggregateAndProof(Container):
+ message: AggregateAndProof
+ signature: BLSSignature
+
+
+- name: SignedAggregateAndProof#electra
+ sources:
+ - file: proto/prysm/v1alpha1/attestation.proto
+ search: message SignedAggregateAttestationAndProofElectra {
+ spec: |
+
+ class SignedAggregateAndProof(Container):
+ # [Modified in Electra:EIP7549]
+ message: AggregateAndProof
+ signature: BLSSignature
+
+
+- name: SignedBLSToExecutionChange
+ sources:
+ - file: proto/prysm/v1alpha1/withdrawals.proto
+ search: message SignedBLSToExecutionChange {
+ spec: |
+
+ class SignedBLSToExecutionChange(Container):
+ message: BLSToExecutionChange
+ signature: BLSSignature
+
+
+- name: SignedBeaconBlock
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message SignedBeaconBlock {
+ spec: |
+
+ class SignedBeaconBlock(Container):
+ message: BeaconBlock
+ signature: BLSSignature
+
+
+- name: SignedBeaconBlockHeader
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message SignedBeaconBlockHeader {
+ spec: |
+
+ class SignedBeaconBlockHeader(Container):
+ message: BeaconBlockHeader
+ signature: BLSSignature
+
+
+- name: SignedContributionAndProof
+ sources:
+ - file: proto/prysm/v1alpha1/sync_committee.proto
+ search: message SignedContributionAndProof {
+ spec: |
+
+ class SignedContributionAndProof(Container):
+ message: ContributionAndProof
+ signature: BLSSignature
+
+
+- name: SignedVoluntaryExit
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message SignedVoluntaryExit {
+ spec: |
+
+ class SignedVoluntaryExit(Container):
+ message: VoluntaryExit
+ signature: BLSSignature
+
+
+- name: SigningData
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message SigningData {
+ spec: |
+
+ class SigningData(Container):
+ object_root: Root
+ domain: Domain
+
+
+- name: SingleAttestation
+ sources:
+ - file: proto/prysm/v1alpha1/attestation.proto
+ search: message SingleAttestation {
+ spec: |
+
+ class SingleAttestation(Container):
+ committee_index: CommitteeIndex
+ attester_index: ValidatorIndex
+ data: AttestationData
+ signature: BLSSignature
+
+
+- name: SyncAggregate
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_block.proto
+ search: message SyncAggregate {
+ spec: |
+
+ class SyncAggregate(Container):
+ sync_committee_bits: Bitvector[SYNC_COMMITTEE_SIZE]
+ sync_committee_signature: BLSSignature
+
+
+- name: SyncAggregatorSelectionData
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message SyncAggregatorSelectionData {
+ spec: |
+
+ class SyncAggregatorSelectionData(Container):
+ slot: Slot
+ subcommittee_index: uint64
+
+
+- name: SyncCommittee
+ sources:
+ - file: proto/prysm/v1alpha1/beacon_state.proto
+ search: message SyncCommittee {
+ spec: |
+
+ class SyncCommittee(Container):
+ pubkeys: Vector[BLSPubkey, SYNC_COMMITTEE_SIZE]
+ aggregate_pubkey: BLSPubkey
+
+
+- name: SyncCommitteeContribution
+ 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]
+ signature: BLSSignature
+
+
+- name: SyncCommitteeMessage
+ sources:
+ - file: proto/prysm/v1alpha1/sync_committee.proto
+ search: message SyncCommitteeMessage {
+ spec: |
+
+ class SyncCommitteeMessage(Container):
+ slot: Slot
+ beacon_block_root: Root
+ validator_index: ValidatorIndex
+ signature: BLSSignature
+
+
+- name: Validator
+ sources:
+ - file: proto/prysm/v1alpha1/validator.proto
+ search: message Validator {
+ spec: |
+
+ class Validator(Container):
+ pubkey: BLSPubkey
+ withdrawal_credentials: Bytes32
+ effective_balance: Gwei
+ slashed: boolean
+ activation_eligibility_epoch: Epoch
+ activation_epoch: Epoch
+ exit_epoch: Epoch
+ withdrawable_epoch: Epoch
+
+
+- name: VoluntaryExit
+ sources:
+ - file: proto/eth/v1/beacon_block.proto
+ search: message VoluntaryExit {
+ spec: |
+
+ class VoluntaryExit(Container):
+ epoch: Epoch
+ validator_index: ValidatorIndex
+
+
+- name: Withdrawal
+ sources:
+ - file: proto/engine/v1/execution_engine.proto
+ search: message Withdrawal {
+ spec: |
+
+ class Withdrawal(Container):
+ index: WithdrawalIndex
+ validator_index: ValidatorIndex
+ address: ExecutionAddress
+ amount: Gwei
+
+
+- name: WithdrawalRequest
+ sources:
+ - file: proto/engine/v1/electra.proto
+ search: message WithdrawalRequest {
+ spec: |
+
+ class WithdrawalRequest(Container):
+ source_address: ExecutionAddress
+ validator_pubkey: BLSPubkey
+ amount: Gwei
+
diff --git a/specrefs/dataclasses.yml b/specrefs/dataclasses.yml
new file mode 100644
index 000000000000..6bf99b0f018b
--- /dev/null
+++ b/specrefs/dataclasses.yml
@@ -0,0 +1,249 @@
+
+- name: BlobParameters
+ sources: []
+ spec: |
+
+ class BlobParameters:
+ epoch: Epoch
+ max_blobs_per_block: uint64
+
+
+- name: BlobsBundle#deneb
+ sources:
+ - file: proto/engine/v1/execution_engine.proto
+ search: ^message BlobsBundle\s*\{
+ regex: true
+ spec: |
+
+ class BlobsBundle(object):
+ commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
+ proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK]
+ blobs: List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK]
+
+
+- name: BlobsBundle#fulu
+ sources:
+ - file: proto/engine/v1/execution_engine.proto
+ search: ^message BlobsBundleV2
+ regex: true
+ spec: |
+
+ class BlobsBundle(object):
+ commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
+ # [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]
+
+
+- name: GetPayloadResponse#bellatrix
+ sources:
+ - file: consensus-types/blocks/get_payload.go
+ search: type GetPayloadResponse struct {
+ - file: consensus-types/blocks/get_payload.go
+ search: GetPayloadResponseV(1
+ spec: |
+
+ class GetPayloadResponse(object):
+ execution_payload: ExecutionPayload
+
+
+- name: GetPayloadResponse#capella
+ sources:
+ - file: consensus-types/blocks/get_payload.go
+ search: type GetPayloadResponse struct {
+ - file: consensus-types/blocks/get_payload.go
+ search: GetPayloadResponseV(1|2
+ spec: |
+
+ class GetPayloadResponse(object):
+ execution_payload: ExecutionPayload
+ block_value: uint256
+
+
+- name: GetPayloadResponse#deneb
+ sources:
+ - file: consensus-types/blocks/get_payload.go
+ search: type GetPayloadResponse struct {
+ - file: consensus-types/blocks/get_payload.go
+ search: GetPayloadResponseV(1|2|3
+ spec: |
+
+ class GetPayloadResponse(object):
+ execution_payload: ExecutionPayload
+ block_value: uint256
+ # [New in Deneb:EIP4844]
+ blobs_bundle: BlobsBundle
+
+
+- name: GetPayloadResponse#electra
+ sources:
+ - file: consensus-types/blocks/get_payload.go
+ search: type GetPayloadResponse struct {
+ - file: consensus-types/blocks/get_payload.go
+ search: GetPayloadResponseV(1|2|3|4
+ spec: |
+
+ class GetPayloadResponse(object):
+ execution_payload: ExecutionPayload
+ block_value: uint256
+ blobs_bundle: BlobsBundle
+ # [New in Electra]
+ execution_requests: Sequence[bytes]
+
+
+- name: GetPayloadResponse#fulu
+ sources:
+ - file: consensus-types/blocks/get_payload.go
+ search: type GetPayloadResponse struct {
+ - file: consensus-types/blocks/get_payload.go
+ search: GetPayloadResponseV(1|2|3|4|5
+ spec: |
+
+ class GetPayloadResponse(object):
+ execution_payload: ExecutionPayload
+ block_value: uint256
+ # [Modified in Fulu:EIP7594]
+ blobs_bundle: BlobsBundle
+ execution_requests: Sequence[bytes]
+
+
+- name: LatestMessage
+ sources: []
+ spec: |
+
+ @dataclass(eq=True, frozen=True)
+ class LatestMessage(object):
+ epoch: Epoch
+ root: Root
+
+
+- name: LightClientStore
+ sources: []
+ spec: |
+
+ class LightClientStore(object):
+ # Header that is finalized
+ finalized_header: LightClientHeader
+ # Sync committees corresponding to the finalized header
+ current_sync_committee: SyncCommittee
+ next_sync_committee: SyncCommittee
+ # Best available header to switch finalized head to if we see nothing else
+ best_valid_update: Optional[LightClientUpdate]
+ # 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
+
+
+- name: NewPayloadRequest#bellatrix
+ sources:
+ - file: beacon-chain/execution/engine_client.go
+ search: func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionData
+ spec: |
+
+ class NewPayloadRequest(object):
+ execution_payload: ExecutionPayload
+
+
+- name: NewPayloadRequest#deneb
+ sources:
+ - file: beacon-chain/execution/engine_client.go
+ search: func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionData, versionedHashes []common.Hash, parentBlockRoot *common.Hash
+ spec: |
+
+ class NewPayloadRequest(object):
+ execution_payload: ExecutionPayload
+ versioned_hashes: Sequence[VersionedHash]
+ parent_beacon_block_root: Root
+
+
+- name: NewPayloadRequest#electra
+ sources:
+ - file: beacon-chain/execution/engine_client.go
+ search: func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionData, versionedHashes []common.Hash, parentBlockRoot *common.Hash, executionRequests *pb.ExecutionRequests
+ spec: |
+
+ class NewPayloadRequest(object):
+ execution_payload: ExecutionPayload
+ versioned_hashes: Sequence[VersionedHash]
+ parent_beacon_block_root: Root
+ # [New in Electra]
+ execution_requests: ExecutionRequests
+
+
+- name: OptimisticStore
+ sources: []
+ spec: |
+
+ class OptimisticStore(object):
+ 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)
+
+
+- name: PayloadAttributes#bellatrix
+ sources:
+ - file: proto/engine/v1/execution_engine.proto
+ search: ^message PayloadAttributes\s*\{
+ regex: true
+ spec: |
+
+ class PayloadAttributes(object):
+ timestamp: uint64
+ prev_randao: Bytes32
+ suggested_fee_recipient: ExecutionAddress
+
+
+- name: PayloadAttributes#capella
+ sources:
+ - file: proto/engine/v1/execution_engine.proto
+ search: ^message PayloadAttributesV2
+ regex: true
+ spec: |
+
+ class PayloadAttributes(object):
+ timestamp: uint64
+ prev_randao: Bytes32
+ suggested_fee_recipient: ExecutionAddress
+ # [New in Capella]
+ withdrawals: Sequence[Withdrawal]
+
+
+- name: PayloadAttributes#deneb
+ sources:
+ - file: proto/engine/v1/execution_engine.proto
+ search: ^message PayloadAttributesV3
+ regex: true
+ spec: |
+
+ class PayloadAttributes(object):
+ timestamp: uint64
+ prev_randao: Bytes32
+ suggested_fee_recipient: ExecutionAddress
+ withdrawals: Sequence[Withdrawal]
+ # [New in Deneb:EIP4788]
+ parent_beacon_block_root: Root
+
+
+- name: Store
+ sources: []
+ spec: |
+
+ class Store(object):
+ 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)
+
diff --git a/specrefs/functions.yml b/specrefs/functions.yml
new file mode 100644
index 000000000000..90a45f1ebd74
--- /dev/null
+++ b/specrefs/functions.yml
@@ -0,0 +1,8682 @@
+- name: add_flag
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func AddValidatorFlag(
+ spec: |
+
+ def add_flag(flags: ParticipationFlags, flag_index: int) -> ParticipationFlags:
+ """
+ Return a new ``ParticipationFlags`` adding ``flag_index`` to ``flags``.
+ """
+ flag = ParticipationFlags(2**flag_index)
+ return flags | flag
+
+
+- name: add_validator_to_registry#phase0
+ sources:
+ - 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
+ ) -> None:
+ state.validators.append(get_validator_from_deposit(pubkey, withdrawal_credentials, amount))
+ state.balances.append(amount)
+
+
+- name: add_validator_to_registry#altair
+ sources:
+ - 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
+ ) -> None:
+ index = get_index_for_new_validator(state)
+ validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount)
+ set_or_append_list(state.validators, index, validator)
+ set_or_append_list(state.balances, index, amount)
+ # [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))
+
+
+- name: add_validator_to_registry#electra
+ sources:
+ - 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
+ ) -> None:
+ index = get_index_for_new_validator(state)
+ # [Modified in Electra:EIP7251]
+ validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount)
+ set_or_append_list(state.validators, index, validator)
+ 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))
+
+
+- name: apply_deposit#phase0
+ sources:
+ - file: beacon-chain/core/altair/deposit.go
+ search: func ApplyDeposit(
+ spec: |
+
+ def apply_deposit(
+ state: BeaconState,
+ pubkey: BLSPubkey,
+ withdrawal_credentials: Bytes32,
+ amount: uint64,
+ signature: BLSSignature,
+ ) -> None:
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ if pubkey not in validator_pubkeys:
+ # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
+ deposit_message = DepositMessage(
+ pubkey=pubkey,
+ withdrawal_credentials=withdrawal_credentials,
+ amount=amount,
+ )
+ # Fork-agnostic domain since deposits are valid across forks
+ domain = compute_domain(DOMAIN_DEPOSIT)
+ signing_root = compute_signing_root(deposit_message, domain)
+ if bls.Verify(pubkey, signing_root, signature):
+ add_validator_to_registry(state, pubkey, withdrawal_credentials, amount)
+ else:
+ # Increase balance by deposit amount
+ index = ValidatorIndex(validator_pubkeys.index(pubkey))
+ increase_balance(state, index, amount)
+
+
+- name: apply_deposit#electra
+ sources:
+ - file: beacon-chain/core/electra/deposits.go
+ search: func ApplyDeposit(
+ spec: |
+
+ def apply_deposit(
+ state: BeaconState,
+ pubkey: BLSPubkey,
+ withdrawal_credentials: Bytes32,
+ amount: uint64,
+ signature: BLSSignature,
+ ) -> None:
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ if pubkey not in validator_pubkeys:
+ # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
+ if is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature):
+ # [Modified in Electra:EIP7251]
+ add_validator_to_registry(state, pubkey, withdrawal_credentials, Gwei(0))
+ else:
+ return
+
+ # [Modified in Electra:EIP7251]
+ # Increase balance by deposit amount
+ state.pending_deposits.append(
+ PendingDeposit(
+ pubkey=pubkey,
+ withdrawal_credentials=withdrawal_credentials,
+ amount=amount,
+ signature=signature,
+ slot=GENESIS_SLOT, # Use GENESIS_SLOT to distinguish from a pending deposit request
+ )
+ )
+
+
+- name: apply_light_client_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientUpdateFromBeaconState(
+ spec: |
+
+ def apply_light_client_update(store: LightClientStore, update: LightClientUpdate) -> None:
+ store_period = compute_sync_committee_period_at_slot(store.finalized_header.beacon.slot)
+ update_finalized_period = compute_sync_committee_period_at_slot(
+ update.finalized_header.beacon.slot
+ )
+ if not is_next_sync_committee_known(store):
+ assert update_finalized_period == store_period
+ store.next_sync_committee = update.next_sync_committee
+ elif update_finalized_period == store_period + 1:
+ store.current_sync_committee = store.next_sync_committee
+ store.next_sync_committee = update.next_sync_committee
+ store.previous_max_active_participants = store.current_max_active_participants
+ store.current_max_active_participants = 0
+ if update.finalized_header.beacon.slot > store.finalized_header.beacon.slot:
+ store.finalized_header = update.finalized_header
+ if store.finalized_header.beacon.slot > store.optimistic_header.beacon.slot:
+ store.optimistic_header = store.finalized_header
+
+
+- name: apply_pending_deposit
+ sources:
+ - file: beacon-chain/core/electra/deposits.go
+ search: func ApplyPendingDeposit(
+ spec: |
+
+ def apply_pending_deposit(state: BeaconState, deposit: PendingDeposit) -> None:
+ """
+ Applies ``deposit`` to the ``state``.
+ """
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ if deposit.pubkey not in validator_pubkeys:
+ # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
+ if is_valid_deposit_signature(
+ deposit.pubkey, deposit.withdrawal_credentials, deposit.amount, deposit.signature
+ ):
+ add_validator_to_registry(
+ state, deposit.pubkey, deposit.withdrawal_credentials, deposit.amount
+ )
+ else:
+ validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
+ increase_balance(state, validator_index, deposit.amount)
+
+
+- name: block_to_light_client_header#altair
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func BlockToLightClientHeader(
+ spec: |
+
+ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
+ return LightClientHeader(
+ beacon=BeaconBlockHeader(
+ slot=block.message.slot,
+ proposer_index=block.message.proposer_index,
+ parent_root=block.message.parent_root,
+ state_root=block.message.state_root,
+ body_root=hash_tree_root(block.message.body),
+ ),
+ )
+
+
+- name: block_to_light_client_header#capella
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func BlockToLightClientHeader(
+ spec: |
+
+ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
+ epoch = compute_epoch_at_slot(block.message.slot)
+
+ if epoch >= CAPELLA_FORK_EPOCH:
+ payload = block.message.body.execution_payload
+ execution_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ withdrawals_root=hash_tree_root(payload.withdrawals),
+ )
+ execution_branch = ExecutionBranch(
+ compute_merkle_proof(block.message.body, EXECUTION_PAYLOAD_GINDEX)
+ )
+ else:
+ # Note that during fork transitions, `finalized_header` may still point to earlier forks.
+ # While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`),
+ # it was not included in the corresponding light client data. To ensure compatibility
+ # with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data.
+ execution_header = ExecutionPayloadHeader()
+ execution_branch = ExecutionBranch()
+
+ return LightClientHeader(
+ beacon=BeaconBlockHeader(
+ slot=block.message.slot,
+ proposer_index=block.message.proposer_index,
+ parent_root=block.message.parent_root,
+ state_root=block.message.state_root,
+ body_root=hash_tree_root(block.message.body),
+ ),
+ execution=execution_header,
+ execution_branch=execution_branch,
+ )
+
+
+- name: block_to_light_client_header#deneb
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func BlockToLightClientHeader(
+ spec: |
+
+ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
+ epoch = compute_epoch_at_slot(block.message.slot)
+
+ if epoch >= CAPELLA_FORK_EPOCH:
+ payload = block.message.body.execution_payload
+ execution_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ withdrawals_root=hash_tree_root(payload.withdrawals),
+ )
+
+ # [New in Deneb:EIP4844]
+ if epoch >= DENEB_FORK_EPOCH:
+ execution_header.blob_gas_used = payload.blob_gas_used
+ execution_header.excess_blob_gas = payload.excess_blob_gas
+
+ execution_branch = ExecutionBranch(
+ compute_merkle_proof(block.message.body, EXECUTION_PAYLOAD_GINDEX)
+ )
+ else:
+ # Note that during fork transitions, `finalized_header` may still point to earlier forks.
+ # While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`),
+ # it was not included in the corresponding light client data. To ensure compatibility
+ # with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data.
+ execution_header = ExecutionPayloadHeader()
+ execution_branch = ExecutionBranch()
+
+ return LightClientHeader(
+ beacon=BeaconBlockHeader(
+ slot=block.message.slot,
+ proposer_index=block.message.proposer_index,
+ parent_root=block.message.parent_root,
+ state_root=block.message.state_root,
+ body_root=hash_tree_root(block.message.body),
+ ),
+ execution=execution_header,
+ execution_branch=execution_branch,
+ )
+
+
+- name: bytes_to_uint64
+ sources:
+ - file: encoding/bytesutil/integers.go
+ search: func FromBytes8(
+ spec: |
+
+ def bytes_to_uint64(data: bytes) -> uint64:
+ """
+ Return the integer deserialization of ``data`` interpreted as ``ENDIANNESS``-endian.
+ """
+ return uint64(int.from_bytes(data, ENDIANNESS))
+
+
+- name: calculate_committee_fraction
+ sources: []
+ spec: |
+
+ 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)
+
+
+- name: check_if_validator_active
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsActiveValidator(
+ spec: |
+
+ def check_if_validator_active(state: BeaconState, validator_index: ValidatorIndex) -> bool:
+ validator = state.validators[validator_index]
+ return is_active_validator(validator, get_current_epoch(state))
+
+
+- name: compute_activation_exit_epoch
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ActivationExitEpoch(
+ spec: |
+
+ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch:
+ """
+ Return the epoch during which validator activations and exits initiated in ``epoch`` take effect.
+ """
+ return Epoch(epoch + 1 + MAX_SEED_LOOKAHEAD)
+
+
+- name: compute_columns_for_custody_group
+ sources:
+ - file: beacon-chain/core/peerdas/das_core.go
+ search: func ComputeColumnsForCustodyGroup(
+ spec: |
+
+ def compute_columns_for_custody_group(custody_group: CustodyIndex) -> Sequence[ColumnIndex]:
+ assert custody_group < NUMBER_OF_CUSTODY_GROUPS
+ columns_per_group = NUMBER_OF_COLUMNS // NUMBER_OF_CUSTODY_GROUPS
+ return [
+ ColumnIndex(NUMBER_OF_CUSTODY_GROUPS * i + custody_group) for i in range(columns_per_group)
+ ]
+
+
+- name: compute_committee
+ sources:
+ - file: beacon-chain/core/helpers/beacon_committee.go
+ search: func ComputeCommittee(
+ spec: |
+
+ def compute_committee(
+ 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
+ return [
+ indices[compute_shuffled_index(uint64(i), uint64(len(indices)), seed)]
+ for i in range(start, end)
+ ]
+
+
+- name: compute_consolidation_epoch_and_update_churn
+ sources:
+ - file: beacon-chain/core/electra/churn.go
+ search: func ComputeConsolidationEpochAndUpdateChurn(
+ spec: |
+
+ def compute_consolidation_epoch_and_update_churn(
+ state: BeaconState, consolidation_balance: Gwei
+ ) -> Epoch:
+ earliest_consolidation_epoch = max(
+ state.earliest_consolidation_epoch, compute_activation_exit_epoch(get_current_epoch(state))
+ )
+ per_epoch_consolidation_churn = get_consolidation_churn_limit(state)
+ # New epoch for consolidations.
+ if state.earliest_consolidation_epoch < earliest_consolidation_epoch:
+ consolidation_balance_to_consume = per_epoch_consolidation_churn
+ else:
+ consolidation_balance_to_consume = state.consolidation_balance_to_consume
+
+ # Consolidation doesn't fit in the current earliest epoch.
+ if consolidation_balance > consolidation_balance_to_consume:
+ balance_to_process = consolidation_balance - consolidation_balance_to_consume
+ additional_epochs = (balance_to_process - 1) // per_epoch_consolidation_churn + 1
+ earliest_consolidation_epoch += additional_epochs
+ consolidation_balance_to_consume += additional_epochs * per_epoch_consolidation_churn
+
+ # Consume the balance and update state variables.
+ state.consolidation_balance_to_consume = (
+ consolidation_balance_to_consume - consolidation_balance
+ )
+ state.earliest_consolidation_epoch = earliest_consolidation_epoch
+
+ return state.earliest_consolidation_epoch
+
+
+- name: compute_domain
+ sources:
+ - file: beacon-chain/core/signing/signing_root.go
+ search: func ComputeDomain(
+ spec: |
+
+ def compute_domain(
+ domain_type: DomainType, fork_version: Version = None, genesis_validators_root: Root = None
+ ) -> Domain:
+ """
+ Return the domain for the ``domain_type`` and ``fork_version``.
+ """
+ if fork_version is None:
+ fork_version = GENESIS_FORK_VERSION
+ if genesis_validators_root is None:
+ genesis_validators_root = Root() # all bytes zero by default
+ fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root)
+ return Domain(domain_type + fork_data_root[:28])
+
+
+- name: compute_epoch_at_slot
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToEpoch(
+ spec: |
+
+ def compute_epoch_at_slot(slot: Slot) -> Epoch:
+ """
+ Return the epoch number at ``slot``.
+ """
+ return Epoch(slot // SLOTS_PER_EPOCH)
+
+
+- name: compute_exit_epoch_and_update_churn
+ sources:
+ - file: beacon-chain/state/state-native/setters_churn.go
+ search: func (b *BeaconState) ExitEpochAndUpdateChurn(
+ spec: |
+
+ def compute_exit_epoch_and_update_churn(state: BeaconState, exit_balance: Gwei) -> Epoch:
+ earliest_exit_epoch = max(
+ state.earliest_exit_epoch, compute_activation_exit_epoch(get_current_epoch(state))
+ )
+ per_epoch_churn = get_activation_exit_churn_limit(state)
+ # New epoch for exits.
+ if state.earliest_exit_epoch < earliest_exit_epoch:
+ exit_balance_to_consume = per_epoch_churn
+ else:
+ exit_balance_to_consume = state.exit_balance_to_consume
+
+ # Exit doesn't fit in the current earliest epoch.
+ if exit_balance > exit_balance_to_consume:
+ balance_to_process = exit_balance - exit_balance_to_consume
+ additional_epochs = (balance_to_process - 1) // per_epoch_churn + 1
+ earliest_exit_epoch += additional_epochs
+ exit_balance_to_consume += additional_epochs * per_epoch_churn
+
+ # Consume the balance and update state variables.
+ state.exit_balance_to_consume = exit_balance_to_consume - exit_balance
+ state.earliest_exit_epoch = earliest_exit_epoch
+
+ return state.earliest_exit_epoch
+
+
+- name: compute_fork_data_root
+ sources:
+ - file: beacon-chain/core/signing/signing_root.go
+ search: func computeForkDataRoot(
+ spec: |
+
+ def compute_fork_data_root(current_version: Version, genesis_validators_root: Root) -> Root:
+ """
+ Return the 32-byte fork data root for the ``current_version`` and ``genesis_validators_root``.
+ This is used primarily in signature domains to avoid collisions across forks/chains.
+ """
+ return hash_tree_root(
+ ForkData(
+ current_version=current_version,
+ genesis_validators_root=genesis_validators_root,
+ )
+ )
+
+
+- name: compute_fork_digest#phase0
+ sources:
+ - file: beacon-chain/core/signing/signing_root.go
+ search: func ComputeForkDigest(
+ spec: |
+
+ def compute_fork_digest(current_version: Version, genesis_validators_root: Root) -> ForkDigest:
+ """
+ Return the 4-byte fork digest for the ``current_version`` and ``genesis_validators_root``.
+ This is a digest primarily used for domain separation on the p2p layer.
+ 4-bytes suffices for practical separation of forks/chains.
+ """
+ return ForkDigest(compute_fork_data_root(current_version, genesis_validators_root)[:4])
+
+
+- name: compute_fork_digest#fulu
+ sources: []
+ spec: |
+
+ def compute_fork_digest(
+ genesis_validators_root: Root,
+ # [New in Fulu:EIP7892]
+ epoch: Epoch,
+ ) -> ForkDigest:
+ """
+ Return the 4-byte fork digest for the ``version`` and ``genesis_validators_root``
+ XOR'd with the hash of the blob parameters for ``epoch``.
+
+ This is a digest primarily used for domain separation on the p2p layer.
+ 4-bytes suffices for practical separation of forks/chains.
+ """
+ fork_version = compute_fork_version(epoch)
+ base_digest = compute_fork_data_root(fork_version, genesis_validators_root)
+ blob_parameters = get_blob_parameters(epoch)
+
+ # Bitmask digest with hash of blob parameters
+ return ForkDigest(
+ bytes(
+ xor(
+ base_digest,
+ hash(
+ uint_to_bytes(uint64(blob_parameters.epoch))
+ + uint_to_bytes(uint64(blob_parameters.max_blobs_per_block))
+ ),
+ )
+ )[:4]
+ )
+
+
+- name: compute_fork_version#altair
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToForkVersion(
+ - file: time/slots/slottime.go
+ search: return version.Altair
+ spec: |
+
+ def compute_fork_version(epoch: Epoch) -> Version:
+ """
+ Return the fork version at the given ``epoch``.
+ """
+ if epoch >= ALTAIR_FORK_EPOCH:
+ return ALTAIR_FORK_VERSION
+ return GENESIS_FORK_VERSION
+
+
+- name: compute_fork_version#bellatrix
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToForkVersion(
+ - file: time/slots/slottime.go
+ search: return version.Bellatrix
+ spec: |
+
+ def compute_fork_version(epoch: Epoch) -> Version:
+ """
+ Return the fork version at the given ``epoch``.
+ """
+ if epoch >= BELLATRIX_FORK_EPOCH:
+ return BELLATRIX_FORK_VERSION
+ if epoch >= ALTAIR_FORK_EPOCH:
+ return ALTAIR_FORK_VERSION
+ return GENESIS_FORK_VERSION
+
+
+- name: compute_fork_version#capella
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToForkVersion(
+ - file: time/slots/slottime.go
+ search: return version.Capella
+ spec: |
+
+ def compute_fork_version(epoch: Epoch) -> Version:
+ """
+ Return the fork version at the given ``epoch``.
+ """
+ if epoch >= CAPELLA_FORK_EPOCH:
+ return CAPELLA_FORK_VERSION
+ if epoch >= BELLATRIX_FORK_EPOCH:
+ return BELLATRIX_FORK_VERSION
+ if epoch >= ALTAIR_FORK_EPOCH:
+ return ALTAIR_FORK_VERSION
+ return GENESIS_FORK_VERSION
+
+
+- name: compute_fork_version#deneb
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToForkVersion(
+ - file: time/slots/slottime.go
+ search: return version.Deneb
+ spec: |
+
+ def compute_fork_version(epoch: Epoch) -> Version:
+ """
+ Return the fork version at the given ``epoch``.
+ """
+ if epoch >= DENEB_FORK_EPOCH:
+ return DENEB_FORK_VERSION
+ if epoch >= CAPELLA_FORK_EPOCH:
+ return CAPELLA_FORK_VERSION
+ if epoch >= BELLATRIX_FORK_EPOCH:
+ return BELLATRIX_FORK_VERSION
+ if epoch >= ALTAIR_FORK_EPOCH:
+ return ALTAIR_FORK_VERSION
+ return GENESIS_FORK_VERSION
+
+
+- name: compute_fork_version#electra
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToForkVersion(
+ - file: time/slots/slottime.go
+ search: return version.Electra
+ spec: |
+
+ def compute_fork_version(epoch: Epoch) -> Version:
+ """
+ Return the fork version at the given ``epoch``.
+ """
+ if epoch >= ELECTRA_FORK_EPOCH:
+ return ELECTRA_FORK_VERSION
+ if epoch >= DENEB_FORK_EPOCH:
+ return DENEB_FORK_VERSION
+ if epoch >= CAPELLA_FORK_EPOCH:
+ return CAPELLA_FORK_VERSION
+ if epoch >= BELLATRIX_FORK_EPOCH:
+ return BELLATRIX_FORK_VERSION
+ if epoch >= ALTAIR_FORK_EPOCH:
+ return ALTAIR_FORK_VERSION
+ return GENESIS_FORK_VERSION
+
+
+- name: compute_fork_version#fulu
+ sources:
+ - file: time/slots/slottime.go
+ search: func ToForkVersion(
+ - file: time/slots/slottime.go
+ search: return version.Fulu
+ spec: |
+
+ def compute_fork_version(epoch: Epoch) -> Version:
+ """
+ Return the fork version at the given ``epoch``.
+ """
+ if epoch >= FULU_FORK_EPOCH:
+ return FULU_FORK_VERSION
+ if epoch >= ELECTRA_FORK_EPOCH:
+ return ELECTRA_FORK_VERSION
+ if epoch >= DENEB_FORK_EPOCH:
+ return DENEB_FORK_VERSION
+ if epoch >= CAPELLA_FORK_EPOCH:
+ return CAPELLA_FORK_VERSION
+ if epoch >= BELLATRIX_FORK_EPOCH:
+ return BELLATRIX_FORK_VERSION
+ if epoch >= ALTAIR_FORK_EPOCH:
+ return ALTAIR_FORK_VERSION
+ return GENESIS_FORK_VERSION
+
+
+- name: compute_matrix
+ sources: []
+ spec: |
+
+ def compute_matrix(blobs: Sequence[Blob]) -> Sequence[MatrixEntry]:
+ """
+ Return the full, flattened sequence of matrix entries.
+
+ This helper demonstrates the relationship between blobs and the matrix of cells/proofs.
+ The data structure for storing cells/proofs is implementation-dependent.
+ """
+ matrix = []
+ for blob_index, blob in enumerate(blobs):
+ cells, proofs = compute_cells_and_kzg_proofs(blob)
+ for cell_index, (cell, proof) in enumerate(zip(cells, proofs)):
+ matrix.append(
+ MatrixEntry(
+ cell=cell,
+ kzg_proof=proof,
+ row_index=blob_index,
+ column_index=cell_index,
+ )
+ )
+ return matrix
+
+
+- name: compute_new_state_root
+ sources:
+ - file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go
+ search: func (vs *Server) computeStateRoot(
+ spec: |
+
+ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root:
+ temp_state: BeaconState = state.copy()
+ signed_block = SignedBeaconBlock(message=block)
+ state_transition(temp_state, signed_block, validate_result=False)
+ return hash_tree_root(temp_state)
+
+
+- name: compute_on_chain_aggregate
+ sources:
+ - 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]()
+ for a in aggregates:
+ for b in a.aggregation_bits:
+ aggregation_bits.append(b)
+
+ signature = bls.Aggregate([a.signature for a in aggregates])
+
+ committee_indices = [get_committee_indices(a.committee_bits)[0] for a in aggregates]
+ committee_flags = [(index in committee_indices) for index in range(0, MAX_COMMITTEES_PER_SLOT)]
+ committee_bits = Bitvector[MAX_COMMITTEES_PER_SLOT](committee_flags)
+
+ return Attestation(
+ aggregation_bits=aggregation_bits,
+ data=data,
+ committee_bits=committee_bits,
+ signature=signature,
+ )
+
+
+- name: compute_proposer_index#phase0
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ComputeProposerIndex(
+ spec: |
+
+ def compute_proposer_index(
+ state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32
+ ) -> ValidatorIndex:
+ """
+ Return from ``indices`` a random index sampled by effective balance.
+ """
+ assert len(indices) > 0
+ MAX_RANDOM_BYTE = 2**8 - 1
+ 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]
+ effective_balance = state.validators[candidate_index].effective_balance
+ if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
+ return candidate_index
+ i += 1
+
+
+- name: compute_proposer_index#electra
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ComputeProposerIndex(
+ - 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:
+ """
+ Return from ``indices`` a random index sampled by effective balance.
+ """
+ assert len(indices) > 0
+ # [Modified in Electra]
+ MAX_RANDOM_VALUE = 2**16 - 1
+ i = uint64(0)
+ total = uint64(len(indices))
+ while True:
+ candidate_index = indices[compute_shuffled_index(i % total, total, seed)]
+ # [Modified in Electra]
+ random_bytes = hash(seed + uint_to_bytes(i // 16))
+ offset = i % 16 * 2
+ random_value = bytes_to_uint64(random_bytes[offset : offset + 2])
+ effective_balance = state.validators[candidate_index].effective_balance
+ # [Modified in Electra:EIP7251]
+ if effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value:
+ return candidate_index
+ i += 1
+
+
+- name: compute_proposer_indices
+ sources:
+ - 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]:
+ """
+ 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]
+
+
+- name: compute_pulled_up_tip
+ sources: []
+ spec: |
+
+ def compute_pulled_up_tip(store: Store, block_root: Root) -> None:
+ state = store.block_states[block_root].copy()
+ # Pull up the post-state of the block to the next epoch boundary
+ process_justification_and_finalization(state)
+
+ store.unrealized_justifications[block_root] = state.current_justified_checkpoint
+ update_unrealized_checkpoints(
+ store, state.current_justified_checkpoint, state.finalized_checkpoint
+ )
+
+ # If the block is from a prior epoch, apply the realized values
+ block_epoch = compute_epoch_at_slot(store.blocks[block_root].slot)
+ current_epoch = get_current_store_epoch(store)
+ if block_epoch < current_epoch:
+ update_checkpoints(store, state.current_justified_checkpoint, state.finalized_checkpoint)
+
+
+- name: compute_shuffled_index
+ sources:
+ - file: beacon-chain/core/helpers/shuffle.go
+ search: func ComputeShuffledIndex(
+ spec: |
+
+ def compute_shuffled_index(index: uint64, index_count: uint64, seed: Bytes32) -> uint64:
+ """
+ Return the shuffled index corresponding to ``seed`` (and ``index_count``).
+ """
+ assert index < 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
+ for current_round in range(SHUFFLE_ROUND_COUNT):
+ pivot = bytes_to_uint64(hash(seed + uint_to_bytes(uint8(current_round)))[0:8]) % index_count
+ flip = (pivot + index_count - index) % index_count
+ position = max(index, flip)
+ source = hash(
+ seed + uint_to_bytes(uint8(current_round)) + uint_to_bytes(uint32(position // 256))
+ )
+ byte = uint8(source[(position % 256) // 8])
+ bit = (byte >> (position % 8)) % 2
+ index = flip if bit else index
+
+ return index
+
+
+- name: compute_signed_block_header
+ sources:
+ - file: consensus-types/interfaces/utils.go
+ search: func SignedBeaconBlockHeaderFromBlock(
+ spec: |
+
+ def compute_signed_block_header(signed_block: SignedBeaconBlock) -> SignedBeaconBlockHeader:
+ block = signed_block.message
+ block_header = BeaconBlockHeader(
+ slot=block.slot,
+ proposer_index=block.proposer_index,
+ parent_root=block.parent_root,
+ state_root=block.state_root,
+ body_root=hash_tree_root(block.body),
+ )
+ return SignedBeaconBlockHeader(message=block_header, signature=signed_block.signature)
+
+
+- name: compute_signing_root
+ sources:
+ - file: beacon-chain/core/signing/signing_root.go
+ search: func ComputeSigningRoot(
+ spec: |
+
+ def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
+ """
+ Return the signing root for the corresponding signing data.
+ """
+ return hash_tree_root(
+ SigningData(
+ object_root=hash_tree_root(ssz_object),
+ domain=domain,
+ )
+ )
+
+
+- name: compute_slots_since_epoch_start
+ sources:
+ - file: time/slots/slottime.go
+ search: func SinceEpochStarts(
+ spec: |
+
+ def compute_slots_since_epoch_start(slot: Slot) -> int:
+ return slot - compute_start_slot_at_epoch(compute_epoch_at_slot(slot))
+
+
+- name: compute_start_slot_at_epoch
+ sources:
+ - file: time/slots/slottime.go
+ search: func EpochStart(
+ spec: |
+
+ def compute_start_slot_at_epoch(epoch: Epoch) -> Slot:
+ """
+ Return the start slot of ``epoch``.
+ """
+ return Slot(epoch * SLOTS_PER_EPOCH)
+
+
+- name: compute_subnet_for_attestation
+ sources:
+ - 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
+ ) -> 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)
+ committees_since_epoch_start = committees_per_slot * slots_since_epoch_start
+
+ return SubnetID((committees_since_epoch_start + committee_index) % ATTESTATION_SUBNET_COUNT)
+
+
+- name: compute_subnet_for_blob_sidecar#deneb
+ sources:
+ - file: beacon-chain/sync/validate_blob.go
+ search: func computeSubnetForBlobSidecar(
+ spec: |
+
+ def compute_subnet_for_blob_sidecar(blob_index: BlobIndex) -> SubnetID:
+ return SubnetID(blob_index % BLOB_SIDECAR_SUBNET_COUNT)
+
+
+- name: compute_subnet_for_blob_sidecar#electra
+ sources:
+ - file: beacon-chain/sync/validate_blob.go
+ search: func computeSubnetForBlobSidecar(
+ - file: beacon-chain/sync/validate_blob.go
+ search: if slots.ToEpoch(slot) >= params.BeaconConfig().ElectraForkEpoch {
+ spec: |
+
+ def compute_subnet_for_blob_sidecar(blob_index: BlobIndex) -> SubnetID:
+ return SubnetID(blob_index % BLOB_SIDECAR_SUBNET_COUNT_ELECTRA)
+
+
+- name: compute_subnet_for_data_column_sidecar
+ sources:
+ - file: beacon-chain/core/peerdas/p2p_interface.go
+ search: func ComputeSubnetForDataColumnSidecar(
+ spec: |
+
+ def compute_subnet_for_data_column_sidecar(column_index: ColumnIndex) -> SubnetID:
+ return SubnetID(column_index % DATA_COLUMN_SIDECAR_SUBNET_COUNT)
+
+
+- name: compute_subnets_for_sync_committee
+ sources:
+ - file: beacon-chain/sync/validate_sync_committee_message.go
+ search: func (s *Service) rejectIncorrectSyncCommittee(
+ spec: |
+
+ def compute_subnets_for_sync_committee(
+ state: BeaconState, validator_index: ValidatorIndex
+ ) -> Set[SubnetID]:
+ next_slot_epoch = compute_epoch_at_slot(Slot(state.slot + 1))
+ if compute_sync_committee_period(get_current_epoch(state)) == compute_sync_committee_period(
+ next_slot_epoch
+ ):
+ sync_committee = state.current_sync_committee
+ else:
+ sync_committee = state.next_sync_committee
+
+ target_pubkey = state.validators[validator_index].pubkey
+ sync_committee_indices = [
+ index for index, pubkey in enumerate(sync_committee.pubkeys) if pubkey == target_pubkey
+ ]
+ return set(
+ [
+ SubnetID(index // (SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT))
+ for index in sync_committee_indices
+ ]
+ )
+
+
+- name: compute_subscribed_subnet
+ sources:
+ - file: beacon-chain/p2p/subnets.go
+ search: func computeSubscribedSubnet(
+ spec: |
+
+ def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID:
+ node_id_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS)
+ node_offset = node_id % EPOCHS_PER_SUBNET_SUBSCRIPTION
+ permutation_seed = hash(
+ uint_to_bytes(uint64((epoch + node_offset) // EPOCHS_PER_SUBNET_SUBSCRIPTION))
+ )
+ permutated_prefix = compute_shuffled_index(
+ node_id_prefix,
+ 1 << ATTESTATION_SUBNET_PREFIX_BITS,
+ permutation_seed,
+ )
+ return SubnetID((permutated_prefix + index) % ATTESTATION_SUBNET_COUNT)
+
+
+- name: compute_subscribed_subnets
+ sources:
+ - file: beacon-chain/p2p/subnets.go
+ search: func computeSubscribedSubnets(
+ spec: |
+
+ def compute_subscribed_subnets(node_id: NodeID, epoch: Epoch) -> Sequence[SubnetID]:
+ return [compute_subscribed_subnet(node_id, epoch, index) for index in range(SUBNETS_PER_NODE)]
+
+
+- name: compute_sync_committee_period
+ sources:
+ - file: time/slots/slottime.go
+ search: func SyncCommitteePeriod(
+ spec: |
+
+ def compute_sync_committee_period(epoch: Epoch) -> uint64:
+ return epoch // EPOCHS_PER_SYNC_COMMITTEE_PERIOD
+
+
+- name: compute_sync_committee_period_at_slot
+ sources: []
+ spec: |
+
+ def compute_sync_committee_period_at_slot(slot: Slot) -> uint64:
+ return compute_sync_committee_period(compute_epoch_at_slot(slot))
+
+
+- name: compute_time_at_slot
+ sources:
+ - file: time/slots/slottime.go
+ search: func StartTime(
+ spec: |
+
+ def compute_time_at_slot(state: BeaconState, slot: Slot) -> uint64:
+ slots_since_genesis = slot - GENESIS_SLOT
+ return uint64(state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT)
+
+
+- name: compute_weak_subjectivity_period#phase0
+ sources:
+ - file: beacon-chain/core/helpers/weak_subjectivity.go
+ search: func ComputeWeakSubjectivityPeriod(
+ spec: |
+
+ 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:
+ - validator set churn (bounded by ``get_validator_churn_limit()`` per epoch), and
+ - validator balance top-ups (bounded by ``MAX_DEPOSITS * SLOTS_PER_EPOCH`` per epoch).
+ A detailed calculation can be found at:
+ https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf
+ """
+ ws_period = MIN_VALIDATOR_WITHDRAWABILITY_DELAY
+ N = len(get_active_validator_indices(state, get_current_epoch(state)))
+ t = get_total_active_balance(state) // N // ETH_TO_GWEI
+ T = MAX_EFFECTIVE_BALANCE // ETH_TO_GWEI
+ delta = get_validator_churn_limit(state)
+ Delta = MAX_DEPOSITS * SLOTS_PER_EPOCH
+ D = SAFETY_DECAY
+
+ if T * (200 + 3 * D) < t * (200 + 12 * D):
+ epochs_for_validator_set_churn = (
+ N * (t * (200 + 12 * D) - T * (200 + 3 * D)) // (600 * delta * (2 * t + T))
+ )
+ epochs_for_balance_top_ups = N * (200 + 3 * D) // (600 * Delta)
+ ws_period += max(epochs_for_validator_set_churn, epochs_for_balance_top_ups)
+ else:
+ ws_period += 3 * N * D * t // (200 * Delta * (T - t))
+
+ return ws_period
+
+
+- name: compute_weak_subjectivity_period#electra
+ sources: []
+ spec: |
+
+ 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:
+ - validator set churn (bounded by ``get_balance_churn_limit()`` per epoch)
+ A detailed calculation can be found at:
+ https://notes.ethereum.org/@CarlBeek/electra_weak_subjectivity
+ """
+ t = get_total_active_balance(state)
+ delta = get_balance_churn_limit(state)
+ epochs_for_validator_set_churn = SAFETY_DECAY * t // (2 * delta * 100)
+ return MIN_VALIDATOR_WITHDRAWABILITY_DELAY + epochs_for_validator_set_churn
+
+
+- name: create_light_client_bootstrap
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientBootstrapFromBeaconState(
+ spec: |
+
+ def create_light_client_bootstrap(
+ state: BeaconState, block: SignedBeaconBlock
+ ) -> LightClientBootstrap:
+ assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
+
+ assert state.slot == state.latest_block_header.slot
+ header = state.latest_block_header.copy()
+ header.state_root = hash_tree_root(state)
+ assert hash_tree_root(header) == hash_tree_root(block.message)
+
+ return LightClientBootstrap(
+ header=block_to_light_client_header(block),
+ current_sync_committee=state.current_sync_committee,
+ current_sync_committee_branch=CurrentSyncCommitteeBranch(
+ compute_merkle_proof(state, current_sync_committee_gindex_at_slot(state.slot))
+ ),
+ )
+
+
+- name: create_light_client_finality_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientFinalityUpdateFromBeaconState(
+ spec: |
+
+ def create_light_client_finality_update(update: LightClientUpdate) -> LightClientFinalityUpdate:
+ return LightClientFinalityUpdate(
+ attested_header=update.attested_header,
+ finalized_header=update.finalized_header,
+ finality_branch=update.finality_branch,
+ sync_aggregate=update.sync_aggregate,
+ signature_slot=update.signature_slot,
+ )
+
+
+- name: create_light_client_optimistic_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientOptimisticUpdateFromBeaconState(
+ spec: |
+
+ def create_light_client_optimistic_update(update: LightClientUpdate) -> LightClientOptimisticUpdate:
+ return LightClientOptimisticUpdate(
+ attested_header=update.attested_header,
+ sync_aggregate=update.sync_aggregate,
+ signature_slot=update.signature_slot,
+ )
+
+
+- name: create_light_client_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientUpdateFromBeaconState(
+ spec: |
+
+ def create_light_client_update(
+ state: BeaconState,
+ block: SignedBeaconBlock,
+ attested_state: BeaconState,
+ attested_block: SignedBeaconBlock,
+ finalized_block: Optional[SignedBeaconBlock],
+ ) -> LightClientUpdate:
+ assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
+ assert (
+ sum(block.message.body.sync_aggregate.sync_committee_bits)
+ >= MIN_SYNC_COMMITTEE_PARTICIPANTS
+ )
+
+ assert state.slot == state.latest_block_header.slot
+ header = state.latest_block_header.copy()
+ header.state_root = hash_tree_root(state)
+ assert hash_tree_root(header) == hash_tree_root(block.message)
+ update_signature_period = compute_sync_committee_period_at_slot(block.message.slot)
+
+ assert attested_state.slot == attested_state.latest_block_header.slot
+ attested_header = attested_state.latest_block_header.copy()
+ attested_header.state_root = hash_tree_root(attested_state)
+ assert (
+ hash_tree_root(attested_header)
+ == hash_tree_root(attested_block.message)
+ == block.message.parent_root
+ )
+ update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot)
+
+ update = LightClientUpdate()
+
+ update.attested_header = block_to_light_client_header(attested_block)
+
+ # `next_sync_committee` is only useful if the message is signed by the current sync committee
+ if update_attested_period == update_signature_period:
+ update.next_sync_committee = attested_state.next_sync_committee
+ update.next_sync_committee_branch = NextSyncCommitteeBranch(
+ compute_merkle_proof(
+ attested_state, next_sync_committee_gindex_at_slot(attested_state.slot)
+ )
+ )
+
+ # Indicate finality whenever possible
+ if finalized_block is not None:
+ if finalized_block.message.slot != GENESIS_SLOT:
+ update.finalized_header = block_to_light_client_header(finalized_block)
+ assert (
+ hash_tree_root(update.finalized_header.beacon)
+ == attested_state.finalized_checkpoint.root
+ )
+ else:
+ assert attested_state.finalized_checkpoint.root == Bytes32()
+ update.finality_branch = FinalityBranch(
+ compute_merkle_proof(attested_state, finalized_root_gindex_at_slot(attested_state.slot))
+ )
+
+ update.sync_aggregate = block.message.body.sync_aggregate
+ update.signature_slot = block.message.slot
+
+ return update
+
+
+- name: current_sync_committee_gindex_at_slot#altair
+ sources:
+ - file: beacon-chain/state/state-native/proofs.go
+ search: func (b *BeaconState) CurrentSyncCommitteeGeneralizedIndex(
+ spec: |
+
+ def current_sync_committee_gindex_at_slot(_slot: Slot) -> GeneralizedIndex:
+ return CURRENT_SYNC_COMMITTEE_GINDEX
+
+
+- name: current_sync_committee_gindex_at_slot#electra
+ sources: []
+ spec: |
+
+ def current_sync_committee_gindex_at_slot(slot: Slot) -> GeneralizedIndex:
+ epoch = compute_epoch_at_slot(slot)
+
+ # [Modified in Electra]
+ if epoch >= ELECTRA_FORK_EPOCH:
+ return CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA
+ return CURRENT_SYNC_COMMITTEE_GINDEX
+
+
+- name: decrease_balance
+ sources:
+ - file: beacon-chain/core/helpers/rewards_penalties.go
+ search: func DecreaseBalance(
+ spec: |
+
+ def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
+ """
+ Decrease the validator balance at index ``index`` by ``delta``, with underflow protection.
+ """
+ state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
+
+
+- name: eth_aggregate_pubkeys
+ sources:
+ - file: crypto/bls/bls.go
+ search: func AggregatePublicKeys(
+ spec: |
+
+ def eth_aggregate_pubkeys(pubkeys: Sequence[BLSPubkey]) -> BLSPubkey:
+ return bls.AggregatePKs(pubkeys)
+
+
+- name: eth_fast_aggregate_verify
+ sources:
+ - file: crypto/bls/blst/signature.go
+ search: func (s *Signature) Eth2FastAggregateVerify(
+ spec: |
+
+ def eth_fast_aggregate_verify(
+ pubkeys: Sequence[BLSPubkey], message: Bytes32, signature: BLSSignature
+ ) -> bool:
+ """
+ Wrapper to ``bls.FastAggregateVerify`` accepting the ``G2_POINT_AT_INFINITY`` signature when ``pubkeys`` is empty.
+ """
+ if len(pubkeys) == 0 and signature == G2_POINT_AT_INFINITY:
+ return True
+ return bls.FastAggregateVerify(pubkeys, message, signature)
+
+
+- name: filter_block_tree
+ sources: []
+ spec: |
+
+ def filter_block_tree(store: Store, block_root: Root, blocks: Dict[Root, BeaconBlock]) -> bool:
+ block = store.blocks[block_root]
+ children = [
+ root for root in store.blocks.keys() if store.blocks[root].parent_root == block_root
+ ]
+
+ # If any children branches contain expected finalized/justified checkpoints,
+ # add to filtered block-tree and signal viability to parent.
+ if any(children):
+ filter_block_tree_result = [filter_block_tree(store, child, blocks) for child in children]
+ if any(filter_block_tree_result):
+ blocks[block_root] = block
+ return True
+ return False
+
+ current_epoch = get_current_store_epoch(store)
+ voting_source = get_voting_source(store, block_root)
+
+ # The voting source should be either at the same height as the store's justified checkpoint or
+ # not more than two epochs ago
+ correct_justified = (
+ store.justified_checkpoint.epoch == GENESIS_EPOCH
+ or voting_source.epoch == store.justified_checkpoint.epoch
+ or voting_source.epoch + 2 >= current_epoch
+ )
+
+ finalized_checkpoint_block = get_checkpoint_block(
+ store,
+ block_root,
+ store.finalized_checkpoint.epoch,
+ )
+
+ correct_finalized = (
+ store.finalized_checkpoint.epoch == GENESIS_EPOCH
+ or store.finalized_checkpoint.root == finalized_checkpoint_block
+ )
+
+ # If expected finalized/justified, add to viable block-tree and signal viability to parent.
+ if correct_justified and correct_finalized:
+ blocks[block_root] = block
+ return True
+
+ # Otherwise, branch not viable
+ return False
+
+
+- name: finalized_root_gindex_at_slot#altair
+ sources:
+ - file: beacon-chain/state/state-native/proofs.go
+ search: func FinalizedRootGeneralizedIndex(
+ spec: |
+
+ def finalized_root_gindex_at_slot(_slot: Slot) -> GeneralizedIndex:
+ return FINALIZED_ROOT_GINDEX
+
+
+- name: finalized_root_gindex_at_slot#electra
+ sources: []
+ spec: |
+
+ def finalized_root_gindex_at_slot(slot: Slot) -> GeneralizedIndex:
+ epoch = compute_epoch_at_slot(slot)
+
+ # [Modified in Electra]
+ if epoch >= ELECTRA_FORK_EPOCH:
+ return FINALIZED_ROOT_GINDEX_ELECTRA
+ return FINALIZED_ROOT_GINDEX
+
+
+- name: get_activation_exit_churn_limit
+ sources:
+ - file: beacon-chain/core/helpers/validator_churn.go
+ search: func ActivationExitChurnLimit(
+ spec: |
+
+ def get_activation_exit_churn_limit(state: BeaconState) -> Gwei:
+ """
+ Return the churn limit for the current epoch dedicated to activations and exits.
+ """
+ return min(MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, get_balance_churn_limit(state))
+
+
+- name: get_active_validator_indices
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ActiveValidatorIndices(
+ spec: |
+
+ def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> Sequence[ValidatorIndex]:
+ """
+ Return the sequence of active validator indices at ``epoch``.
+ """
+ return [
+ ValidatorIndex(i) for i, v in enumerate(state.validators) if is_active_validator(v, epoch)
+ ]
+
+
+- name: get_aggregate_and_proof
+ sources: []
+ spec: |
+
+ def get_aggregate_and_proof(
+ state: BeaconState, aggregator_index: ValidatorIndex, aggregate: Attestation, privkey: int
+ ) -> AggregateAndProof:
+ return AggregateAndProof(
+ aggregator_index=aggregator_index,
+ aggregate=aggregate,
+ selection_proof=get_slot_signature(state, aggregate.data.slot, privkey),
+ )
+
+
+- name: get_aggregate_and_proof_signature
+ sources:
+ - file: validator/client/aggregate.go
+ search: func (v *validator) aggregateAndProofSig(
+ spec: |
+
+ def get_aggregate_and_proof_signature(
+ state: BeaconState, aggregate_and_proof: AggregateAndProof, privkey: int
+ ) -> BLSSignature:
+ aggregate = aggregate_and_proof.aggregate
+ domain = get_domain(
+ state, DOMAIN_AGGREGATE_AND_PROOF, compute_epoch_at_slot(aggregate.data.slot)
+ )
+ signing_root = compute_signing_root(aggregate_and_proof, domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_aggregate_signature
+ sources:
+ - file: crypto/bls/bls.go
+ search: func AggregateSignatures(
+ spec: |
+
+ def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature:
+ signatures = [attestation.signature for attestation in attestations]
+ return bls.Aggregate(signatures)
+
+
+- name: get_ancestor
+ sources:
+ - file: beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go
+ search: func (f *ForkChoice) AncestorRoot(
+ spec: |
+
+ def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
+ block = store.blocks[root]
+ if block.slot > slot:
+ return get_ancestor(store, block.parent_root, slot)
+ return root
+
+
+- name: get_attestation_component_deltas
+ sources: []
+ spec: |
+
+ def get_attestation_component_deltas(
+ state: BeaconState, attestations: Sequence[PendingAttestation]
+ ) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Helper with shared logic for use by get source, target, and head deltas functions
+ """
+ rewards = [Gwei(0)] * len(state.validators)
+ penalties = [Gwei(0)] * len(state.validators)
+ total_balance = get_total_active_balance(state)
+ unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations)
+ 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
+ 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.
+ rewards[index] += get_base_reward(state, index)
+ else:
+ reward_numerator = get_base_reward(state, index) * (attesting_balance // increment)
+ rewards[index] += reward_numerator // (total_balance // increment)
+ else:
+ penalties[index] += get_base_reward(state, index)
+ return rewards, penalties
+
+
+- name: get_attestation_deltas
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return attestation reward/penalty deltas for each validator.
+ """
+ source_rewards, source_penalties = get_source_deltas(state)
+ target_rewards, target_penalties = get_target_deltas(state)
+ head_rewards, head_penalties = get_head_deltas(state)
+ inclusion_delay_rewards, _ = get_inclusion_delay_deltas(state)
+ _, inactivity_penalties = get_inactivity_penalty_deltas(state)
+
+ rewards = [
+ source_rewards[i] + target_rewards[i] + head_rewards[i] + inclusion_delay_rewards[i]
+ for i in range(len(state.validators))
+ ]
+
+ penalties = [
+ source_penalties[i] + target_penalties[i] + head_penalties[i] + inactivity_penalties[i]
+ for i in range(len(state.validators))
+ ]
+
+ return rewards, penalties
+
+
+- name: get_attestation_participation_flag_indices#altair
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func AttestationParticipationFlagIndices(
+ spec: |
+
+ def get_attestation_participation_flag_indices(
+ state: BeaconState, data: AttestationData, inclusion_delay: uint64
+ ) -> Sequence[int]:
+ """
+ Return the flag indices that are satisfied by an attestation.
+ """
+ if data.target.epoch == get_current_epoch(state):
+ justified_checkpoint = state.current_justified_checkpoint
+ else:
+ justified_checkpoint = state.previous_justified_checkpoint
+
+ # Matching roots
+ is_matching_source = data.source == justified_checkpoint
+ is_matching_target = is_matching_source and data.target.root == get_block_root(
+ state, data.target.epoch
+ )
+ is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(
+ state, data.slot
+ )
+ assert is_matching_source
+
+ participation_flag_indices = []
+ if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH):
+ participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX)
+ if is_matching_target and inclusion_delay <= SLOTS_PER_EPOCH:
+ participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX)
+ if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY:
+ participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX)
+
+ return participation_flag_indices
+
+
+- name: get_attestation_participation_flag_indices#deneb
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func AttestationParticipationFlagIndices(
+ spec: |
+
+ def get_attestation_participation_flag_indices(
+ state: BeaconState, data: AttestationData, inclusion_delay: uint64
+ ) -> Sequence[int]:
+ """
+ Return the flag indices that are satisfied by an attestation.
+ """
+ if data.target.epoch == get_current_epoch(state):
+ justified_checkpoint = state.current_justified_checkpoint
+ else:
+ justified_checkpoint = state.previous_justified_checkpoint
+
+ # Matching roots
+ is_matching_source = data.source == justified_checkpoint
+ is_matching_target = is_matching_source and data.target.root == get_block_root(
+ state, data.target.epoch
+ )
+ is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(
+ state, data.slot
+ )
+ assert is_matching_source
+
+ participation_flag_indices = []
+ if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH):
+ participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX)
+ # [Modified in Deneb:EIP7045]
+ if is_matching_target:
+ participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX)
+ if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY:
+ participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX)
+
+ return participation_flag_indices
+
+
+- name: get_attestation_signature
+ sources:
+ - file: beacon-chain/core/blocks/signature.go
+ search: func AttestationSignatureBatch(
+ spec: |
+
+ def get_attestation_signature(
+ state: BeaconState, attestation_data: AttestationData, privkey: int
+ ) -> BLSSignature:
+ domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch)
+ signing_root = compute_signing_root(attestation_data, domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_attesting_balance
+ sources: []
+ spec: |
+
+ def get_attesting_balance(state: BeaconState, attestations: Sequence[PendingAttestation]) -> Gwei:
+ """
+ Return the combined effective balance of the set of unslashed validators participating in ``attestations``.
+ Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
+ """
+ return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
+
+
+- name: get_attesting_indices#phase0
+ sources:
+ - file: proto/prysm/v1alpha1/attestation/attestation_utils.go
+ search: func AttestingIndices(
+ spec: |
+
+ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
+ """
+ Return the set of attesting indices corresponding to ``data`` and ``bits``.
+ """
+ committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
+ return set(index for i, index in enumerate(committee) if attestation.aggregation_bits[i])
+
+
+- name: get_attesting_indices#electra
+ sources:
+ - file: proto/prysm/v1alpha1/attestation/attestation_utils.go
+ search: func AttestingIndices(
+ spec: |
+
+ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
+ """
+ Return the set of attesting indices corresponding to ``aggregation_bits`` and ``committee_bits``.
+ """
+ output: Set[ValidatorIndex] = set()
+ committee_indices = get_committee_indices(attestation.committee_bits)
+ committee_offset = 0
+ for committee_index in committee_indices:
+ committee = get_beacon_committee(state, attestation.data.slot, committee_index)
+ committee_attesters = set(
+ attester_index
+ for i, attester_index in enumerate(committee)
+ if attestation.aggregation_bits[committee_offset + i]
+ )
+ output = output.union(committee_attesters)
+
+ committee_offset += len(committee)
+
+ return output
+
+
+- name: get_balance_churn_limit
+ sources:
+ - file: beacon-chain/core/helpers/validator_churn.go
+ search: func BalanceChurnLimit(
+ spec: |
+
+ def get_balance_churn_limit(state: BeaconState) -> Gwei:
+ """
+ Return the churn limit for the current epoch.
+ """
+ churn = max(
+ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA, get_total_active_balance(state) // CHURN_LIMIT_QUOTIENT
+ )
+ return churn - churn % EFFECTIVE_BALANCE_INCREMENT
+
+
+- name: get_base_reward#phase0
+ sources: []
+ spec: |
+
+ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
+ total_balance = get_total_active_balance(state)
+ effective_balance = state.validators[index].effective_balance
+ return Gwei(
+ effective_balance
+ * BASE_REWARD_FACTOR
+ // integer_squareroot(total_balance)
+ // BASE_REWARDS_PER_EPOCH
+ )
+
+
+- name: get_base_reward#altair
+ sources:
+ - file: beacon-chain/core/altair/reward.go
+ search: func BaseReward(
+ spec: |
+
+ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
+ """
+ Return the base reward for the validator defined by ``index`` with respect to the current ``state``.
+ """
+ increments = state.validators[index].effective_balance // EFFECTIVE_BALANCE_INCREMENT
+ return Gwei(increments * get_base_reward_per_increment(state))
+
+
+- name: get_base_reward_per_increment
+ sources:
+ - file: beacon-chain/core/altair/reward.go
+ search: func BaseRewardPerIncrement(
+ spec: |
+
+ def get_base_reward_per_increment(state: BeaconState) -> Gwei:
+ return Gwei(
+ EFFECTIVE_BALANCE_INCREMENT
+ * BASE_REWARD_FACTOR
+ // integer_squareroot(get_total_active_balance(state))
+ )
+
+
+- name: get_beacon_committee
+ sources:
+ - file: beacon-chain/core/helpers/beacon_committee.go
+ search: func BeaconCommittee(
+ spec: |
+
+ def get_beacon_committee(
+ state: BeaconState, slot: Slot, index: CommitteeIndex
+ ) -> Sequence[ValidatorIndex]:
+ """
+ Return the beacon committee at ``slot`` for ``index``.
+ """
+ epoch = compute_epoch_at_slot(slot)
+ committees_per_slot = get_committee_count_per_slot(state, epoch)
+ return compute_committee(
+ indices=get_active_validator_indices(state, epoch),
+ seed=get_seed(state, epoch, DOMAIN_BEACON_ATTESTER),
+ index=(slot % SLOTS_PER_EPOCH) * committees_per_slot + index,
+ count=committees_per_slot * SLOTS_PER_EPOCH,
+ )
+
+
+- name: get_beacon_proposer_index#phase0
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func BeaconProposerIndex(
+ spec: |
+
+ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
+ """
+ Return the beacon proposer index at the current slot.
+ """
+ epoch = get_current_epoch(state)
+ seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + uint_to_bytes(state.slot))
+ indices = get_active_validator_indices(state, epoch)
+ return compute_proposer_index(state, indices, seed)
+
+
+- name: get_beacon_proposer_index#fulu
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func BeaconProposerIndex(
+ - file: beacon-chain/core/helpers/validators.go
+ search: func beaconProposerIndexAtSlotFulu(
+ spec: |
+
+ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
+ """
+ Return the beacon proposer index at the current slot.
+ """
+ return state.proposer_lookahead[state.slot % SLOTS_PER_EPOCH]
+
+
+- name: get_beacon_proposer_indices
+ sources:
+ - 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]:
+ """
+ Return the proposer indices for the given ``epoch``.
+ """
+ indices = get_active_validator_indices(state, epoch)
+ seed = get_seed(state, epoch, DOMAIN_BEACON_PROPOSER)
+ return compute_proposer_indices(state, epoch, seed, indices)
+
+
+- name: get_blob_parameters
+ sources: []
+ spec: |
+
+ def get_blob_parameters(epoch: Epoch) -> BlobParameters:
+ """
+ Return the blob parameters at a given epoch.
+ """
+ for entry in sorted(BLOB_SCHEDULE, key=lambda e: e["EPOCH"], reverse=True):
+ if epoch >= entry["EPOCH"]:
+ return BlobParameters(entry["EPOCH"], entry["MAX_BLOBS_PER_BLOCK"])
+ return BlobParameters(ELECTRA_FORK_EPOCH, MAX_BLOBS_PER_BLOCK_ELECTRA)
+
+
+- name: get_blob_sidecars
+ sources:
+ - file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer_deneb.go
+ search: func BuildBlobSidecars(
+ spec: |
+
+ def get_blob_sidecars(
+ signed_block: SignedBeaconBlock, blobs: Sequence[Blob], blob_kzg_proofs: Sequence[KZGProof]
+ ) -> Sequence[BlobSidecar]:
+ block = signed_block.message
+ signed_block_header = compute_signed_block_header(signed_block)
+ return [
+ BlobSidecar(
+ index=index,
+ blob=blob,
+ kzg_commitment=block.body.blob_kzg_commitments[index],
+ kzg_proof=blob_kzg_proofs[index],
+ signed_block_header=signed_block_header,
+ kzg_commitment_inclusion_proof=compute_merkle_proof(
+ block.body,
+ get_generalized_index(BeaconBlockBody, "blob_kzg_commitments", index),
+ ),
+ )
+ for index, blob in enumerate(blobs)
+ ]
+
+
+- name: get_block_root
+ sources:
+ - file: beacon-chain/core/helpers/block.go
+ search: func BlockRoot(
+ spec: |
+
+ def get_block_root(state: BeaconState, epoch: Epoch) -> Root:
+ """
+ Return the block root at the start of a recent ``epoch``.
+ """
+ return get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch))
+
+
+- name: get_block_root_at_slot
+ sources:
+ - file: beacon-chain/core/helpers/block.go
+ search: func BlockRootAtSlot(
+ spec: |
+
+ def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Root:
+ """
+ Return the block root at a recent ``slot``.
+ """
+ assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
+ return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
+
+
+- name: get_block_signature
+ sources:
+ - file: testing/util/helpers.go
+ search: func BlockSignature(
+ spec: |
+
+ def get_block_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature:
+ domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block.slot))
+ signing_root = compute_signing_root(block, domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_checkpoint_block
+ sources: []
+ spec: |
+
+ def get_checkpoint_block(store: Store, root: Root, epoch: Epoch) -> Root:
+ """
+ Compute the checkpoint block for epoch ``epoch`` in the chain of block ``root``
+ """
+ epoch_first_slot = compute_start_slot_at_epoch(epoch)
+ return get_ancestor(store, root, epoch_first_slot)
+
+
+- name: get_committee_assignment
+ sources:
+ - file: beacon-chain/core/helpers/beacon_committee.go
+ search: func CommitteeAssignments(
+ spec: |
+
+ def get_committee_assignment(
+ state: BeaconState, epoch: Epoch, validator_index: ValidatorIndex
+ ) -> Optional[Tuple[Sequence[ValidatorIndex], CommitteeIndex, Slot]]:
+ """
+ Return the committee assignment in the ``epoch`` for ``validator_index``.
+ ``assignment`` returned is a tuple of the following form:
+ * ``assignment[0]`` is the list of validators in the committee
+ * ``assignment[1]`` is the index to which the committee is assigned
+ * ``assignment[2]`` is the slot at which the committee is assigned
+ Return None if no assignment.
+ """
+ next_epoch = Epoch(get_current_epoch(state) + 1)
+ assert epoch <= next_epoch
+
+ start_slot = compute_start_slot_at_epoch(epoch)
+ committee_count_per_slot = get_committee_count_per_slot(state, epoch)
+ for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
+ for index in range(committee_count_per_slot):
+ committee = get_beacon_committee(state, Slot(slot), CommitteeIndex(index))
+ if validator_index in committee:
+ return committee, CommitteeIndex(index), Slot(slot)
+ return None
+
+
+- name: get_committee_count_per_slot
+ sources:
+ - file: beacon-chain/core/helpers/beacon_committee.go
+ search: func SlotCommitteeCount(
+ spec: |
+
+ 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),
+ min(
+ MAX_COMMITTEES_PER_SLOT,
+ uint64(len(get_active_validator_indices(state, epoch)))
+ // SLOTS_PER_EPOCH
+ // TARGET_COMMITTEE_SIZE,
+ ),
+ )
+
+
+- name: get_committee_indices
+ sources:
+ - file: beacon-chain/core/helpers/beacon_committee.go
+ search: func CommitteeIndices(
+ spec: |
+
+ def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]:
+ return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit]
+
+
+- name: get_consolidation_churn_limit
+ sources:
+ - file: beacon-chain/core/helpers/validator_churn.go
+ search: func ConsolidationChurnLimit(
+ spec: |
+
+ def get_consolidation_churn_limit(state: BeaconState) -> Gwei:
+ return get_balance_churn_limit(state) - get_activation_exit_churn_limit(state)
+
+
+- name: get_contribution_and_proof
+ sources: []
+ spec: |
+
+ def get_contribution_and_proof(
+ state: BeaconState,
+ aggregator_index: ValidatorIndex,
+ contribution: SyncCommitteeContribution,
+ privkey: int,
+ ) -> ContributionAndProof:
+ selection_proof = get_sync_committee_selection_proof(
+ state,
+ contribution.slot,
+ contribution.subcommittee_index,
+ privkey,
+ )
+ return ContributionAndProof(
+ aggregator_index=aggregator_index,
+ contribution=contribution,
+ selection_proof=selection_proof,
+ )
+
+
+- name: get_contribution_and_proof_signature
+ sources:
+ - file: validator/client/sync_committee.go
+ search: func (v *validator) signContributionAndProof(
+ spec: |
+
+ def get_contribution_and_proof_signature(
+ state: BeaconState, contribution_and_proof: ContributionAndProof, privkey: int
+ ) -> BLSSignature:
+ contribution = contribution_and_proof.contribution
+ domain = get_domain(
+ state, DOMAIN_CONTRIBUTION_AND_PROOF, compute_epoch_at_slot(contribution.slot)
+ )
+ signing_root = compute_signing_root(contribution_and_proof, domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_current_epoch
+ sources:
+ - file: beacon-chain/core/time/slot_epoch.go
+ search: func CurrentEpoch(
+ spec: |
+
+ def get_current_epoch(state: BeaconState) -> Epoch:
+ """
+ Return the current epoch.
+ """
+ return compute_epoch_at_slot(state.slot)
+
+
+- name: get_current_slot
+ sources:
+ - file: time/slots/slottime.go
+ search: func CurrentSlot(
+ spec: |
+
+ def get_current_slot(store: Store) -> Slot:
+ return Slot(GENESIS_SLOT + get_slots_since_genesis(store))
+
+
+- name: get_current_store_epoch
+ sources: []
+ spec: |
+
+ def get_current_store_epoch(store: Store) -> Epoch:
+ return compute_epoch_at_slot(get_current_slot(store))
+
+
+- name: get_custody_groups
+ 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]:
+ 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] = []
+ 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
+ )
+ if custody_group not in custody_groups:
+ custody_groups.append(custody_group)
+ if current_id == UINT256_MAX:
+ # Overflow prevention
+ current_id = uint256(0)
+ else:
+ current_id += 1
+
+ assert len(custody_groups) == len(set(custody_groups))
+ return sorted(custody_groups)
+
+
+- name: get_data_column_sidecars
+ sources:
+ - file: beacon-chain/core/peerdas/das_core.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]]
+ ],
+ ) -> Sequence[DataColumnSidecar]:
+ """
+ Given a signed block header and the commitments, inclusion proof, cells/proofs associated with
+ each blob in the block, assemble the sidecars which can be distributed to peers.
+ """
+ assert len(cells_and_kzg_proofs) == len(kzg_commitments)
+
+ sidecars = []
+ for column_index in range(NUMBER_OF_COLUMNS):
+ column_cells, column_proofs = [], []
+ for cells, proofs in cells_and_kzg_proofs:
+ column_cells.append(cells[column_index])
+ column_proofs.append(proofs[column_index])
+ sidecars.append(
+ DataColumnSidecar(
+ index=column_index,
+ column=column_cells,
+ kzg_commitments=kzg_commitments,
+ kzg_proofs=column_proofs,
+ signed_block_header=signed_block_header,
+ kzg_commitments_inclusion_proof=kzg_commitments_inclusion_proof,
+ )
+ )
+ return sidecars
+
+
+- name: get_data_column_sidecars_from_block
+ sources:
+ - file: beacon-chain/core/peerdas/das_core.go
+ search: func dataColumnsSidecars(
+ 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]]
+ ],
+ ) -> Sequence[DataColumnSidecar]:
+ """
+ Given a signed block and the cells/proofs associated with each blob in the
+ block, assemble the sidecars which can be distributed to peers.
+ """
+ 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"),
+ )
+ return get_data_column_sidecars(
+ signed_block_header,
+ blob_kzg_commitments,
+ kzg_commitments_inclusion_proof,
+ cells_and_kzg_proofs,
+ )
+
+
+- name: get_data_column_sidecars_from_column_sidecar
+ 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]]
+ ],
+ ) -> Sequence[DataColumnSidecar]:
+ """
+ Given a DataColumnSidecar and the cells/proofs associated with each blob corresponding
+ to the commitments it contains, assemble all sidecars for distribution to peers.
+ """
+ assert len(cells_and_kzg_proofs) == len(sidecar.kzg_commitments)
+
+ return get_data_column_sidecars(
+ sidecar.signed_block_header,
+ sidecar.kzg_commitments,
+ sidecar.kzg_commitments_inclusion_proof,
+ cells_and_kzg_proofs,
+ )
+
+
+- name: get_domain
+ sources:
+ - file: beacon-chain/core/signing/domain.go
+ search: func Domain(
+ spec: |
+
+ def get_domain(state: BeaconState, domain_type: DomainType, epoch: Epoch = None) -> Domain:
+ """
+ Return the signature domain (fork version concatenated with domain type) of a message.
+ """
+ epoch = get_current_epoch(state) if epoch is None else epoch
+ fork_version = (
+ state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
+ )
+ return compute_domain(domain_type, fork_version, state.genesis_validators_root)
+
+
+- name: get_eligible_validator_indices
+ sources: []
+ spec: |
+
+ def get_eligible_validator_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
+ previous_epoch = get_previous_epoch(state)
+ return [
+ ValidatorIndex(index)
+ for index, v in enumerate(state.validators)
+ if is_active_validator(v, previous_epoch)
+ or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)
+ ]
+
+
+- name: get_epoch_signature
+ sources: []
+ spec: |
+
+ def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature:
+ domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot))
+ signing_root = compute_signing_root(compute_epoch_at_slot(block.slot), domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_eth1_pending_deposit_count
+ sources:
+ - 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:
+ 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)
+
+
+- name: get_eth1_vote#phase0
+ sources: []
+ spec: |
+
+ def get_eth1_vote(state: BeaconState, eth1_chain: Sequence[Eth1Block]) -> Eth1Data:
+ period_start = voting_period_start_time(state)
+ # `eth1_chain` abstractly represents all blocks in the eth1 chain sorted by ascending block height
+ votes_to_consider = [
+ get_eth1_data(block)
+ for block in eth1_chain
+ if (
+ is_candidate_block(block, period_start)
+ # Ensure cannot move back to earlier deposit contract states
+ and get_eth1_data(block).deposit_count >= state.eth1_data.deposit_count
+ )
+ ]
+
+ # Valid votes already cast during this period
+ valid_votes = [vote for vote in state.eth1_data_votes if vote in votes_to_consider]
+
+ # Default vote on latest eth1 block data in the period range unless eth1 chain is not live
+ # Non-substantive casting for linter
+ state_eth1_data: Eth1Data = state.eth1_data
+ default_vote = (
+ votes_to_consider[len(votes_to_consider) - 1] if any(votes_to_consider) else state_eth1_data
+ )
+
+ return max(
+ valid_votes,
+ # Tiebreak by smallest distance
+ key=lambda v: (
+ valid_votes.count(v),
+ -valid_votes.index(v),
+ ),
+ default=default_vote,
+ )
+
+
+- name: get_eth1_vote#electra
+ sources: []
+ spec: |
+
+ def get_eth1_vote(state: BeaconState, eth1_chain: Sequence[Eth1Block]) -> Eth1Data:
+ # [New in Electra:EIP6110]
+ if state.eth1_deposit_index == state.deposit_requests_start_index:
+ return state.eth1_data
+
+ period_start = voting_period_start_time(state)
+ # `eth1_chain` abstractly represents all blocks in the eth1 chain sorted by ascending block height
+ votes_to_consider = [
+ get_eth1_data(block)
+ for block in eth1_chain
+ if (
+ is_candidate_block(block, period_start)
+ # Ensure cannot move back to earlier deposit contract states
+ and get_eth1_data(block).deposit_count >= state.eth1_data.deposit_count
+ )
+ ]
+
+ # Valid votes already cast during this period
+ valid_votes = [vote for vote in state.eth1_data_votes if vote in votes_to_consider]
+
+ # Default vote on latest eth1 block data in the period range unless eth1 chain is not live
+ # Non-substantive casting for linter
+ state_eth1_data: Eth1Data = state.eth1_data
+ default_vote = (
+ votes_to_consider[len(votes_to_consider) - 1] if any(votes_to_consider) else state_eth1_data
+ )
+
+ return max(
+ valid_votes,
+ # Tiebreak by smallest distance
+ key=lambda v: (
+ valid_votes.count(v),
+ -valid_votes.index(v),
+ ),
+ default=default_vote,
+ )
+
+
+- name: get_execution_payload
+ sources: []
+ spec: |
+
+ def get_execution_payload(
+ payload_id: Optional[PayloadId], execution_engine: ExecutionEngine
+ ) -> ExecutionPayload:
+ if payload_id is None:
+ # Pre-merge, empty payload
+ return ExecutionPayload()
+ else:
+ return execution_engine.get_payload(payload_id).execution_payload
+
+
+- name: get_execution_requests
+ sources:
+ - 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 = []
+
+ request_types = [
+ DEPOSIT_REQUEST_TYPE,
+ WITHDRAWAL_REQUEST_TYPE,
+ CONSOLIDATION_REQUEST_TYPE,
+ ]
+
+ prev_request_type = None
+ for request in execution_requests_list:
+ request_type, request_data = request[0:1], request[1:]
+
+ # Check that the request type is valid
+ assert request_type in request_types
+ # Check that the request data is not empty
+ assert len(request_data) != 0
+ # Check that requests are in strictly ascending order
+ # Each successive type must be greater than the last with no duplicates
+ assert prev_request_type is None or prev_request_type < request_type
+ prev_request_type = request_type
+
+ if request_type == DEPOSIT_REQUEST_TYPE:
+ deposits = ssz_deserialize(
+ List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], request_data
+ )
+ elif request_type == WITHDRAWAL_REQUEST_TYPE:
+ withdrawals = ssz_deserialize(
+ List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], request_data
+ )
+ elif request_type == CONSOLIDATION_REQUEST_TYPE:
+ consolidations = ssz_deserialize(
+ List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], request_data
+ )
+
+ return ExecutionRequests(
+ deposits=deposits,
+ withdrawals=withdrawals,
+ consolidations=consolidations,
+ )
+
+
+- name: get_execution_requests_list
+ sources:
+ - file: proto/engine/v1/electra.go
+ search: func EncodeExecutionRequests(
+ spec: |
+
+ def get_execution_requests_list(execution_requests: ExecutionRequests) -> Sequence[bytes]:
+ requests = [
+ (DEPOSIT_REQUEST_TYPE, execution_requests.deposits),
+ (WITHDRAWAL_REQUEST_TYPE, execution_requests.withdrawals),
+ (CONSOLIDATION_REQUEST_TYPE, execution_requests.consolidations),
+ ]
+
+ return [
+ request_type + ssz_serialize(request_data)
+ for request_type, request_data in requests
+ if len(request_data) != 0
+ ]
+
+
+- name: get_expected_withdrawals#capella
+ sources:
+ - file: beacon-chain/state/state-native/getters_withdrawal.go
+ search: func (b *BeaconState) ExpectedWithdrawals(
+ spec: |
+
+ def get_expected_withdrawals(state: BeaconState) -> Sequence[Withdrawal]:
+ epoch = get_current_epoch(state)
+ withdrawal_index = state.next_withdrawal_index
+ validator_index = state.next_withdrawal_validator_index
+ withdrawals: List[Withdrawal] = []
+ bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
+ for _ in range(bound):
+ validator = state.validators[validator_index]
+ balance = state.balances[validator_index]
+ if is_fully_withdrawable_validator(validator, balance, epoch):
+ withdrawals.append(
+ Withdrawal(
+ index=withdrawal_index,
+ validator_index=validator_index,
+ address=ExecutionAddress(validator.withdrawal_credentials[12:]),
+ amount=balance,
+ )
+ )
+ withdrawal_index += WithdrawalIndex(1)
+ elif is_partially_withdrawable_validator(validator, balance):
+ withdrawals.append(
+ Withdrawal(
+ index=withdrawal_index,
+ validator_index=validator_index,
+ address=ExecutionAddress(validator.withdrawal_credentials[12:]),
+ amount=balance - MAX_EFFECTIVE_BALANCE,
+ )
+ )
+ withdrawal_index += WithdrawalIndex(1)
+ if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
+ break
+ validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
+ return withdrawals
+
+
+- name: get_expected_withdrawals#electra
+ sources:
+ - file: beacon-chain/state/state-native/getters_withdrawal.go
+ search: func (b *BeaconState) ExpectedWithdrawals(
+ spec: |
+
+ def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
+ epoch = get_current_epoch(state)
+ withdrawal_index = state.next_withdrawal_index
+ validator_index = state.next_withdrawal_validator_index
+ withdrawals: List[Withdrawal] = []
+ processed_partial_withdrawals_count = 0
+
+ # [New in Electra:EIP7251]
+ # Consume pending partial withdrawals
+ for withdrawal in state.pending_partial_withdrawals:
+ if (
+ withdrawal.withdrawable_epoch > epoch
+ or len(withdrawals) == MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP
+ ):
+ break
+
+ validator = state.validators[withdrawal.validator_index]
+ has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
+ total_withdrawn = sum(
+ w.amount for w in withdrawals if w.validator_index == withdrawal.validator_index
+ )
+ balance = state.balances[withdrawal.validator_index] - total_withdrawn
+ has_excess_balance = balance > MIN_ACTIVATION_BALANCE
+ if (
+ validator.exit_epoch == FAR_FUTURE_EPOCH
+ and has_sufficient_effective_balance
+ and has_excess_balance
+ ):
+ withdrawable_balance = min(balance - MIN_ACTIVATION_BALANCE, withdrawal.amount)
+ withdrawals.append(
+ Withdrawal(
+ index=withdrawal_index,
+ validator_index=withdrawal.validator_index,
+ address=ExecutionAddress(validator.withdrawal_credentials[12:]),
+ amount=withdrawable_balance,
+ )
+ )
+ withdrawal_index += WithdrawalIndex(1)
+
+ processed_partial_withdrawals_count += 1
+
+ # Sweep for remaining.
+ bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
+ for _ in range(bound):
+ validator = state.validators[validator_index]
+ # [Modified in Electra:EIP7251]
+ total_withdrawn = sum(w.amount for w in withdrawals if w.validator_index == validator_index)
+ balance = state.balances[validator_index] - total_withdrawn
+ if is_fully_withdrawable_validator(validator, balance, epoch):
+ withdrawals.append(
+ Withdrawal(
+ index=withdrawal_index,
+ validator_index=validator_index,
+ address=ExecutionAddress(validator.withdrawal_credentials[12:]),
+ amount=balance,
+ )
+ )
+ withdrawal_index += WithdrawalIndex(1)
+ elif is_partially_withdrawable_validator(validator, balance):
+ withdrawals.append(
+ Withdrawal(
+ index=withdrawal_index,
+ validator_index=validator_index,
+ address=ExecutionAddress(validator.withdrawal_credentials[12:]),
+ # [Modified in Electra:EIP7251]
+ amount=balance - get_max_effective_balance(validator),
+ )
+ )
+ withdrawal_index += WithdrawalIndex(1)
+ if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
+ break
+ validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
+ return withdrawals, processed_partial_withdrawals_count
+
+
+- name: get_filtered_block_tree
+ sources: []
+ spec: |
+
+ def get_filtered_block_tree(store: Store) -> Dict[Root, BeaconBlock]:
+ """
+ Retrieve a filtered block tree from ``store``, only returning branches
+ whose leaf state's justified/finalized info agrees with that in ``store``.
+ """
+ base = store.justified_checkpoint.root
+ blocks: Dict[Root, BeaconBlock] = {}
+ filter_block_tree(store, base, blocks)
+ return blocks
+
+
+- name: get_finality_delay
+ sources:
+ - file: beacon-chain/core/helpers/rewards_penalties.go
+ search: func FinalityDelay(
+ spec: |
+
+ def get_finality_delay(state: BeaconState) -> uint64:
+ return get_previous_epoch(state) - state.finalized_checkpoint.epoch
+
+
+- name: get_flag_index_deltas
+ sources:
+ - file: beacon-chain/core/altair/epoch_precompute.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_flag_index_deltas(
+ state: BeaconState, flag_index: int
+ ) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return the deltas for a given ``flag_index`` by scanning through the participation flags.
+ """
+ rewards = [Gwei(0)] * len(state.validators)
+ penalties = [Gwei(0)] * len(state.validators)
+ previous_epoch = get_previous_epoch(state)
+ unslashed_participating_indices = get_unslashed_participating_indices(
+ state, flag_index, previous_epoch
+ )
+ weight = PARTICIPATION_FLAG_WEIGHTS[flag_index]
+ unslashed_participating_balance = get_total_balance(state, unslashed_participating_indices)
+ unslashed_participating_increments = (
+ unslashed_participating_balance // EFFECTIVE_BALANCE_INCREMENT
+ )
+ active_increments = get_total_active_balance(state) // EFFECTIVE_BALANCE_INCREMENT
+ for index in get_eligible_validator_indices(state):
+ base_reward = get_base_reward(state, index)
+ if index in unslashed_participating_indices:
+ if not is_in_inactivity_leak(state):
+ reward_numerator = base_reward * weight * unslashed_participating_increments
+ rewards[index] += Gwei(reward_numerator // (active_increments * WEIGHT_DENOMINATOR))
+ elif flag_index != TIMELY_HEAD_FLAG_INDEX:
+ penalties[index] += Gwei(base_reward * weight // WEIGHT_DENOMINATOR)
+ return rewards, penalties
+
+
+- name: get_forkchoice_store
+ 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)
+ anchor_epoch = get_current_epoch(anchor_state)
+ justified_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
+ finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
+ proposer_boost_root = Root()
+ return Store(
+ time=uint64(anchor_state.genesis_time + SECONDS_PER_SLOT * anchor_state.slot),
+ genesis_time=anchor_state.genesis_time,
+ justified_checkpoint=justified_checkpoint,
+ finalized_checkpoint=finalized_checkpoint,
+ unrealized_justified_checkpoint=justified_checkpoint,
+ unrealized_finalized_checkpoint=finalized_checkpoint,
+ proposer_boost_root=proposer_boost_root,
+ equivocating_indices=set(),
+ blocks={anchor_root: copy(anchor_block)},
+ block_states={anchor_root: copy(anchor_state)},
+ checkpoint_states={justified_checkpoint: copy(anchor_state)},
+ unrealized_justifications={anchor_root: justified_checkpoint},
+ )
+
+
+- name: get_head
+ sources:
+ - file: beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go
+ search: func (f *ForkChoice) Head(
+ spec: |
+
+ def get_head(store: Store) -> Root:
+ # Get filtered block tree that only includes viable branches
+ blocks = get_filtered_block_tree(store)
+ # Execute the LMD-GHOST fork choice
+ head = store.justified_checkpoint.root
+ while True:
+ children = [root for root in blocks.keys() if blocks[root].parent_root == head]
+ if len(children) == 0:
+ return head
+ # Sort by latest attesting balance with ties broken lexicographically
+ # Ties broken by favoring block with lexicographically higher root
+ head = max(children, key=lambda root: (get_weight(store, root), root))
+
+
+- name: get_head_deltas
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_head_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return attester micro-rewards/penalties for head-vote for each validator.
+ """
+ matching_head_attestations = get_matching_head_attestations(state, get_previous_epoch(state))
+ return get_attestation_component_deltas(state, matching_head_attestations)
+
+
+- name: get_inactivity_penalty_deltas#phase0
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return inactivity reward/penalty deltas for each validator.
+ """
+ penalties = [Gwei(0) for _ in range(len(state.validators))]
+ if is_in_inactivity_leak(state):
+ matching_target_attestations = get_matching_target_attestations(
+ state, get_previous_epoch(state)
+ )
+ matching_target_attesting_indices = get_unslashed_attesting_indices(
+ state, matching_target_attestations
+ )
+ for index in get_eligible_validator_indices(state):
+ # If validator is performing optimally this cancels all rewards for a neutral balance
+ base_reward = get_base_reward(state, index)
+ penalties[index] += Gwei(
+ BASE_REWARDS_PER_EPOCH * base_reward - get_proposer_reward(state, index)
+ )
+ if index not in matching_target_attesting_indices:
+ effective_balance = state.validators[index].effective_balance
+ penalties[index] += Gwei(
+ effective_balance * get_finality_delay(state) // INACTIVITY_PENALTY_QUOTIENT
+ )
+
+ # No rewards associated with inactivity penalties
+ rewards = [Gwei(0) for _ in range(len(state.validators))]
+ return rewards, penalties
+
+
+- name: get_inactivity_penalty_deltas#altair
+ sources:
+ - file: beacon-chain/core/altair/epoch_precompute.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return the inactivity penalty deltas by considering timely target participation flags and inactivity scores.
+ """
+ rewards = [Gwei(0) for _ in range(len(state.validators))]
+ penalties = [Gwei(0) for _ in range(len(state.validators))]
+ previous_epoch = get_previous_epoch(state)
+ matching_target_indices = get_unslashed_participating_indices(
+ state, TIMELY_TARGET_FLAG_INDEX, previous_epoch
+ )
+ for index in get_eligible_validator_indices(state):
+ if index not in matching_target_indices:
+ penalty_numerator = (
+ state.validators[index].effective_balance * state.inactivity_scores[index]
+ )
+ penalty_denominator = INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR
+ penalties[index] += Gwei(penalty_numerator // penalty_denominator)
+ return rewards, penalties
+
+
+- name: get_inactivity_penalty_deltas#bellatrix
+ sources:
+ - file: beacon-chain/core/altair/epoch_precompute.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return the inactivity penalty deltas by considering timely target participation flags and inactivity scores.
+ """
+ rewards = [Gwei(0) for _ in range(len(state.validators))]
+ penalties = [Gwei(0) for _ in range(len(state.validators))]
+ previous_epoch = get_previous_epoch(state)
+ matching_target_indices = get_unslashed_participating_indices(
+ state, TIMELY_TARGET_FLAG_INDEX, previous_epoch
+ )
+ for index in get_eligible_validator_indices(state):
+ if index not in matching_target_indices:
+ penalty_numerator = (
+ state.validators[index].effective_balance * state.inactivity_scores[index]
+ )
+ # [Modified in Bellatrix]
+ penalty_denominator = INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
+ penalties[index] += Gwei(penalty_numerator // penalty_denominator)
+ return rewards, penalties
+
+
+- name: get_inclusion_delay_deltas
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_inclusion_delay_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return proposer and inclusion delay micro-rewards/penalties for each validator.
+ """
+ rewards = [Gwei(0) for _ in range(len(state.validators))]
+ matching_source_attestations = get_matching_source_attestations(
+ state, get_previous_epoch(state)
+ )
+ for index in get_unslashed_attesting_indices(state, matching_source_attestations):
+ attestation = min(
+ [a for a in matching_source_attestations if index in get_attesting_indices(state, a)],
+ key=lambda a: a.inclusion_delay,
+ )
+ rewards[attestation.proposer_index] += get_proposer_reward(state, index)
+ max_attester_reward = Gwei(
+ get_base_reward(state, index) - get_proposer_reward(state, index)
+ )
+ rewards[index] += Gwei(max_attester_reward // attestation.inclusion_delay)
+
+ # No penalties associated with inclusion delay
+ penalties = [Gwei(0) for _ in range(len(state.validators))]
+ return rewards, penalties
+
+
+- name: get_index_for_new_validator
+ sources: []
+ spec: |
+
+ def get_index_for_new_validator(state: BeaconState) -> ValidatorIndex:
+ return ValidatorIndex(len(state.validators))
+
+
+- name: get_indexed_attestation
+ sources:
+ - 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``.
+ """
+ attesting_indices = get_attesting_indices(state, attestation)
+
+ return IndexedAttestation(
+ attesting_indices=sorted(attesting_indices),
+ data=attestation.data,
+ signature=attestation.signature,
+ )
+
+
+- name: get_lc_execution_root#capella
+ sources: []
+ spec: |
+
+ def get_lc_execution_root(header: LightClientHeader) -> Root:
+ epoch = compute_epoch_at_slot(header.beacon.slot)
+
+ if epoch >= CAPELLA_FORK_EPOCH:
+ return hash_tree_root(header.execution)
+
+ return Root()
+
+
+- name: get_lc_execution_root#deneb
+ sources: []
+ spec: |
+
+ def get_lc_execution_root(header: LightClientHeader) -> Root:
+ epoch = compute_epoch_at_slot(header.beacon.slot)
+
+ # [New in Deneb]
+ if epoch >= DENEB_FORK_EPOCH:
+ return hash_tree_root(header.execution)
+
+ # [Modified in Deneb]
+ if epoch >= CAPELLA_FORK_EPOCH:
+ execution_header = capella.ExecutionPayloadHeader(
+ parent_hash=header.execution.parent_hash,
+ fee_recipient=header.execution.fee_recipient,
+ state_root=header.execution.state_root,
+ receipts_root=header.execution.receipts_root,
+ logs_bloom=header.execution.logs_bloom,
+ prev_randao=header.execution.prev_randao,
+ block_number=header.execution.block_number,
+ gas_limit=header.execution.gas_limit,
+ gas_used=header.execution.gas_used,
+ timestamp=header.execution.timestamp,
+ extra_data=header.execution.extra_data,
+ base_fee_per_gas=header.execution.base_fee_per_gas,
+ block_hash=header.execution.block_hash,
+ transactions_root=header.execution.transactions_root,
+ withdrawals_root=header.execution.withdrawals_root,
+ )
+ return hash_tree_root(execution_header)
+
+ return Root()
+
+
+- name: get_lc_execution_root#electra
+ sources: []
+ spec: |
+
+ def get_lc_execution_root(header: LightClientHeader) -> Root:
+ epoch = compute_epoch_at_slot(header.beacon.slot)
+
+ # [New in Electra]
+ if epoch >= ELECTRA_FORK_EPOCH:
+ return hash_tree_root(header.execution)
+
+ # [Modified in Electra]
+ if epoch >= DENEB_FORK_EPOCH:
+ execution_header = deneb.ExecutionPayloadHeader(
+ parent_hash=header.execution.parent_hash,
+ fee_recipient=header.execution.fee_recipient,
+ state_root=header.execution.state_root,
+ receipts_root=header.execution.receipts_root,
+ logs_bloom=header.execution.logs_bloom,
+ prev_randao=header.execution.prev_randao,
+ block_number=header.execution.block_number,
+ gas_limit=header.execution.gas_limit,
+ gas_used=header.execution.gas_used,
+ timestamp=header.execution.timestamp,
+ extra_data=header.execution.extra_data,
+ base_fee_per_gas=header.execution.base_fee_per_gas,
+ block_hash=header.execution.block_hash,
+ transactions_root=header.execution.transactions_root,
+ withdrawals_root=header.execution.withdrawals_root,
+ blob_gas_used=header.execution.blob_gas_used,
+ excess_blob_gas=header.execution.excess_blob_gas,
+ )
+ return hash_tree_root(execution_header)
+
+ if epoch >= CAPELLA_FORK_EPOCH:
+ execution_header = capella.ExecutionPayloadHeader(
+ parent_hash=header.execution.parent_hash,
+ fee_recipient=header.execution.fee_recipient,
+ state_root=header.execution.state_root,
+ receipts_root=header.execution.receipts_root,
+ logs_bloom=header.execution.logs_bloom,
+ prev_randao=header.execution.prev_randao,
+ block_number=header.execution.block_number,
+ gas_limit=header.execution.gas_limit,
+ gas_used=header.execution.gas_used,
+ timestamp=header.execution.timestamp,
+ extra_data=header.execution.extra_data,
+ base_fee_per_gas=header.execution.base_fee_per_gas,
+ block_hash=header.execution.block_hash,
+ transactions_root=header.execution.transactions_root,
+ withdrawals_root=header.execution.withdrawals_root,
+ )
+ return hash_tree_root(execution_header)
+
+ return Root()
+
+
+- name: get_matching_head_attestations
+ sources: []
+ spec: |
+
+ def get_matching_head_attestations(
+ state: BeaconState, epoch: Epoch
+ ) -> Sequence[PendingAttestation]:
+ return [
+ a
+ for a in get_matching_target_attestations(state, epoch)
+ if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot)
+ ]
+
+
+- name: get_matching_source_attestations
+ sources: []
+ spec: |
+
+ def get_matching_source_attestations(
+ state: BeaconState, epoch: Epoch
+ ) -> Sequence[PendingAttestation]:
+ assert epoch in (get_previous_epoch(state), get_current_epoch(state))
+ return (
+ state.current_epoch_attestations
+ if epoch == get_current_epoch(state)
+ else state.previous_epoch_attestations
+ )
+
+
+- name: get_matching_target_attestations
+ sources: []
+ spec: |
+
+ def get_matching_target_attestations(
+ state: BeaconState, epoch: Epoch
+ ) -> Sequence[PendingAttestation]:
+ return [
+ a
+ for a in get_matching_source_attestations(state, epoch)
+ if a.data.target.root == get_block_root(state, epoch)
+ ]
+
+
+- name: get_max_effective_balance
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ValidatorMaxEffectiveBalance(
+ spec: |
+
+ def get_max_effective_balance(validator: Validator) -> Gwei:
+ """
+ Get max effective balance for ``validator``.
+ """
+ if has_compounding_withdrawal_credential(validator):
+ return MAX_EFFECTIVE_BALANCE_ELECTRA
+ else:
+ return MIN_ACTIVATION_BALANCE
+
+
+- name: get_next_sync_committee
+ sources:
+ - file: beacon-chain/core/altair/sync_committee.go
+ search: func NextSyncCommittee(
+ spec: |
+
+ def get_next_sync_committee(state: BeaconState) -> SyncCommittee:
+ """
+ Return the next sync committee, with possible pubkey duplicates.
+ """
+ indices = get_next_sync_committee_indices(state)
+ pubkeys = [state.validators[index].pubkey for index in indices]
+ aggregate_pubkey = eth_aggregate_pubkeys(pubkeys)
+ return SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=aggregate_pubkey)
+
+
+- name: get_next_sync_committee_indices#altair
+ sources:
+ - 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.
+ """
+ epoch = Epoch(get_current_epoch(state) + 1)
+
+ MAX_RANDOM_BYTE = 2**8 - 1
+ active_validator_indices = get_active_validator_indices(state, epoch)
+ active_validator_count = uint64(len(active_validator_indices))
+ seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
+ i = 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
+ )
+ candidate_index = active_validator_indices[shuffled_index]
+ 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)
+ i += 1
+ return sync_committee_indices
+
+
+- name: get_next_sync_committee_indices#electra
+ sources:
+ - file: beacon-chain/core/altair/sync_committee.go
+ search: func NextSyncCommitteeIndices(
+ - 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.
+ """
+ epoch = Epoch(get_current_epoch(state) + 1)
+
+ # [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))
+ seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
+ 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
+ )
+ candidate_index = active_validator_indices[shuffled_index]
+ # [Modified in Electra]
+ random_bytes = hash(seed + uint_to_bytes(i // 16))
+ offset = i % 16 * 2
+ random_value = bytes_to_uint64(random_bytes[offset : offset + 2])
+ effective_balance = state.validators[candidate_index].effective_balance
+ # [Modified in Electra:EIP7251]
+ if effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value:
+ sync_committee_indices.append(candidate_index)
+ i += 1
+ return sync_committee_indices
+
+
+- name: get_pending_balance_to_withdraw
+ sources:
+ - file: beacon-chain/state/state-native/getters_validator.go
+ search: func (b *BeaconState) PendingBalanceToWithdraw(
+ spec: |
+
+ def get_pending_balance_to_withdraw(state: BeaconState, validator_index: ValidatorIndex) -> Gwei:
+ return sum(
+ withdrawal.amount
+ for withdrawal in state.pending_partial_withdrawals
+ if withdrawal.validator_index == validator_index
+ )
+
+
+- name: get_pow_block_at_terminal_total_difficulty
+ sources:
+ - file: beacon-chain/execution/engine_client.go
+ search: func (s *Service) GetTerminalBlockHash(
+ spec: |
+
+ def get_pow_block_at_terminal_total_difficulty(
+ pow_chain: Dict[Hash32, PowBlock],
+ ) -> Optional[PowBlock]:
+ # `pow_chain` abstractly represents all blocks in the PoW chain
+ for block in pow_chain.values():
+ block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
+ if block_reached_ttd:
+ # If genesis block, no parent exists so reaching TTD alone qualifies as valid terminal block
+ if block.parent_hash == Hash32():
+ return block
+ parent = pow_chain[block.parent_hash]
+ parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
+ if not parent_reached_ttd:
+ return block
+
+ return None
+
+
+- name: get_previous_epoch
+ sources:
+ - file: beacon-chain/core/time/slot_epoch.go
+ search: func PrevEpoch(
+ spec: |
+
+ def get_previous_epoch(state: BeaconState) -> Epoch:
+ """`
+ Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
+ """
+ current_epoch = get_current_epoch(state)
+ return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1)
+
+
+- name: get_proposer_head
+ sources: []
+ spec: |
+
+ def get_proposer_head(store: Store, head_root: Root, slot: Slot) -> Root:
+ head_block = store.blocks[head_root]
+ parent_root = head_block.parent_root
+ parent_block = store.blocks[parent_root]
+
+ # Only re-org the head block if it arrived later than the attestation deadline.
+ head_late = is_head_late(store, head_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_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_root # ensure boost has worn off
+ head_weak = is_head_weak(store, head_root)
+
+ # Check that the missing votes are assigned to the parent and not being hoarded.
+ parent_strong = is_parent_strong(store, parent_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 block.
+ return parent_root
+ else:
+ return head_root
+
+
+- name: get_proposer_reward
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func ProposersDelta(
+ spec: |
+
+ def get_proposer_reward(state: BeaconState, attesting_index: ValidatorIndex) -> Gwei:
+ return Gwei(get_base_reward(state, attesting_index) // PROPOSER_REWARD_QUOTIENT)
+
+
+- name: get_proposer_score
+ sources: []
+ spec: |
+
+ def get_proposer_score(store: Store) -> Gwei:
+ justified_checkpoint_state = store.checkpoint_states[store.justified_checkpoint]
+ committee_weight = get_total_active_balance(justified_checkpoint_state) // SLOTS_PER_EPOCH
+ return (committee_weight * PROPOSER_SCORE_BOOST) // 100
+
+
+- name: get_randao_mix
+ sources:
+ - file: beacon-chain/core/helpers/randao.go
+ search: func RandaoMix(
+ spec: |
+
+ def get_randao_mix(state: BeaconState, epoch: Epoch) -> Bytes32:
+ """
+ Return the randao mix at a recent ``epoch``.
+ """
+ return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
+
+
+- name: get_safety_threshold
+ sources: []
+ spec: |
+
+ def get_safety_threshold(store: LightClientStore) -> uint64:
+ return (
+ max(
+ store.previous_max_active_participants,
+ store.current_max_active_participants,
+ )
+ // 2
+ )
+
+
+- name: get_seed
+ sources:
+ - file: beacon-chain/core/helpers/randao.go
+ search: func Seed(
+ spec: |
+
+ def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Bytes32:
+ """
+ Return the seed at ``epoch``.
+ """
+ mix = get_randao_mix(
+ state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1)
+ ) # Avoid underflow
+ return hash(domain_type + uint_to_bytes(epoch) + mix)
+
+
+- name: get_slot_signature
+ sources: []
+ spec: |
+
+ def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature:
+ domain = get_domain(state, DOMAIN_SELECTION_PROOF, compute_epoch_at_slot(slot))
+ signing_root = compute_signing_root(slot, domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_slots_since_genesis
+ sources:
+ - file: time/slots/slottime.go
+ search: func CurrentSlot(
+ spec: |
+
+ def get_slots_since_genesis(store: Store) -> int:
+ return (store.time - store.genesis_time) // SECONDS_PER_SLOT
+
+
+- name: get_source_deltas
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_source_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return attester micro-rewards/penalties for source-vote for each validator.
+ """
+ matching_source_attestations = get_matching_source_attestations(
+ state, get_previous_epoch(state)
+ )
+ return get_attestation_component_deltas(state, matching_source_attestations)
+
+
+- name: get_subtree_index
+ sources: []
+ spec: |
+
+ def get_subtree_index(generalized_index: GeneralizedIndex) -> uint64:
+ return uint64(generalized_index % 2 ** (floorlog2(generalized_index)))
+
+
+- name: get_sync_committee_message
+ sources: []
+ spec: |
+
+ def get_sync_committee_message(
+ state: BeaconState, block_root: Root, validator_index: ValidatorIndex, privkey: int
+ ) -> SyncCommitteeMessage:
+ epoch = get_current_epoch(state)
+ domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, epoch)
+ signing_root = compute_signing_root(block_root, domain)
+ signature = bls.Sign(privkey, signing_root)
+
+ return SyncCommitteeMessage(
+ slot=state.slot,
+ beacon_block_root=block_root,
+ validator_index=validator_index,
+ signature=signature,
+ )
+
+
+- name: get_sync_committee_selection_proof
+ sources: []
+ spec: |
+
+ def get_sync_committee_selection_proof(
+ 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(
+ slot=slot,
+ subcommittee_index=subcommittee_index,
+ )
+ signing_root = compute_signing_root(signing_data, domain)
+ return bls.Sign(privkey, signing_root)
+
+
+- name: get_sync_subcommittee_pubkeys
+ sources:
+ - file: beacon-chain/core/altair/sync_committee.go
+ search: func SyncSubCommitteePubkeys(
+ spec: |
+
+ def get_sync_subcommittee_pubkeys(
+ 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
+ next_slot_epoch = compute_epoch_at_slot(Slot(state.slot + 1))
+ if compute_sync_committee_period(get_current_epoch(state)) == compute_sync_committee_period(
+ next_slot_epoch
+ ):
+ sync_committee = state.current_sync_committee
+ else:
+ sync_committee = state.next_sync_committee
+
+ # Return pubkeys for the subcommittee index
+ sync_subcommittee_size = SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT
+ i = subcommittee_index * sync_subcommittee_size
+ return sync_committee.pubkeys[i : i + sync_subcommittee_size]
+
+
+- name: get_target_deltas
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func AttestationsDelta(
+ spec: |
+
+ def get_target_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
+ """
+ Return attester micro-rewards/penalties for target-vote for each validator.
+ """
+ matching_target_attestations = get_matching_target_attestations(
+ state, get_previous_epoch(state)
+ )
+ return get_attestation_component_deltas(state, matching_target_attestations)
+
+
+- name: get_terminal_pow_block
+ sources:
+ - file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer_execution_payload.go
+ search: func (vs *Server) getTerminalBlockHashIfExists(
+ spec: |
+
+ def get_terminal_pow_block(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
+ if TERMINAL_BLOCK_HASH != Hash32():
+ # Terminal block hash override takes precedence over terminal total difficulty
+ if TERMINAL_BLOCK_HASH in pow_chain:
+ return pow_chain[TERMINAL_BLOCK_HASH]
+ else:
+ return None
+
+ return get_pow_block_at_terminal_total_difficulty(pow_chain)
+
+
+- name: get_total_active_balance
+ sources:
+ - file: beacon-chain/core/helpers/rewards_penalties.go
+ search: func TotalActiveBalance(
+ spec: |
+
+ def get_total_active_balance(state: BeaconState) -> Gwei:
+ """
+ Return the combined effective balance of the active validators.
+ Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
+ """
+ return get_total_balance(
+ state, set(get_active_validator_indices(state, get_current_epoch(state)))
+ )
+
+
+- name: get_total_balance
+ sources:
+ - 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.
+ """
+ return Gwei(
+ max(
+ EFFECTIVE_BALANCE_INCREMENT,
+ sum([state.validators[index].effective_balance for index in indices]),
+ )
+ )
+
+
+- name: get_unslashed_attesting_indices
+ sources: []
+ spec: |
+
+ def get_unslashed_attesting_indices(
+ state: BeaconState, attestations: Sequence[PendingAttestation]
+ ) -> Set[ValidatorIndex]:
+ output: Set[ValidatorIndex] = set()
+ for a in attestations:
+ output = output.union(get_attesting_indices(state, a))
+ return set(filter(lambda index: not state.validators[index].slashed, output))
+
+
+- name: get_unslashed_participating_indices
+ sources: []
+ spec: |
+
+ def get_unslashed_participating_indices(
+ state: BeaconState, flag_index: int, epoch: Epoch
+ ) -> Set[ValidatorIndex]:
+ """
+ Return the set of validator indices that are both active and unslashed for the given ``flag_index`` and ``epoch``.
+ """
+ assert epoch in (get_previous_epoch(state), get_current_epoch(state))
+ if epoch == get_current_epoch(state):
+ epoch_participation = state.current_epoch_participation
+ else:
+ epoch_participation = state.previous_epoch_participation
+ active_validator_indices = get_active_validator_indices(state, epoch)
+ participating_indices = [
+ i for i in active_validator_indices if has_flag(epoch_participation[i], flag_index)
+ ]
+ return set(filter(lambda index: not state.validators[index].slashed, participating_indices))
+
+
+- name: get_validator_activation_churn_limit
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ValidatorActivationChurnLimitDeneb(
+ spec: |
+
+ def get_validator_activation_churn_limit(state: BeaconState) -> uint64:
+ """
+ Return the validator activation churn limit for the current epoch.
+ """
+ return min(MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, get_validator_churn_limit(state))
+
+
+- name: get_validator_churn_limit
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func ValidatorExitChurnLimit(
+ spec: |
+
+ 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
+ )
+
+
+- name: get_validator_from_deposit#phase0
+ sources:
+ - file: beacon-chain/core/altair/deposit.go
+ search: func GetValidatorFromDeposit(
+ spec: |
+
+ def get_validator_from_deposit(
+ pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64
+ ) -> Validator:
+ effective_balance = min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
+
+ return Validator(
+ pubkey=pubkey,
+ withdrawal_credentials=withdrawal_credentials,
+ effective_balance=effective_balance,
+ slashed=False,
+ activation_eligibility_epoch=FAR_FUTURE_EPOCH,
+ activation_epoch=FAR_FUTURE_EPOCH,
+ exit_epoch=FAR_FUTURE_EPOCH,
+ withdrawable_epoch=FAR_FUTURE_EPOCH,
+ )
+
+
+- name: get_validator_from_deposit#electra
+ sources:
+ - file: beacon-chain/core/electra/deposits.go
+ search: func GetValidatorFromDeposit(
+ spec: |
+
+ def get_validator_from_deposit(
+ pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64
+ ) -> Validator:
+ validator = Validator(
+ pubkey=pubkey,
+ withdrawal_credentials=withdrawal_credentials,
+ effective_balance=Gwei(0),
+ slashed=False,
+ activation_eligibility_epoch=FAR_FUTURE_EPOCH,
+ activation_epoch=FAR_FUTURE_EPOCH,
+ exit_epoch=FAR_FUTURE_EPOCH,
+ withdrawable_epoch=FAR_FUTURE_EPOCH,
+ )
+
+ # [Modified in Electra:EIP7251]
+ max_effective_balance = get_max_effective_balance(validator)
+ validator.effective_balance = min(
+ amount - amount % EFFECTIVE_BALANCE_INCREMENT, max_effective_balance
+ )
+
+ return validator
+
+
+- name: get_validators_custody_requirement
+ sources:
+ - file: beacon-chain/core/peerdas/validator.go
+ search: func ValidatorsCustodyRequirement(
+ spec: |
+
+ def get_validators_custody_requirement(
+ state: BeaconState, validator_indices: Sequence[ValidatorIndex]
+ ) -> uint64:
+ total_node_balance = sum(
+ state.validators[index].effective_balance for index in validator_indices
+ )
+ count = total_node_balance // BALANCE_PER_ADDITIONAL_CUSTODY_GROUP
+ return min(max(count, VALIDATOR_CUSTODY_REQUIREMENT), NUMBER_OF_CUSTODY_GROUPS)
+
+
+- name: get_voting_source
+ sources: []
+ spec: |
+
+ def get_voting_source(store: Store, block_root: Root) -> Checkpoint:
+ """
+ Compute the voting source checkpoint in event that block with root ``block_root`` is the head block
+ """
+ block = store.blocks[block_root]
+ current_epoch = get_current_store_epoch(store)
+ block_epoch = compute_epoch_at_slot(block.slot)
+ if current_epoch > block_epoch:
+ # The block is from a prior epoch, the voting source will be pulled-up
+ return store.unrealized_justifications[block_root]
+ else:
+ # The block is not from a prior epoch, therefore the voting source is not pulled up
+ head_state = store.block_states[block_root]
+ return head_state.current_justified_checkpoint
+
+
+- name: get_weight
+ sources:
+ - file: beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go
+ search: func (f *ForkChoice) Weight(
+ spec: |
+
+ def get_weight(store: Store, root: Root) -> Gwei:
+ state = store.checkpoint_states[store.justified_checkpoint]
+ unslashed_and_active_indices = [
+ i
+ for i in get_active_validator_indices(state, get_current_epoch(state))
+ if not state.validators[i].slashed
+ ]
+ attestation_score = Gwei(
+ sum(
+ state.validators[i].effective_balance
+ for i in unslashed_and_active_indices
+ if (
+ i in store.latest_messages
+ and i not in store.equivocating_indices
+ and get_ancestor(store, store.latest_messages[i].root, store.blocks[root].slot)
+ == root
+ )
+ )
+ )
+ if store.proposer_boost_root == Root():
+ # Return only attestation score if ``proposer_boost_root`` is not set
+ return attestation_score
+
+ # Calculate proposer score if ``proposer_boost_root`` is set
+ proposer_score = Gwei(0)
+ # Boost is applied if ``root`` is an ancestor of ``proposer_boost_root``
+ if get_ancestor(store, store.proposer_boost_root, store.blocks[root].slot) == root:
+ proposer_score = get_proposer_score(store)
+ return attestation_score + proposer_score
+
+
+- name: has_compounding_withdrawal_credential
+ sources:
+ - file: beacon-chain/state/state-native/readonly_validator.go
+ search: func (v readOnlyValidator) HasCompoundingWithdrawalCredentials(
+ spec: |
+
+ def has_compounding_withdrawal_credential(validator: Validator) -> bool:
+ """
+ Check if ``validator`` has an 0x02 prefixed "compounding" withdrawal credential.
+ """
+ return is_compounding_withdrawal_credential(validator.withdrawal_credentials)
+
+
+- name: has_eth1_withdrawal_credential
+ sources:
+ - file: beacon-chain/state/state-native/readonly_validator.go
+ search: func (v readOnlyValidator) HasETH1WithdrawalCredentials(
+ spec: |
+
+ def has_eth1_withdrawal_credential(validator: Validator) -> bool:
+ """
+ Check if ``validator`` has an 0x01 prefixed "eth1" withdrawal credential.
+ """
+ return validator.withdrawal_credentials[:1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX
+
+
+- name: has_execution_withdrawal_credential
+ sources:
+ - file: beacon-chain/state/state-native/readonly_validator.go
+ search: func (v readOnlyValidator) HasExecutionWithdrawalCredentials(
+ spec: |
+
+ def has_execution_withdrawal_credential(validator: Validator) -> bool:
+ """
+ Check if ``validator`` has a 0x01 or 0x02 prefixed withdrawal credential.
+ """
+ return (
+ has_eth1_withdrawal_credential(validator) # 0x01
+ or has_compounding_withdrawal_credential(validator) # 0x02
+ )
+
+
+- name: has_flag
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func HasValidatorFlag(
+ spec: |
+
+ def has_flag(flags: ParticipationFlags, flag_index: int) -> bool:
+ """
+ Return whether ``flags`` has ``flag_index`` set.
+ """
+ flag = ParticipationFlags(2**flag_index)
+ return flags & flag == flag
+
+
+- name: increase_balance
+ sources:
+ - file: beacon-chain/core/helpers/rewards_penalties.go
+ search: func IncreaseBalance(
+ spec: |
+
+ def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
+ """
+ Increase the validator balance at index ``index`` by ``delta``.
+ """
+ state.balances[index] += delta
+
+
+- name: initialize_beacon_state_from_eth1
+ sources:
+ - 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]
+ ) -> BeaconState:
+ fork = Fork(
+ previous_version=GENESIS_FORK_VERSION,
+ current_version=GENESIS_FORK_VERSION,
+ epoch=GENESIS_EPOCH,
+ )
+ state = BeaconState(
+ genesis_time=eth1_timestamp + GENESIS_DELAY,
+ fork=fork,
+ eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
+ latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
+ randao_mixes=[eth1_block_hash]
+ * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
+ )
+
+ # Process deposits
+ leaves = list(map(lambda deposit: deposit.data, deposits))
+ for index, deposit in enumerate(deposits):
+ deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[: index + 1])
+ state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
+ process_deposit(state, deposit)
+
+ # Process activations
+ for index, validator in enumerate(state.validators):
+ balance = state.balances[index]
+ validator.effective_balance = min(
+ balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE
+ )
+ if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
+ validator.activation_eligibility_epoch = GENESIS_EPOCH
+ validator.activation_epoch = GENESIS_EPOCH
+
+ # Set genesis validators root for domain separation and chain versioning
+ state.genesis_validators_root = hash_tree_root(state.validators)
+
+ return state
+
+
+- name: initialize_light_client_store
+ sources:
+ - file: beacon-chain/core/light-client/store.go
+ search: func NewLightClientStore(
+ spec: |
+
+ def initialize_light_client_store(
+ trusted_block_root: Root, bootstrap: LightClientBootstrap
+ ) -> LightClientStore:
+ assert is_valid_light_client_header(bootstrap.header)
+ assert hash_tree_root(bootstrap.header.beacon) == trusted_block_root
+
+ assert is_valid_normalized_merkle_branch(
+ leaf=hash_tree_root(bootstrap.current_sync_committee),
+ branch=bootstrap.current_sync_committee_branch,
+ gindex=current_sync_committee_gindex_at_slot(bootstrap.header.beacon.slot),
+ root=bootstrap.header.beacon.state_root,
+ )
+
+ return LightClientStore(
+ finalized_header=bootstrap.header,
+ current_sync_committee=bootstrap.current_sync_committee,
+ next_sync_committee=SyncCommittee(),
+ best_valid_update=None,
+ optimistic_header=bootstrap.header,
+ previous_max_active_participants=0,
+ current_max_active_participants=0,
+ )
+
+
+- name: initialize_proposer_lookahead
+ sources:
+ - 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]:
+ """
+ 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 = []
+ for i in range(MIN_SEED_LOOKAHEAD + 1):
+ lookahead.extend(get_beacon_proposer_indices(state, Epoch(current_epoch + i)))
+ return lookahead
+
+
+- name: initiate_validator_exit#phase0
+ sources:
+ - file: beacon-chain/core/validators/validator.go
+ search: func InitiateValidatorExit(
+ - file: beacon-chain/core/validators/validator.go
+ search: if s.Version() < version.Electra {
+ spec: |
+
+ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
+ """
+ Initiate the exit of the validator with index ``index``.
+ """
+ # Return if validator already initiated exit
+ validator = state.validators[index]
+ if validator.exit_epoch != FAR_FUTURE_EPOCH:
+ return
+
+ # Compute exit queue epoch
+ exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
+ exit_queue_epoch = max(exit_epochs + [compute_activation_exit_epoch(get_current_epoch(state))])
+ exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch])
+ if exit_queue_churn >= get_validator_churn_limit(state):
+ exit_queue_epoch += Epoch(1)
+
+ # Set validator exit epoch and withdrawable epoch
+ validator.exit_epoch = exit_queue_epoch
+ validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
+
+
+- name: initiate_validator_exit#electra
+ sources:
+ - file: beacon-chain/core/validators/validator.go
+ search: func InitiateValidatorExit(
+ spec: |
+
+ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
+ """
+ Initiate the exit of the validator with index ``index``.
+ """
+ # Return if validator already initiated exit
+ validator = state.validators[index]
+ if validator.exit_epoch != FAR_FUTURE_EPOCH:
+ return
+
+ # Compute exit queue epoch [Modified in Electra:EIP7251]
+ exit_queue_epoch = compute_exit_epoch_and_update_churn(state, validator.effective_balance)
+
+ # Set validator exit epoch and withdrawable epoch
+ validator.exit_epoch = exit_queue_epoch
+ validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
+
+
+- name: integer_squareroot
+ sources:
+ - file: math/math_helper.go
+ search: func IntegerSquareRoot(
+ spec: |
+
+ def integer_squareroot(n: uint64) -> uint64:
+ """
+ Return the largest integer ``x`` such that ``x**2 <= n``.
+ """
+ if n == UINT64_MAX:
+ return UINT64_MAX_SQRT
+ x = n
+ y = (x + 1) // 2
+ while y < x:
+ x = y
+ y = (x + n // x) // 2
+ return x
+
+
+- name: is_active_validator
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsActiveValidator(
+ spec: |
+
+ def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
+ """
+ Check if ``validator`` is active.
+ """
+ return validator.activation_epoch <= epoch < validator.exit_epoch
+
+
+- name: is_aggregator
+ sources:
+ - file: beacon-chain/core/helpers/attestation.go
+ search: func IsAggregator(
+ spec: |
+
+ def is_aggregator(
+ state: BeaconState, slot: Slot, index: CommitteeIndex, slot_signature: BLSSignature
+ ) -> bool:
+ committee = get_beacon_committee(state, slot, index)
+ modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE)
+ return bytes_to_uint64(hash(slot_signature)[0:8]) % modulo == 0
+
+
+- name: is_assigned_to_sync_committee
+ sources: []
+ spec: |
+
+ def is_assigned_to_sync_committee(
+ state: BeaconState, epoch: Epoch, validator_index: ValidatorIndex
+ ) -> bool:
+ sync_committee_period = compute_sync_committee_period(epoch)
+ current_epoch = get_current_epoch(state)
+ current_sync_committee_period = compute_sync_committee_period(current_epoch)
+ next_sync_committee_period = current_sync_committee_period + 1
+ assert sync_committee_period in (current_sync_committee_period, next_sync_committee_period)
+
+ pubkey = state.validators[validator_index].pubkey
+ if sync_committee_period == current_sync_committee_period:
+ return pubkey in state.current_sync_committee.pubkeys
+ else: # sync_committee_period == next_sync_committee_period
+ return pubkey in state.next_sync_committee.pubkeys
+
+
+- name: is_better_update
+ sources:
+ - file: beacon-chain/core/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_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:
+ return new_has_supermajority
+ if not new_has_supermajority and new_num_active_participants != old_num_active_participants:
+ return new_num_active_participants > old_num_active_participants
+
+ # Compare presence of relevant sync committee
+ new_has_relevant_sync_committee = is_sync_committee_update(new_update) and (
+ compute_sync_committee_period_at_slot(new_update.attested_header.beacon.slot)
+ == compute_sync_committee_period_at_slot(new_update.signature_slot)
+ )
+ old_has_relevant_sync_committee = is_sync_committee_update(old_update) and (
+ compute_sync_committee_period_at_slot(old_update.attested_header.beacon.slot)
+ == compute_sync_committee_period_at_slot(old_update.signature_slot)
+ )
+ if new_has_relevant_sync_committee != old_has_relevant_sync_committee:
+ return new_has_relevant_sync_committee
+
+ # Compare indication of any finality
+ new_has_finality = is_finality_update(new_update)
+ old_has_finality = is_finality_update(old_update)
+ if new_has_finality != old_has_finality:
+ return new_has_finality
+
+ # Compare sync committee finality
+ if new_has_finality:
+ new_has_sync_committee_finality = compute_sync_committee_period_at_slot(
+ new_update.finalized_header.beacon.slot
+ ) == compute_sync_committee_period_at_slot(new_update.attested_header.beacon.slot)
+ old_has_sync_committee_finality = compute_sync_committee_period_at_slot(
+ old_update.finalized_header.beacon.slot
+ ) == compute_sync_committee_period_at_slot(old_update.attested_header.beacon.slot)
+ if new_has_sync_committee_finality != old_has_sync_committee_finality:
+ return new_has_sync_committee_finality
+
+ # Tiebreaker 1: Sync committee participation beyond supermajority
+ if new_num_active_participants != old_num_active_participants:
+ return new_num_active_participants > old_num_active_participants
+
+ # Tiebreaker 2: Prefer older data (fewer changes to best)
+ if new_update.attested_header.beacon.slot != old_update.attested_header.beacon.slot:
+ return new_update.attested_header.beacon.slot < old_update.attested_header.beacon.slot
+
+ # Tiebreaker 3: Prefer updates with earlier signature slots
+ return new_update.signature_slot < old_update.signature_slot
+
+
+- name: is_candidate_block
+ sources: []
+ spec: |
+
+ 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
+ )
+
+
+- name: is_compounding_withdrawal_credential
+ sources: []
+ spec: |
+
+ def is_compounding_withdrawal_credential(withdrawal_credentials: Bytes32) -> bool:
+ return withdrawal_credentials[:1] == COMPOUNDING_WITHDRAWAL_PREFIX
+
+
+- name: is_data_available#deneb
+ sources:
+ - file: beacon-chain/blockchain/process_block.go
+ search: func (s *Service) isDataAvailable(
+ - 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:
+ # `retrieve_blobs_and_proofs` is implementation and context dependent
+ # It returns all the blobs for the given block root, and raises an exception if not available
+ # Note: the p2p network does not guarantee sidecar retrieval outside of
+ # `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)
+
+
+- name: is_data_available#fulu
+ sources:
+ - file: beacon-chain/blockchain/process_block.go
+ search: func (s *Service) isDataAvailable(
+ - file: beacon-chain/blockchain/process_block.go
+ search: func (s *Service) areDataColumnsAvailable(
+ spec: |
+
+ def is_data_available(beacon_block_root: Root) -> bool:
+ # `retrieve_column_sidecars` is implementation and context dependent, replacing
+ # `retrieve_blobs_and_proofs`. For the given block root, it returns all column
+ # sidecars to sample, or raises an exception if they are not available.
+ # The p2p network does not guarantee sidecar retrieval outside of
+ # `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` epochs.
+ column_sidecars = retrieve_column_sidecars(beacon_block_root)
+ return all(
+ verify_data_column_sidecar(column_sidecar)
+ and verify_data_column_sidecar_kzg_proofs(column_sidecar)
+ for column_sidecar in column_sidecars
+ )
+
+
+- name: is_eligible_for_activation
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsEligibleForActivation(
+ spec: |
+
+ def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool:
+ """
+ Check if ``validator`` is eligible for activation.
+ """
+ return (
+ # Placement in queue is finalized
+ validator.activation_eligibility_epoch <= state.finalized_checkpoint.epoch
+ # Has not yet been activated
+ and validator.activation_epoch == FAR_FUTURE_EPOCH
+ )
+
+
+- name: is_eligible_for_activation_queue#phase0
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsEligibleForActivationQueue(
+ spec: |
+
+ def is_eligible_for_activation_queue(validator: Validator) -> bool:
+ """
+ Check if ``validator`` is eligible to be placed into the activation queue.
+ """
+ return (
+ validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
+ and validator.effective_balance == MAX_EFFECTIVE_BALANCE
+ )
+
+
+- name: is_eligible_for_activation_queue#electra
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsEligibleForActivationQueue(
+ spec: |
+
+ def is_eligible_for_activation_queue(validator: Validator) -> bool:
+ """
+ Check if ``validator`` is eligible to be placed into the activation queue.
+ """
+ return (
+ validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
+ # [Modified in Electra:EIP7251]
+ and validator.effective_balance >= MIN_ACTIVATION_BALANCE
+ )
+
+
+- name: is_execution_block
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func IsExecutionBlock(
+ spec: |
+
+ def is_execution_block(block: BeaconBlock) -> bool:
+ return block.body.execution_payload != ExecutionPayload()
+
+
+- name: is_execution_enabled
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func IsExecutionEnabled(
+ spec: |
+
+ def is_execution_enabled(state: BeaconState, body: BeaconBlockBody) -> bool:
+ return is_merge_transition_block(state, body) or is_merge_transition_complete(state)
+
+
+- name: is_ffg_competitive
+ sources: []
+ spec: |
+
+ def is_ffg_competitive(store: Store, head_root: Root, parent_root: Root) -> bool:
+ return (
+ store.unrealized_justifications[head_root] == store.unrealized_justifications[parent_root]
+ )
+
+
+- name: is_finality_update
+ sources: []
+ spec: |
+
+ def is_finality_update(update: LightClientUpdate) -> bool:
+ return update.finality_branch != FinalityBranch()
+
+
+- name: is_finalization_ok
+ sources: []
+ spec: |
+
+ def is_finalization_ok(store: Store, slot: Slot) -> bool:
+ epochs_since_finalization = compute_epoch_at_slot(slot) - store.finalized_checkpoint.epoch
+ return epochs_since_finalization <= REORG_MAX_EPOCHS_SINCE_FINALIZATION
+
+
+- name: is_fully_withdrawable_validator#capella
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsFullyWithdrawableValidator(
+ spec: |
+
+ def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch: Epoch) -> bool:
+ """
+ Check if ``validator`` is fully withdrawable.
+ """
+ return (
+ has_eth1_withdrawal_credential(validator)
+ and validator.withdrawable_epoch <= epoch
+ and balance > 0
+ )
+
+
+- name: is_fully_withdrawable_validator#electra
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsFullyWithdrawableValidator(
+ - file: beacon-chain/core/helpers/validators.go
+ search: if fork >= version.Electra {
+ spec: |
+
+ def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch: Epoch) -> bool:
+ """
+ Check if ``validator`` is fully withdrawable.
+ """
+ return (
+ # [Modified in Electra:EIP7251]
+ has_execution_withdrawal_credential(validator)
+ and validator.withdrawable_epoch <= epoch
+ and balance > 0
+ )
+
+
+- name: is_head_late
+ sources: []
+ spec: |
+
+ def is_head_late(store: Store, head_root: Root) -> bool:
+ return not store.block_timeliness[head_root]
+
+
+- name: is_head_weak
+ sources: []
+ spec: |
+
+ def is_head_weak(store: Store, head_root: Root) -> bool:
+ justified_state = store.checkpoint_states[store.justified_checkpoint]
+ reorg_threshold = calculate_committee_fraction(justified_state, REORG_HEAD_WEIGHT_THRESHOLD)
+ head_weight = get_weight(store, head_root)
+ return head_weight < reorg_threshold
+
+
+- name: is_in_inactivity_leak
+ sources:
+ - file: beacon-chain/core/helpers/rewards_penalties.go
+ search: func IsInInactivityLeak(
+ spec: |
+
+ def is_in_inactivity_leak(state: BeaconState) -> bool:
+ return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
+
+
+- name: is_merge_transition_block
+ sources: []
+ spec: |
+
+ def is_merge_transition_block(state: BeaconState, body: BeaconBlockBody) -> bool:
+ return not is_merge_transition_complete(state) and body.execution_payload != ExecutionPayload()
+
+
+- name: is_merge_transition_complete
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func IsMergeTransitionComplete(
+ spec: |
+
+ def is_merge_transition_complete(state: BeaconState) -> bool:
+ return state.latest_execution_payload_header != ExecutionPayloadHeader()
+
+
+- name: is_next_sync_committee_known
+ sources: []
+ spec: |
+
+ def is_next_sync_committee_known(store: LightClientStore) -> bool:
+ return store.next_sync_committee != SyncCommittee()
+
+
+- name: is_optimistic
+ sources:
+ - file: beacon-chain/blockchain/chain_info.go
+ search: func (s *Service) IsOptimistic(
+ spec: |
+
+ def is_optimistic(opt_store: OptimisticStore, block: BeaconBlock) -> bool:
+ return hash_tree_root(block) in opt_store.optimistic_roots
+
+
+- name: is_optimistic_candidate_block
+ sources: []
+ spec: |
+
+ def is_optimistic_candidate_block(
+ opt_store: OptimisticStore, current_slot: Slot, block: BeaconBlock
+ ) -> bool:
+ if is_execution_block(opt_store.blocks[block.parent_root]):
+ return True
+
+ if block.slot + SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY <= current_slot:
+ return True
+
+ return False
+
+
+- name: is_parent_strong
+ sources: []
+ spec: |
+
+ def is_parent_strong(store: Store, parent_root: Root) -> bool:
+ justified_state = store.checkpoint_states[store.justified_checkpoint]
+ parent_threshold = calculate_committee_fraction(justified_state, REORG_PARENT_WEIGHT_THRESHOLD)
+ parent_weight = get_weight(store, parent_root)
+ return parent_weight > parent_threshold
+
+
+- name: is_partially_withdrawable_validator#capella
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsPartiallyWithdrawableValidator(
+ - file: beacon-chain/core/helpers/validators.go
+ search: func isPartiallyWithdrawableValidatorCapella(
+ spec: |
+
+ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> bool:
+ """
+ Check if ``validator`` is partially withdrawable.
+ """
+ has_max_effective_balance = validator.effective_balance == MAX_EFFECTIVE_BALANCE
+ has_excess_balance = balance > MAX_EFFECTIVE_BALANCE
+ return (
+ has_eth1_withdrawal_credential(validator)
+ and has_max_effective_balance
+ and has_excess_balance
+ )
+
+
+- name: is_partially_withdrawable_validator#electra
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsPartiallyWithdrawableValidator(
+ - file: beacon-chain/core/helpers/validators.go
+ search: func isPartiallyWithdrawableValidatorElectra(v
+ spec: |
+
+ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> bool:
+ """
+ Check if ``validator`` is partially withdrawable.
+ """
+ max_effective_balance = get_max_effective_balance(validator)
+ # [Modified in Electra:EIP7251]
+ has_max_effective_balance = validator.effective_balance == max_effective_balance
+ # [Modified in Electra:EIP7251]
+ has_excess_balance = balance > max_effective_balance
+ return (
+ # [Modified in Electra:EIP7251]
+ has_execution_withdrawal_credential(validator)
+ and has_max_effective_balance
+ and has_excess_balance
+ )
+
+
+- name: is_proposer
+ sources: []
+ spec: |
+
+ def is_proposer(state: BeaconState, validator_index: ValidatorIndex) -> bool:
+ return get_beacon_proposer_index(state) == validator_index
+
+
+- name: is_proposing_on_time
+ sources: []
+ spec: |
+
+ def is_proposing_on_time(store: Store) -> bool:
+ # Use half `SECONDS_PER_SLOT // INTERVALS_PER_SLOT` as the proposer reorg deadline
+ time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
+ proposer_reorg_cutoff = SECONDS_PER_SLOT // INTERVALS_PER_SLOT // 2
+ return time_into_slot <= proposer_reorg_cutoff
+
+
+- name: is_shuffling_stable
+ sources: []
+ spec: |
+
+ def is_shuffling_stable(slot: Slot) -> bool:
+ return slot % SLOTS_PER_EPOCH != 0
+
+
+- name: is_slashable_attestation_data
+ sources:
+ - file: beacon-chain/core/blocks/attester_slashing.go
+ search: func IsSlashableAttestationData(
+ spec: |
+
+ def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
+ """
+ Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules.
+ """
+ return (
+ # Double vote
+ (data_1 != data_2 and data_1.target.epoch == data_2.target.epoch)
+ or
+ # Surround vote
+ (data_1.source.epoch < data_2.source.epoch and data_2.target.epoch < data_1.target.epoch)
+ )
+
+
+- name: is_slashable_validator
+ sources:
+ - file: beacon-chain/core/helpers/validators.go
+ search: func IsSlashableValidator(
+ spec: |
+
+ def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool:
+ """
+ Check if ``validator`` is slashable.
+ """
+ return (not validator.slashed) and (
+ validator.activation_epoch <= epoch < validator.withdrawable_epoch
+ )
+
+
+- name: is_sync_committee_aggregator
+ sources:
+ - file: beacon-chain/core/altair/sync_committee.go
+ search: func IsSyncCommitteeAggregator(
+ - file: validator/client/validator.go
+ search: func (v *validator) isSyncCommitteeAggregator(
+ spec: |
+
+ def is_sync_committee_aggregator(signature: BLSSignature) -> bool:
+ modulo = max(
+ 1,
+ SYNC_COMMITTEE_SIZE
+ // SYNC_COMMITTEE_SUBNET_COUNT
+ // TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE,
+ )
+ return bytes_to_uint64(hash(signature)[0:8]) % modulo == 0
+
+
+- name: is_sync_committee_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func HasRelevantSyncCommittee(
+ spec: |
+
+ def is_sync_committee_update(update: LightClientUpdate) -> bool:
+ return update.next_sync_committee_branch != NextSyncCommitteeBranch()
+
+
+- name: is_valid_deposit_signature
+ sources:
+ - file: beacon-chain/core/electra/deposits.go
+ search: func IsValidDepositSignature(
+ - file: beacon-chain/core/blocks/deposit.go
+ search: func IsValidDepositSignature(
+ spec: |
+
+ def is_valid_deposit_signature(
+ pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64, signature: BLSSignature
+ ) -> bool:
+ deposit_message = DepositMessage(
+ pubkey=pubkey,
+ withdrawal_credentials=withdrawal_credentials,
+ amount=amount,
+ )
+ # Fork-agnostic domain since deposits are valid across forks
+ domain = compute_domain(DOMAIN_DEPOSIT)
+ signing_root = compute_signing_root(deposit_message, domain)
+ return bls.Verify(pubkey, signing_root, signature)
+
+
+- name: is_valid_genesis_state
+ sources:
+ - file: beacon-chain/core/transition/state.go
+ search: func IsValidGenesisState(
+ spec: |
+
+ def is_valid_genesis_state(state: BeaconState) -> bool:
+ if state.genesis_time < MIN_GENESIS_TIME:
+ return False
+ if len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
+ return False
+ return True
+
+
+- name: is_valid_indexed_attestation
+ 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 or not 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_light_client_header#altair
+ sources: []
+ spec: |
+
+ def is_valid_light_client_header(_header: LightClientHeader) -> bool:
+ return True
+
+
+- name: is_valid_light_client_header#capella
+ sources: []
+ spec: |
+
+ def is_valid_light_client_header(header: LightClientHeader) -> bool:
+ epoch = compute_epoch_at_slot(header.beacon.slot)
+
+ if epoch < CAPELLA_FORK_EPOCH:
+ return (
+ header.execution == ExecutionPayloadHeader()
+ and header.execution_branch == ExecutionBranch()
+ )
+
+ return is_valid_merkle_branch(
+ leaf=get_lc_execution_root(header),
+ branch=header.execution_branch,
+ depth=floorlog2(EXECUTION_PAYLOAD_GINDEX),
+ index=get_subtree_index(EXECUTION_PAYLOAD_GINDEX),
+ root=header.beacon.body_root,
+ )
+
+
+- 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):
+ return False
+ if header.execution.excess_blob_gas != uint64(0):
+ return False
+
+ if epoch < CAPELLA_FORK_EPOCH:
+ return (
+ header.execution == ExecutionPayloadHeader()
+ and header.execution_branch == ExecutionBranch()
+ )
+
+ return is_valid_merkle_branch(
+ leaf=get_lc_execution_root(header),
+ branch=header.execution_branch,
+ depth=floorlog2(EXECUTION_PAYLOAD_GINDEX),
+ index=get_subtree_index(EXECUTION_PAYLOAD_GINDEX),
+ root=header.beacon.body_root,
+ )
+
+
+- name: is_valid_merkle_branch
+ sources: []
+ spec: |
+
+ def is_valid_merkle_branch(
+ leaf: Bytes32, branch: Sequence[Bytes32], depth: uint64, index: uint64, root: Root
+ ) -> bool:
+ """
+ Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and ``branch``.
+ """
+ value = leaf
+ for i in range(depth):
+ if index // (2**i) % 2:
+ value = hash(branch[i] + value)
+ else:
+ value = hash(value + branch[i])
+ return value == root
+
+
+- name: is_valid_normalized_merkle_branch
+ sources: []
+ spec: |
+
+ def is_valid_normalized_merkle_branch(
+ leaf: Bytes32, branch: Sequence[Bytes32], gindex: GeneralizedIndex, root: Root
+ ) -> bool:
+ depth = floorlog2(gindex)
+ index = get_subtree_index(gindex)
+ num_extra = len(branch) - depth
+ for i in range(num_extra):
+ if branch[i] != Bytes32():
+ return False
+ return is_valid_merkle_branch(leaf, branch[num_extra:], depth, index, root)
+
+
+- name: is_valid_switch_to_compounding_request
+ sources:
+ - file: beacon-chain/core/electra/consolidations.go
+ search: func IsValidSwitchToCompoundingRequest(
+ spec: |
+
+ def is_valid_switch_to_compounding_request(
+ state: BeaconState, consolidation_request: ConsolidationRequest
+ ) -> bool:
+ # Switch to compounding requires source and target be equal
+ if consolidation_request.source_pubkey != consolidation_request.target_pubkey:
+ return False
+
+ # Verify pubkey exists
+ source_pubkey = consolidation_request.source_pubkey
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ if source_pubkey not in validator_pubkeys:
+ return False
+
+ source_validator = state.validators[ValidatorIndex(validator_pubkeys.index(source_pubkey))]
+
+ # Verify request has been authorized
+ if source_validator.withdrawal_credentials[12:] != consolidation_request.source_address:
+ return False
+
+ # Verify source withdrawal credentials
+ if not has_eth1_withdrawal_credential(source_validator):
+ return False
+
+ # Verify the source is active
+ current_epoch = get_current_epoch(state)
+ if not is_active_validator(source_validator, current_epoch):
+ return False
+
+ # Verify exit for source has not been initiated
+ if source_validator.exit_epoch != FAR_FUTURE_EPOCH:
+ return False
+
+ return True
+
+
+- name: is_valid_terminal_pow_block
+ sources:
+ - file: beacon-chain/blockchain/pow_block.go
+ search: func validateTerminalBlockDifficulties(
+ spec: |
+
+ def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool:
+ is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
+ is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
+ return is_total_difficulty_reached and is_parent_total_difficulty_valid
+
+
+- name: is_within_weak_subjectivity_period#phase0
+ sources:
+ - file: beacon-chain/core/helpers/weak_subjectivity.go
+ search: func IsWithinWeakSubjectivityPeriod(
+ spec: |
+
+ def is_within_weak_subjectivity_period(
+ store: Store, ws_state: BeaconState, ws_checkpoint: Checkpoint
+ ) -> bool:
+ # Clients may choose to validate the input state against the input Weak Subjectivity Checkpoint
+ assert ws_state.latest_block_header.state_root == ws_checkpoint.root
+ assert compute_epoch_at_slot(ws_state.slot) == ws_checkpoint.epoch
+
+ ws_period = compute_weak_subjectivity_period(ws_state)
+ ws_state_epoch = compute_epoch_at_slot(ws_state.slot)
+ current_epoch = compute_epoch_at_slot(get_current_slot(store))
+ return current_epoch <= ws_state_epoch + ws_period
+
+
+- name: is_within_weak_subjectivity_period#electra
+ sources: []
+ spec: |
+
+ def is_within_weak_subjectivity_period(
+ store: Store, ws_state: BeaconState, ws_checkpoint: Checkpoint
+ ) -> bool:
+ # Clients may choose to validate the input state against the input Weak Subjectivity Checkpoint
+ assert ws_state.latest_block_header.state_root == ws_checkpoint.root
+ assert compute_epoch_at_slot(ws_state.slot) == ws_checkpoint.epoch
+
+ # [Modified in Electra]
+ ws_period = compute_weak_subjectivity_period(ws_state)
+ ws_state_epoch = compute_epoch_at_slot(ws_state.slot)
+ current_epoch = compute_epoch_at_slot(get_current_slot(store))
+ return current_epoch <= ws_state_epoch + ws_period
+
+
+- name: kzg_commitment_to_versioned_hash
+ sources:
+ - file: consensus-types/primitives/kzg.go
+ search: func ConvertKzgCommitmentToVersionedHash(
+ spec: |
+
+ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> VersionedHash:
+ return VERSIONED_HASH_VERSION_KZG + hash(kzg_commitment)[1:]
+
+
+- name: latest_verified_ancestor
+ sources: []
+ spec: |
+
+ def latest_verified_ancestor(opt_store: OptimisticStore, block: BeaconBlock) -> BeaconBlock:
+ # It is assumed that the `block` parameter is never an INVALIDATED block.
+ while True:
+ if not is_optimistic(opt_store, block) or block.parent_root == Root():
+ return block
+ block = opt_store.blocks[block.parent_root]
+
+
+- name: max_compressed_len
+ sources:
+ - file: beacon-chain/p2p/encoder/ssz.go
+ search: func MaxCompressedLen(
+ spec: |
+
+ 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)
+
+
+- name: max_message_size
+ sources:
+ - file: beacon-chain/p2p/pubsub.go
+ search: func MaxMessageSize(
+ spec: |
+
+ 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)
+
+
+- name: next_sync_committee_gindex_at_slot#altair
+ sources:
+ - file: beacon-chain/state/state-native/proofs.go
+ search: func (b *BeaconState) NextSyncCommitteeGeneralizedIndex(
+ spec: |
+
+ def next_sync_committee_gindex_at_slot(_slot: Slot) -> GeneralizedIndex:
+ return NEXT_SYNC_COMMITTEE_GINDEX
+
+
+- name: next_sync_committee_gindex_at_slot#electra
+ sources: []
+ spec: |
+
+ def next_sync_committee_gindex_at_slot(slot: Slot) -> GeneralizedIndex:
+ epoch = compute_epoch_at_slot(slot)
+
+ # [Modified in Electra]
+ if epoch >= ELECTRA_FORK_EPOCH:
+ return NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA
+ return NEXT_SYNC_COMMITTEE_GINDEX
+
+
+- name: normalize_merkle_branch
+ sources: []
+ spec: |
+
+ def normalize_merkle_branch(
+ branch: Sequence[Bytes32], gindex: GeneralizedIndex
+ ) -> Sequence[Bytes32]:
+ depth = floorlog2(gindex)
+ num_extra = depth - len(branch)
+ return [Bytes32()] * num_extra + [*branch]
+
+
+- name: on_attestation
+ sources:
+ - 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.
+
+ An ``attestation`` that is asserted as invalid may be valid at a later time,
+ consider scheduling it for later processing in such case.
+ """
+ validate_on_attestation(store, attestation, is_from_block)
+
+ store_target_checkpoint_state(store, attestation.data.target)
+
+ # Get state at the `target` to fully validate attestation
+ target_state = store.checkpoint_states[attestation.data.target]
+ indexed_attestation = get_indexed_attestation(target_state, attestation)
+ assert is_valid_indexed_attestation(target_state, indexed_attestation)
+
+ # Update latest messages for attesting indices
+ update_latest_messages(store, indexed_attestation.attesting_indices, attestation)
+
+
+- name: on_attester_slashing
+ sources:
+ - 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``
+ from either within a block or directly on the wire.
+ """
+ attestation_1 = attester_slashing.attestation_1
+ attestation_2 = attester_slashing.attestation_2
+ assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
+ state = store.block_states[store.justified_checkpoint.root]
+ assert is_valid_indexed_attestation(state, attestation_1)
+ assert is_valid_indexed_attestation(state, attestation_2)
+
+ indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
+ for index in indices:
+ store.equivocating_indices.add(index)
+
+
+- name: on_block#phase0
+ sources:
+ - file: beacon-chain/blockchain/receive_block.go
+ search: func (s *Service) ReceiveBlock(
+ spec: |
+
+ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
+ block = signed_block.message
+ # Parent block must be known
+ assert block.parent_root in store.block_states
+ # Make a copy of the state to avoid mutability issues
+ pre_state = copy(store.block_states[block.parent_root])
+ # Blocks cannot be in the future. If they are, their consideration must be delayed until they are in the past.
+ assert get_current_slot(store) >= block.slot
+
+ # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
+ finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
+ assert block.slot > finalized_slot
+ # Check block is a descendant of the finalized block at the checkpoint finalized slot
+ finalized_checkpoint_block = get_checkpoint_block(
+ store,
+ block.parent_root,
+ store.finalized_checkpoint.epoch,
+ )
+ assert store.finalized_checkpoint.root == finalized_checkpoint_block
+
+ # 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, True)
+ # Add new block to the store
+ store.blocks[block_root] = block
+ # Add new state for this block to the store
+ store.block_states[block_root] = state
+
+ # Add block timeliness to the store
+ time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
+ is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
+ is_timely = get_current_slot(store) == block.slot and is_before_attesting_interval
+ store.block_timeliness[hash_tree_root(block)] = is_timely
+
+ # Add proposer score boost if the block is timely and not conflicting with an existing block
+ is_first_block = store.proposer_boost_root == Root()
+ if is_timely and is_first_block:
+ store.proposer_boost_root = hash_tree_root(block)
+
+ # Update checkpoints in store if necessary
+ update_checkpoints(store, state.current_justified_checkpoint, state.finalized_checkpoint)
+
+ # Eagerly compute unrealized justification and finality
+ compute_pulled_up_tip(store, block_root)
+
+
+- name: on_block#bellatrix
+ sources:
+ - 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.
+
+ A block that is asserted as invalid due to unavailable PoW block may be valid at a later time,
+ consider scheduling it for later processing in such case.
+ """
+ block = signed_block.message
+ # Parent block must be known
+ assert block.parent_root in store.block_states
+ # Make a copy of the state to avoid mutability issues
+ pre_state = copy(store.block_states[block.parent_root])
+ # Blocks cannot be in the future. If they are, their consideration must be delayed until they are in the past.
+ assert get_current_slot(store) >= block.slot
+
+ # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
+ finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
+ assert block.slot > finalized_slot
+ # Check block is a descendant of the finalized block at the checkpoint finalized slot
+ finalized_checkpoint_block = get_checkpoint_block(
+ store,
+ block.parent_root,
+ store.finalized_checkpoint.epoch,
+ )
+ assert store.finalized_checkpoint.root == finalized_checkpoint_block
+
+ # 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, True)
+
+ # [New in Bellatrix]
+ if is_merge_transition_block(pre_state, block.body):
+ validate_merge_block(block)
+
+ # Add new block to the store
+ store.blocks[block_root] = block
+ # Add new state for this block to the store
+ store.block_states[block_root] = state
+
+ # Add block timeliness to the store
+ time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
+ is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
+ is_timely = get_current_slot(store) == block.slot and is_before_attesting_interval
+ store.block_timeliness[hash_tree_root(block)] = is_timely
+
+ # Add proposer score boost if the block is timely and not conflicting with an existing block
+ is_first_block = store.proposer_boost_root == Root()
+ if is_timely and is_first_block:
+ store.proposer_boost_root = hash_tree_root(block)
+
+ # Update checkpoints in store if necessary
+ update_checkpoints(store, state.current_justified_checkpoint, state.finalized_checkpoint)
+
+ # Eagerly compute unrealized justification and finality.
+ compute_pulled_up_tip(store, block_root)
+
+
+- name: on_block#capella
+ sources:
+ - 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
+ # 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.
+ assert get_current_slot(store) >= block.slot
+
+ # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
+ finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
+ assert block.slot > finalized_slot
+ # Check block is a descendant of the finalized block at the checkpoint finalized slot
+ finalized_checkpoint_block = get_checkpoint_block(
+ store,
+ block.parent_root,
+ store.finalized_checkpoint.epoch,
+ )
+ assert store.finalized_checkpoint.root == finalized_checkpoint_block
+
+ # 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, True)
+
+ # Add new block to the store
+ store.blocks[block_root] = block
+ # Add new state for this block to the store
+ store.block_states[block_root] = state
+
+ # Add block timeliness to the store
+ time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
+ is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
+ is_timely = get_current_slot(store) == block.slot and is_before_attesting_interval
+ store.block_timeliness[hash_tree_root(block)] = is_timely
+
+ # Add proposer score boost if the block is timely and not conflicting with an existing block
+ is_first_block = store.proposer_boost_root == Root()
+ if is_timely and is_first_block:
+ store.proposer_boost_root = hash_tree_root(block)
+
+ # Update checkpoints in store if necessary
+ update_checkpoints(store, state.current_justified_checkpoint, state.finalized_checkpoint)
+
+ # Eagerly compute unrealized justification and finality.
+ compute_pulled_up_tip(store, block_root)
+
+
+- name: on_block#deneb
+ sources:
+ - 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
+ # 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.
+ assert get_current_slot(store) >= block.slot
+
+ # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
+ finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
+ assert block.slot > finalized_slot
+ # Check block is a descendant of the finalized block at the checkpoint finalized slot
+ finalized_checkpoint_block = get_checkpoint_block(
+ store,
+ block.parent_root,
+ store.finalized_checkpoint.epoch,
+ )
+ assert store.finalized_checkpoint.root == finalized_checkpoint_block
+
+ # [New in Deneb:EIP4844]
+ # Check if blob data is available
+ # If not, this block MAY be queued and subsequently considered when blob data becomes available
+ # *Note*: Extraneous or invalid Blobs (in addition to the expected/referenced valid blobs)
+ # received on the p2p network MUST NOT invalidate a block that is otherwise valid and available
+ assert is_data_available(hash_tree_root(block), 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, True)
+
+ # Add new block to the store
+ store.blocks[block_root] = block
+ # Add new state for this block to the store
+ store.block_states[block_root] = state
+
+ # Add block timeliness to the store
+ time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
+ is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
+ is_timely = get_current_slot(store) == block.slot and is_before_attesting_interval
+ store.block_timeliness[hash_tree_root(block)] = is_timely
+
+ # Add proposer score boost if the block is timely and not conflicting with an existing block
+ is_first_block = store.proposer_boost_root == Root()
+ if is_timely and is_first_block:
+ store.proposer_boost_root = hash_tree_root(block)
+
+ # Update checkpoints in store if necessary
+ update_checkpoints(store, state.current_justified_checkpoint, state.finalized_checkpoint)
+
+ # Eagerly compute unrealized justification and finality.
+ compute_pulled_up_tip(store, block_root)
+
+
+- name: on_block#fulu
+ sources:
+ - 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
+ # Parent block must be known
+ assert block.parent_root in store.block_states
+ # Make a copy of the state to avoid mutability issues
+ state = copy(store.block_states[block.parent_root])
+ # Blocks cannot be in the future. If they are, their consideration must be delayed until they are in the past.
+ assert get_current_slot(store) >= block.slot
+
+ # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
+ finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
+ assert block.slot > finalized_slot
+ # Check block is a descendant of the finalized block at the checkpoint finalized slot
+ finalized_checkpoint_block = get_checkpoint_block(
+ store,
+ block.parent_root,
+ store.finalized_checkpoint.epoch,
+ )
+ assert store.finalized_checkpoint.root == finalized_checkpoint_block
+
+ # [Modified in Fulu:EIP7594]
+ assert is_data_available(hash_tree_root(block))
+
+ # Check the block is valid and compute the post-state
+ block_root = hash_tree_root(block)
+ state_transition(state, signed_block, True)
+
+ # Add new block to the store
+ store.blocks[block_root] = block
+ # Add new state for this block to the store
+ store.block_states[block_root] = state
+
+ # Add block timeliness to the store
+ time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
+ is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
+ is_timely = get_current_slot(store) == block.slot and is_before_attesting_interval
+ store.block_timeliness[hash_tree_root(block)] = is_timely
+
+ # Add proposer score boost if the block is timely and not conflicting with an existing block
+ is_first_block = store.proposer_boost_root == Root()
+ if is_timely and is_first_block:
+ store.proposer_boost_root = hash_tree_root(block)
+
+ # Update checkpoints in store if necessary
+ update_checkpoints(store, state.current_justified_checkpoint, state.finalized_checkpoint)
+
+ # Eagerly compute unrealized justification and finality.
+ compute_pulled_up_tip(store, block_root)
+
+
+- name: on_tick
+ sources: []
+ spec: |
+
+ 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) // SECONDS_PER_SLOT
+ while get_current_slot(store) < tick_slot:
+ previous_time = store.genesis_time + (get_current_slot(store) + 1) * SECONDS_PER_SLOT
+ on_tick_per_slot(store, previous_time)
+ on_tick_per_slot(store, time)
+
+
+- name: on_tick_per_slot
+ sources: []
+ spec: |
+
+ def on_tick_per_slot(store: Store, time: uint64) -> None:
+ previous_slot = get_current_slot(store)
+
+ # Update store time
+ store.time = time
+
+ current_slot = get_current_slot(store)
+
+ # If this is a new slot, reset store.proposer_boost_root
+ if current_slot > previous_slot:
+ store.proposer_boost_root = Root()
+
+ # If a new epoch, pull-up justification and finalization from previous epoch
+ if current_slot > previous_slot and compute_slots_since_epoch_start(current_slot) == 0:
+ update_checkpoints(
+ store, store.unrealized_justified_checkpoint, store.unrealized_finalized_checkpoint
+ )
+
+
+- name: prepare_execution_payload#bellatrix
+ sources: []
+ spec: |
+
+ def prepare_execution_payload(
+ state: BeaconState,
+ safe_block_hash: Hash32,
+ finalized_block_hash: Hash32,
+ suggested_fee_recipient: ExecutionAddress,
+ execution_engine: ExecutionEngine,
+ pow_chain: Optional[Dict[Hash32, PowBlock]] = None,
+ ) -> Optional[PayloadId]:
+ if not is_merge_transition_complete(state):
+ assert pow_chain is not None
+ is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
+ is_activation_epoch_reached = (
+ get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
+ )
+ if is_terminal_block_hash_set and not is_activation_epoch_reached:
+ # Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed
+ return None
+
+ terminal_pow_block = get_terminal_pow_block(pow_chain)
+ if terminal_pow_block is None:
+ # Pre-merge, no prepare payload call is needed
+ return None
+ # Signify merge via producing on top of the terminal PoW block
+ parent_hash = terminal_pow_block.block_hash
+ else:
+ # Post-merge, normal payload
+ parent_hash = state.latest_execution_payload_header.block_hash
+
+ # Set the forkchoice head and initiate the payload build process
+ payload_attributes = PayloadAttributes(
+ timestamp=compute_time_at_slot(state, state.slot),
+ prev_randao=get_randao_mix(state, get_current_epoch(state)),
+ suggested_fee_recipient=suggested_fee_recipient,
+ )
+ return execution_engine.notify_forkchoice_updated(
+ head_block_hash=parent_hash,
+ safe_block_hash=safe_block_hash,
+ finalized_block_hash=finalized_block_hash,
+ payload_attributes=payload_attributes,
+ )
+
+
+- name: prepare_execution_payload#capella
+ sources: []
+ spec: |
+
+ def prepare_execution_payload(
+ state: BeaconState,
+ safe_block_hash: Hash32,
+ finalized_block_hash: Hash32,
+ suggested_fee_recipient: ExecutionAddress,
+ execution_engine: ExecutionEngine,
+ ) -> Optional[PayloadId]:
+ # [Modified in Capella]
+ # Removed `is_merge_transition_complete` check
+ parent_hash = state.latest_execution_payload_header.block_hash
+
+ # Set the forkchoice head and initiate the payload build process
+ payload_attributes = PayloadAttributes(
+ timestamp=compute_time_at_slot(state, state.slot),
+ prev_randao=get_randao_mix(state, get_current_epoch(state)),
+ suggested_fee_recipient=suggested_fee_recipient,
+ # [New in Capella]
+ withdrawals=get_expected_withdrawals(state),
+ )
+ return execution_engine.notify_forkchoice_updated(
+ head_block_hash=parent_hash,
+ safe_block_hash=safe_block_hash,
+ finalized_block_hash=finalized_block_hash,
+ payload_attributes=payload_attributes,
+ )
+
+
+- name: prepare_execution_payload#deneb
+ sources: []
+ spec: |
+
+ def prepare_execution_payload(
+ state: BeaconState,
+ safe_block_hash: Hash32,
+ finalized_block_hash: Hash32,
+ suggested_fee_recipient: ExecutionAddress,
+ execution_engine: ExecutionEngine,
+ ) -> Optional[PayloadId]:
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ parent_hash = state.latest_execution_payload_header.block_hash
+
+ # Set the forkchoice head and initiate the payload build process
+ payload_attributes = PayloadAttributes(
+ timestamp=compute_time_at_slot(state, state.slot),
+ prev_randao=get_randao_mix(state, get_current_epoch(state)),
+ suggested_fee_recipient=suggested_fee_recipient,
+ withdrawals=get_expected_withdrawals(state),
+ # [New in Deneb:EIP4788]
+ parent_beacon_block_root=hash_tree_root(state.latest_block_header),
+ )
+ return execution_engine.notify_forkchoice_updated(
+ head_block_hash=parent_hash,
+ safe_block_hash=safe_block_hash,
+ finalized_block_hash=finalized_block_hash,
+ payload_attributes=payload_attributes,
+ )
+
+
+- name: prepare_execution_payload#electra
+ sources: []
+ spec: |
+
+ def prepare_execution_payload(
+ state: BeaconState,
+ safe_block_hash: Hash32,
+ finalized_block_hash: Hash32,
+ suggested_fee_recipient: ExecutionAddress,
+ execution_engine: ExecutionEngine,
+ ) -> Optional[PayloadId]:
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ parent_hash = state.latest_execution_payload_header.block_hash
+
+ # [Modified in EIP7251]
+ # Set the forkchoice head and initiate the payload build process
+ withdrawals, _ = get_expected_withdrawals(state)
+
+ payload_attributes = PayloadAttributes(
+ timestamp=compute_time_at_slot(state, state.slot),
+ prev_randao=get_randao_mix(state, get_current_epoch(state)),
+ suggested_fee_recipient=suggested_fee_recipient,
+ withdrawals=withdrawals,
+ parent_beacon_block_root=hash_tree_root(state.latest_block_header),
+ )
+ return execution_engine.notify_forkchoice_updated(
+ head_block_hash=parent_hash,
+ safe_block_hash=safe_block_hash,
+ finalized_block_hash=finalized_block_hash,
+ payload_attributes=payload_attributes,
+ )
+
+
+- name: process_attestation#phase0
+ sources:
+ - file: beacon-chain/core/blocks/attestation.go
+ search: func ProcessAttestationNoVerifySignature(
+ spec: |
+
+ def process_attestation(state: BeaconState, attestation: Attestation) -> 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)
+ assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
+ assert data.index < get_committee_count_per_slot(state, data.target.epoch)
+
+ committee = get_beacon_committee(state, data.slot, data.index)
+ assert len(attestation.aggregation_bits) == len(committee)
+
+ pending_attestation = PendingAttestation(
+ data=data,
+ aggregation_bits=attestation.aggregation_bits,
+ inclusion_delay=state.slot - data.slot,
+ proposer_index=get_beacon_proposer_index(state),
+ )
+
+ if data.target.epoch == get_current_epoch(state):
+ assert data.source == state.current_justified_checkpoint
+ state.current_epoch_attestations.append(pending_attestation)
+ else:
+ assert data.source == state.previous_justified_checkpoint
+ state.previous_epoch_attestations.append(pending_attestation)
+
+ # Verify signature
+ assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
+
+
+- name: process_attestation#altair
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func ProcessAttestationNoVerifySignature(
+ spec: |
+
+ def process_attestation(state: BeaconState, attestation: Attestation) -> 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)
+ assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
+ assert data.index < get_committee_count_per_slot(state, data.target.epoch)
+
+ committee = get_beacon_committee(state, data.slot, data.index)
+ assert len(attestation.aggregation_bits) == len(committee)
+
+ # Participation flag indices
+ participation_flag_indices = get_attestation_participation_flag_indices(
+ state, data, state.slot - data.slot
+ )
+
+ # Verify signature
+ assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
+
+ # Update epoch participation flags
+ if data.target.epoch == get_current_epoch(state):
+ epoch_participation = state.current_epoch_participation
+ else:
+ epoch_participation = state.previous_epoch_participation
+
+ proposer_reward_numerator = 0
+ for index in get_attesting_indices(state, attestation):
+ for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
+ if flag_index in participation_flag_indices and not has_flag(
+ epoch_participation[index], flag_index
+ ):
+ epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
+ proposer_reward_numerator += get_base_reward(state, index) * weight
+
+ # Reward proposer
+ proposer_reward_denominator = (
+ (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
+ )
+ proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
+ increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
+
+
+- name: process_attestation#deneb
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func ProcessAttestationNoVerifySignature(
+ spec: |
+
+ def process_attestation(state: BeaconState, attestation: Attestation) -> 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)
+ # [Modified in Deneb:EIP7045]
+ assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot
+ assert data.index < get_committee_count_per_slot(state, data.target.epoch)
+
+ committee = get_beacon_committee(state, data.slot, data.index)
+ assert len(attestation.aggregation_bits) == len(committee)
+
+ # Participation flag indices
+ participation_flag_indices = get_attestation_participation_flag_indices(
+ state, data, state.slot - data.slot
+ )
+
+ # Verify signature
+ assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
+
+ # Update epoch participation flags
+ if data.target.epoch == get_current_epoch(state):
+ epoch_participation = state.current_epoch_participation
+ else:
+ epoch_participation = state.previous_epoch_participation
+
+ proposer_reward_numerator = 0
+ for index in get_attesting_indices(state, attestation):
+ for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
+ if flag_index in participation_flag_indices and not has_flag(
+ epoch_participation[index], flag_index
+ ):
+ epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
+ proposer_reward_numerator += get_base_reward(state, index) * weight
+
+ # Reward proposer
+ proposer_reward_denominator = (
+ (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
+ )
+ proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
+ increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
+
+
+- name: process_attestation#electra
+ sources:
+ - file: beacon-chain/core/altair/attestation.go
+ search: func ProcessAttestationNoVerifySignature(
+ spec: |
+
+ def process_attestation(state: BeaconState, attestation: Attestation) -> 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)
+ assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot
+
+ # [Modified in Electra:EIP7549]
+ assert data.index == 0
+ committee_indices = get_committee_indices(attestation.committee_bits)
+ committee_offset = 0
+ for committee_index in committee_indices:
+ assert committee_index < get_committee_count_per_slot(state, data.target.epoch)
+ committee = get_beacon_committee(state, data.slot, committee_index)
+ committee_attesters = set(
+ attester_index
+ for i, attester_index in enumerate(committee)
+ if attestation.aggregation_bits[committee_offset + i]
+ )
+ assert len(committee_attesters) > 0
+ committee_offset += len(committee)
+
+ # Bitfield length matches total number of participants
+ assert len(attestation.aggregation_bits) == committee_offset
+
+ # Participation flag indices
+ participation_flag_indices = get_attestation_participation_flag_indices(
+ state, data, state.slot - data.slot
+ )
+
+ # Verify signature
+ assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
+
+ # Update epoch participation flags
+ if data.target.epoch == get_current_epoch(state):
+ epoch_participation = state.current_epoch_participation
+ else:
+ epoch_participation = state.previous_epoch_participation
+
+ proposer_reward_numerator = 0
+ for index in get_attesting_indices(state, attestation):
+ for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
+ if flag_index in participation_flag_indices and not has_flag(
+ epoch_participation[index], flag_index
+ ):
+ epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
+ proposer_reward_numerator += get_base_reward(state, index) * weight
+
+ # Reward proposer
+ proposer_reward_denominator = (
+ (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
+ )
+ proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
+ increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
+
+
+- name: process_attester_slashing
+ sources:
+ - file: beacon-chain/core/blocks/attester_slashing.go
+ search: func ProcessAttesterSlashing(
+ spec: |
+
+ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
+ attestation_1 = attester_slashing.attestation_1
+ attestation_2 = attester_slashing.attestation_2
+ assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
+ assert is_valid_indexed_attestation(state, attestation_1)
+ assert is_valid_indexed_attestation(state, attestation_2)
+
+ slashed_any = False
+ indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
+ for index in sorted(indices):
+ if is_slashable_validator(state.validators[index], get_current_epoch(state)):
+ slash_validator(state, index)
+ slashed_any = True
+ assert slashed_any
+
+
+- name: process_block#phase0
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessBlockNoVerifyAnySig(
+ spec: |
+
+ def process_block(state: BeaconState, block: BeaconBlock) -> None:
+ process_block_header(state, block)
+ process_randao(state, block.body)
+ process_eth1_data(state, block.body)
+ process_operations(state, block.body)
+
+
+- name: process_block#altair
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessBlockNoVerifyAnySig(
+ spec: |
+
+ def process_block(state: BeaconState, block: BeaconBlock) -> None:
+ process_block_header(state, block)
+ process_randao(state, block.body)
+ process_eth1_data(state, block.body)
+ # [Modified in Altair]
+ process_operations(state, block.body)
+ # [New in Altair]
+ process_sync_aggregate(state, block.body.sync_aggregate)
+
+
+- name: process_block#bellatrix
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessBlockNoVerifyAnySig(
+ spec: |
+
+ def process_block(state: BeaconState, block: BeaconBlock) -> None:
+ process_block_header(state, block)
+ if is_execution_enabled(state, block.body):
+ # [New in Bellatrix]
+ process_execution_payload(state, block.body, EXECUTION_ENGINE)
+ process_randao(state, block.body)
+ process_eth1_data(state, block.body)
+ process_operations(state, block.body)
+ process_sync_aggregate(state, block.body.sync_aggregate)
+
+
+- name: process_block#capella
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessBlockNoVerifyAnySig(
+ spec: |
+
+ def process_block(state: BeaconState, block: BeaconBlock) -> None:
+ process_block_header(state, block)
+ # [Modified in Capella]
+ # Removed `is_execution_enabled` call
+ # [New in Capella]
+ process_withdrawals(state, block.body.execution_payload)
+ # [Modified in Capella]
+ process_execution_payload(state, block.body, EXECUTION_ENGINE)
+ process_randao(state, block.body)
+ process_eth1_data(state, block.body)
+ # [Modified in Capella]
+ process_operations(state, block.body)
+ process_sync_aggregate(state, block.body.sync_aggregate)
+
+
+- name: process_block#electra
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessBlockNoVerifyAnySig(
+ spec: |
+
+ def process_block(state: BeaconState, block: BeaconBlock) -> None:
+ process_block_header(state, block)
+ # [Modified in Electra:EIP7251]
+ process_withdrawals(state, block.body.execution_payload)
+ # [Modified in Electra:EIP6110]
+ process_execution_payload(state, block.body, EXECUTION_ENGINE)
+ process_randao(state, block.body)
+ process_eth1_data(state, block.body)
+ # [Modified in Electra:EIP6110:EIP7002:EIP7549:EIP7251]
+ process_operations(state, block.body)
+ process_sync_aggregate(state, block.body.sync_aggregate)
+
+
+- name: process_block_header
+ sources:
+ - file: beacon-chain/core/blocks/header.go
+ search: func ProcessBlockHeader(
+ spec: |
+
+ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
+ # Verify that the slots match
+ assert block.slot == state.slot
+ # Verify that the block is newer than latest block header
+ assert block.slot > state.latest_block_header.slot
+ # Verify that proposer index is the correct index
+ assert block.proposer_index == get_beacon_proposer_index(state)
+ # Verify that the parent matches
+ assert block.parent_root == hash_tree_root(state.latest_block_header)
+ # Cache current block as the new latest block
+ state.latest_block_header = BeaconBlockHeader(
+ slot=block.slot,
+ proposer_index=block.proposer_index,
+ parent_root=block.parent_root,
+ state_root=Bytes32(), # Overwritten in the next process_slot call
+ body_root=hash_tree_root(block.body),
+ )
+
+ # Verify proposer is not slashed
+ proposer = state.validators[block.proposer_index]
+ assert not proposer.slashed
+
+
+- name: process_bls_to_execution_change
+ sources:
+ - file: beacon-chain/core/blocks/withdrawals.go
+ search: func ProcessBLSToExecutionChanges(
+ spec: |
+
+ def process_bls_to_execution_change(
+ state: BeaconState, signed_address_change: SignedBLSToExecutionChange
+ ) -> None:
+ address_change = signed_address_change.message
+
+ assert address_change.validator_index < len(state.validators)
+
+ validator = state.validators[address_change.validator_index]
+
+ assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX
+ assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:]
+
+ # Fork-agnostic domain since address changes are valid across forks
+ domain = compute_domain(
+ DOMAIN_BLS_TO_EXECUTION_CHANGE, genesis_validators_root=state.genesis_validators_root
+ )
+ signing_root = compute_signing_root(address_change, domain)
+ assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature)
+
+ validator.withdrawal_credentials = (
+ ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + address_change.to_execution_address
+ )
+
+
+- name: process_consolidation_request
+ sources:
+ - file: beacon-chain/core/electra/consolidations.go
+ search: func ProcessConsolidationRequests(
+ spec: |
+
+ def process_consolidation_request(
+ state: BeaconState, consolidation_request: ConsolidationRequest
+ ) -> None:
+ if is_valid_switch_to_compounding_request(state, consolidation_request):
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ request_source_pubkey = consolidation_request.source_pubkey
+ source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
+ switch_to_compounding_validator(state, source_index)
+ return
+
+ # Verify that source != target, so a consolidation cannot be used as an exit
+ if consolidation_request.source_pubkey == consolidation_request.target_pubkey:
+ return
+ # If the pending consolidations queue is full, consolidation requests are ignored
+ if len(state.pending_consolidations) == PENDING_CONSOLIDATIONS_LIMIT:
+ return
+ # If there is too little available consolidation churn limit, consolidation requests are ignored
+ if get_consolidation_churn_limit(state) <= MIN_ACTIVATION_BALANCE:
+ return
+
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ # Verify pubkeys exists
+ request_source_pubkey = consolidation_request.source_pubkey
+ request_target_pubkey = consolidation_request.target_pubkey
+ if request_source_pubkey not in validator_pubkeys:
+ return
+ if request_target_pubkey not in validator_pubkeys:
+ return
+ source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
+ target_index = ValidatorIndex(validator_pubkeys.index(request_target_pubkey))
+ source_validator = state.validators[source_index]
+ target_validator = state.validators[target_index]
+
+ # Verify source withdrawal credentials
+ has_correct_credential = has_execution_withdrawal_credential(source_validator)
+ is_correct_source_address = (
+ source_validator.withdrawal_credentials[12:] == consolidation_request.source_address
+ )
+ if not (has_correct_credential and is_correct_source_address):
+ return
+
+ # Verify that target has compounding withdrawal credentials
+ if not has_compounding_withdrawal_credential(target_validator):
+ return
+
+ # Verify the source and the target are active
+ current_epoch = get_current_epoch(state)
+ if not is_active_validator(source_validator, current_epoch):
+ return
+ if not is_active_validator(target_validator, current_epoch):
+ return
+ # Verify exits for source and target have not been initiated
+ if source_validator.exit_epoch != FAR_FUTURE_EPOCH:
+ return
+ if target_validator.exit_epoch != FAR_FUTURE_EPOCH:
+ return
+ # Verify the source has been active long enough
+ if current_epoch < source_validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
+ return
+ # Verify the source has no pending withdrawals in the queue
+ if get_pending_balance_to_withdraw(state, source_index) > 0:
+ return
+
+ # Initiate source validator exit and append pending consolidation
+ source_validator.exit_epoch = compute_consolidation_epoch_and_update_churn(
+ state, source_validator.effective_balance
+ )
+ source_validator.withdrawable_epoch = Epoch(
+ source_validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
+ )
+ state.pending_consolidations.append(
+ PendingConsolidation(source_index=source_index, target_index=target_index)
+ )
+
+
+- name: process_deposit#phase0
+ sources:
+ - file: beacon-chain/core/altair/deposit.go
+ search: func ProcessDeposit(
+ spec: |
+
+ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
+ # Verify the Merkle branch
+ assert is_valid_merkle_branch(
+ leaf=hash_tree_root(deposit.data),
+ branch=deposit.proof,
+ # Add 1 for the List length mix-in
+ depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1,
+ index=state.eth1_deposit_index,
+ root=state.eth1_data.deposit_root,
+ )
+
+ # Deposits must be processed in order
+ state.eth1_deposit_index += 1
+
+ apply_deposit(
+ state=state,
+ pubkey=deposit.data.pubkey,
+ withdrawal_credentials=deposit.data.withdrawal_credentials,
+ amount=deposit.data.amount,
+ signature=deposit.data.signature,
+ )
+
+
+- name: process_deposit#electra
+ sources:
+ - file: beacon-chain/core/electra/deposits.go
+ search: func ProcessDeposit(
+ spec: |
+
+ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
+ # Verify the Merkle branch
+ assert is_valid_merkle_branch(
+ leaf=hash_tree_root(deposit.data),
+ branch=deposit.proof,
+ # Add 1 for the List length mix-in
+ depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1,
+ index=state.eth1_deposit_index,
+ root=state.eth1_data.deposit_root,
+ )
+
+ # Deposits must be processed in order
+ state.eth1_deposit_index += 1
+
+ # [Modified in Electra:EIP7251]
+ apply_deposit(
+ state=state,
+ pubkey=deposit.data.pubkey,
+ withdrawal_credentials=deposit.data.withdrawal_credentials,
+ amount=deposit.data.amount,
+ signature=deposit.data.signature,
+ )
+
+
+- name: process_deposit_request
+ sources:
+ - file: beacon-chain/core/electra/deposits.go
+ search: func processDepositRequest(
+ spec: |
+
+ def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
+ # Set deposit request start index
+ if state.deposit_requests_start_index == UNSET_DEPOSIT_REQUESTS_START_INDEX:
+ state.deposit_requests_start_index = deposit_request.index
+
+ # Create pending deposit
+ state.pending_deposits.append(
+ PendingDeposit(
+ pubkey=deposit_request.pubkey,
+ withdrawal_credentials=deposit_request.withdrawal_credentials,
+ amount=deposit_request.amount,
+ signature=deposit_request.signature,
+ slot=state.slot,
+ )
+ )
+
+
+- name: process_effective_balance_updates#phase0
+ sources:
+ - 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)
+ DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
+ UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
+ if (
+ balance + DOWNWARD_THRESHOLD < validator.effective_balance
+ or validator.effective_balance + UPWARD_THRESHOLD < balance
+ ):
+ validator.effective_balance = min(
+ balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE
+ )
+
+
+- name: process_effective_balance_updates#electra
+ sources:
+ - 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)
+ DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
+ UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
+ # [Modified in Electra:EIP7251]
+ max_effective_balance = get_max_effective_balance(validator)
+
+ if (
+ balance + DOWNWARD_THRESHOLD < validator.effective_balance
+ or validator.effective_balance + UPWARD_THRESHOLD < balance
+ ):
+ validator.effective_balance = min(
+ balance - balance % EFFECTIVE_BALANCE_INCREMENT, max_effective_balance
+ )
+
+
+- name: process_epoch#phase0
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessEpoch(
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessEpochPrecompute(
+ spec: |
+
+ def process_epoch(state: BeaconState) -> None:
+ process_justification_and_finalization(state)
+ process_rewards_and_penalties(state)
+ process_registry_updates(state)
+ process_slashings(state)
+ process_eth1_data_reset(state)
+ process_effective_balance_updates(state)
+ process_slashings_reset(state)
+ process_randao_mixes_reset(state)
+ process_historical_roots_update(state)
+ process_participation_record_updates(state)
+
+
+- name: process_epoch#altair
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessEpoch(
+ - file: beacon-chain/core/altair/transition.go
+ search: func ProcessEpoch(
+ spec: |
+
+ def process_epoch(state: BeaconState) -> None:
+ # [Modified in Altair]
+ process_justification_and_finalization(state)
+ # [New in Altair]
+ process_inactivity_updates(state)
+ # [Modified in Altair]
+ process_rewards_and_penalties(state)
+ process_registry_updates(state)
+ # [Modified in Altair]
+ process_slashings(state)
+ process_eth1_data_reset(state)
+ process_effective_balance_updates(state)
+ process_slashings_reset(state)
+ process_randao_mixes_reset(state)
+ process_historical_roots_update(state)
+ # [New in Altair]
+ process_participation_flag_updates(state)
+ # [New in Altair]
+ process_sync_committee_updates(state)
+
+
+- name: process_epoch#electra
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessEpoch(
+ - file: beacon-chain/core/electra/transition.go
+ search: func ProcessEpoch(
+ spec: |
+
+ def process_epoch(state: BeaconState) -> None:
+ process_justification_and_finalization(state)
+ process_inactivity_updates(state)
+ process_rewards_and_penalties(state)
+ # [Modified in Electra:EIP7251]
+ process_registry_updates(state)
+ # [Modified in Electra:EIP7251]
+ process_slashings(state)
+ process_eth1_data_reset(state)
+ # [New in Electra:EIP7251]
+ process_pending_deposits(state)
+ # [New in Electra:EIP7251]
+ process_pending_consolidations(state)
+ # [Modified in Electra:EIP7251]
+ process_effective_balance_updates(state)
+ process_slashings_reset(state)
+ process_randao_mixes_reset(state)
+ process_historical_summaries_update(state)
+ process_participation_flag_updates(state)
+ process_sync_committee_updates(state)
+
+
+- name: process_epoch#fulu
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessEpoch(
+ - file: beacon-chain/core/fulu/transition.go
+ search: func ProcessEpoch(
+ spec: |
+
+ def process_epoch(state: BeaconState) -> None:
+ process_justification_and_finalization(state)
+ process_inactivity_updates(state)
+ process_rewards_and_penalties(state)
+ process_registry_updates(state)
+ process_slashings(state)
+ process_eth1_data_reset(state)
+ process_pending_deposits(state)
+ process_pending_consolidations(state)
+ process_effective_balance_updates(state)
+ process_slashings_reset(state)
+ process_randao_mixes_reset(state)
+ process_historical_summaries_update(state)
+ process_participation_flag_updates(state)
+ process_sync_committee_updates(state)
+ # [New in Fulu:EIP7917]
+ process_proposer_lookahead(state)
+
+
+- name: process_eth1_data
+ sources:
+ - file: beacon-chain/core/blocks/eth1_data.go
+ search: func ProcessEth1DataInBlock(
+ spec: |
+
+ def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
+ state.eth1_data_votes.append(body.eth1_data)
+ if (
+ state.eth1_data_votes.count(body.eth1_data) * 2
+ > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH
+ ):
+ state.eth1_data = body.eth1_data
+
+
+- name: process_eth1_data_reset
+ sources:
+ - 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 = []
+
+
+- name: process_execution_payload#bellatrix
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func ProcessPayload(
+ spec: |
+
+ def process_execution_payload(
+ state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine
+ ) -> None:
+ payload = body.execution_payload
+
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ if is_merge_transition_complete(state):
+ assert payload.parent_hash == state.latest_execution_payload_header.block_hash
+ # Verify prev_randao
+ assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
+ # Verify timestamp
+ assert payload.timestamp == compute_time_at_slot(state, state.slot)
+ # Verify the execution payload is valid
+ assert execution_engine.verify_and_notify_new_payload(
+ NewPayloadRequest(execution_payload=payload)
+ )
+ # Cache execution payload header
+ state.latest_execution_payload_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ )
+
+
+- name: process_execution_payload#capella
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func ProcessPayload(
+ spec: |
+
+ def process_execution_payload(
+ state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine
+ ) -> None:
+ payload = body.execution_payload
+ # [Modified in Capella]
+ # Removed `is_merge_transition_complete` check
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ assert payload.parent_hash == state.latest_execution_payload_header.block_hash
+ # Verify prev_randao
+ assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
+ # Verify timestamp
+ assert payload.timestamp == compute_time_at_slot(state, state.slot)
+ # Verify the execution payload is valid
+ assert execution_engine.verify_and_notify_new_payload(
+ NewPayloadRequest(execution_payload=payload)
+ )
+ # Cache execution payload header
+ state.latest_execution_payload_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ # [New in Capella]
+ withdrawals_root=hash_tree_root(payload.withdrawals),
+ )
+
+
+- name: process_execution_payload#deneb
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func ProcessPayload(
+ spec: |
+
+ def process_execution_payload(
+ state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine
+ ) -> None:
+ payload = body.execution_payload
+
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ assert payload.parent_hash == state.latest_execution_payload_header.block_hash
+ # Verify prev_randao
+ assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
+ # Verify timestamp
+ assert payload.timestamp == compute_time_at_slot(state, state.slot)
+
+ # [New in Deneb:EIP4844] Verify commitments are under limit
+ assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK
+
+ # Verify the execution payload is valid
+ # [Modified in Deneb:EIP4844] Pass `versioned_hashes` to Execution Engine
+ # [Modified in Deneb:EIP4788] Pass `parent_beacon_block_root` to Execution Engine
+ versioned_hashes = [
+ kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments
+ ]
+ assert execution_engine.verify_and_notify_new_payload(
+ NewPayloadRequest(
+ execution_payload=payload,
+ versioned_hashes=versioned_hashes,
+ parent_beacon_block_root=state.latest_block_header.parent_root,
+ )
+ )
+
+ # Cache execution payload header
+ state.latest_execution_payload_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ withdrawals_root=hash_tree_root(payload.withdrawals),
+ # [New in Deneb:EIP4844]
+ blob_gas_used=payload.blob_gas_used,
+ # [New in Deneb:EIP4844]
+ excess_blob_gas=payload.excess_blob_gas,
+ )
+
+
+- name: process_execution_payload#electra
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func ProcessPayload(
+ spec: |
+
+ def process_execution_payload(
+ state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine
+ ) -> None:
+ payload = body.execution_payload
+
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ assert payload.parent_hash == state.latest_execution_payload_header.block_hash
+ # Verify prev_randao
+ assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
+ # Verify timestamp
+ assert payload.timestamp == compute_time_at_slot(state, state.slot)
+ # [Modified in Electra:EIP7691] Verify commitments are under limit
+ assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_ELECTRA
+ # Verify the execution payload is valid
+ versioned_hashes = [
+ kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments
+ ]
+ assert execution_engine.verify_and_notify_new_payload(
+ NewPayloadRequest(
+ execution_payload=payload,
+ versioned_hashes=versioned_hashes,
+ parent_beacon_block_root=state.latest_block_header.parent_root,
+ # [New in Electra]
+ execution_requests=body.execution_requests,
+ )
+ )
+ # Cache execution payload header
+ state.latest_execution_payload_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ withdrawals_root=hash_tree_root(payload.withdrawals),
+ blob_gas_used=payload.blob_gas_used,
+ excess_blob_gas=payload.excess_blob_gas,
+ )
+
+
+- name: process_execution_payload#fulu
+ sources:
+ - file: beacon-chain/core/blocks/payload.go
+ search: func ProcessPayload(
+ spec: |
+
+ def process_execution_payload(
+ state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine
+ ) -> None:
+ payload = body.execution_payload
+
+ # Verify consistency of the parent hash with respect to the previous execution payload header
+ assert payload.parent_hash == state.latest_execution_payload_header.block_hash
+ # Verify prev_randao
+ assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
+ # Verify timestamp
+ assert payload.timestamp == compute_time_at_slot(state, state.slot)
+ # [Modified in Fulu:EIP7892] Verify commitments are under limit
+ assert (
+ len(body.blob_kzg_commitments)
+ <= get_blob_parameters(get_current_epoch(state)).max_blobs_per_block
+ )
+ # Verify the execution payload is valid
+ versioned_hashes = [
+ kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments
+ ]
+ assert execution_engine.verify_and_notify_new_payload(
+ NewPayloadRequest(
+ execution_payload=payload,
+ versioned_hashes=versioned_hashes,
+ parent_beacon_block_root=state.latest_block_header.parent_root,
+ execution_requests=body.execution_requests,
+ )
+ )
+ # Cache execution payload header
+ state.latest_execution_payload_header = ExecutionPayloadHeader(
+ parent_hash=payload.parent_hash,
+ fee_recipient=payload.fee_recipient,
+ state_root=payload.state_root,
+ receipts_root=payload.receipts_root,
+ logs_bloom=payload.logs_bloom,
+ prev_randao=payload.prev_randao,
+ block_number=payload.block_number,
+ gas_limit=payload.gas_limit,
+ gas_used=payload.gas_used,
+ timestamp=payload.timestamp,
+ extra_data=payload.extra_data,
+ base_fee_per_gas=payload.base_fee_per_gas,
+ block_hash=payload.block_hash,
+ transactions_root=hash_tree_root(payload.transactions),
+ withdrawals_root=hash_tree_root(payload.withdrawals),
+ blob_gas_used=payload.blob_gas_used,
+ excess_blob_gas=payload.excess_blob_gas,
+ )
+
+
+- name: process_historical_roots_update
+ sources:
+ - file: beacon-chain/core/epoch/epoch_processing.go
+ search: func ProcessHistoricalDataUpdate(
+ spec: |
+
+ def process_historical_roots_update(state: BeaconState) -> None:
+ # Set historical root accumulator
+ next_epoch = Epoch(get_current_epoch(state) + 1)
+ if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
+ historical_batch = HistoricalBatch(
+ block_roots=state.block_roots, state_roots=state.state_roots
+ )
+ state.historical_roots.append(hash_tree_root(historical_batch))
+
+
+- name: process_historical_summaries_update
+ sources:
+ - file: beacon-chain/core/epoch/epoch_processing.go
+ search: func ProcessHistoricalDataUpdate(
+ spec: |
+
+ def process_historical_summaries_update(state: BeaconState) -> None:
+ # Set historical block root accumulator.
+ next_epoch = Epoch(get_current_epoch(state) + 1)
+ if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
+ historical_summary = HistoricalSummary(
+ block_summary_root=hash_tree_root(state.block_roots),
+ state_summary_root=hash_tree_root(state.state_roots),
+ )
+ state.historical_summaries.append(historical_summary)
+
+
+- name: process_inactivity_updates
+ sources:
+ - file: beacon-chain/core/altair/epoch_precompute.go
+ search: func ProcessInactivityScores(
+ spec: |
+
+ def process_inactivity_updates(state: BeaconState) -> None:
+ # Skip the genesis epoch as score updates are based on the previous epoch participation
+ if get_current_epoch(state) == GENESIS_EPOCH:
+ return
+
+ for index in get_eligible_validator_indices(state):
+ # Increase the inactivity score of inactive validators
+ if index in get_unslashed_participating_indices(
+ state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state)
+ ):
+ state.inactivity_scores[index] -= min(1, state.inactivity_scores[index])
+ else:
+ state.inactivity_scores[index] += INACTIVITY_SCORE_BIAS
+ # Decrease the inactivity score of all eligible validators during a leak-free epoch
+ if not is_in_inactivity_leak(state):
+ state.inactivity_scores[index] -= min(
+ INACTIVITY_SCORE_RECOVERY_RATE, state.inactivity_scores[index]
+ )
+
+
+- name: process_justification_and_finalization#phase0
+ sources:
+ - file: beacon-chain/core/epoch/precompute/justification_finalization.go
+ search: func ProcessJustificationAndFinalizationPreCompute(
+ spec: |
+
+ def process_justification_and_finalization(state: BeaconState) -> None:
+ # Initial FFG checkpoint values have a `0x00` stub for `root`.
+ # Skip FFG updates in the first two epochs to avoid corner cases that might result in modifying this stub.
+ if get_current_epoch(state) <= GENESIS_EPOCH + 1:
+ return
+ previous_attestations = get_matching_target_attestations(state, get_previous_epoch(state))
+ current_attestations = get_matching_target_attestations(state, get_current_epoch(state))
+ total_active_balance = get_total_active_balance(state)
+ previous_target_balance = get_attesting_balance(state, previous_attestations)
+ current_target_balance = get_attesting_balance(state, current_attestations)
+ weigh_justification_and_finalization(
+ state, total_active_balance, previous_target_balance, current_target_balance
+ )
+
+
+- name: process_justification_and_finalization#altair
+ sources:
+ - file: beacon-chain/core/epoch/precompute/justification_finalization.go
+ search: func ProcessJustificationAndFinalizationPreCompute(
+ spec: |
+
+ def process_justification_and_finalization(state: BeaconState) -> None:
+ # Initial FFG checkpoint values have a `0x00` stub for `root`.
+ # Skip FFG updates in the first two epochs to avoid corner cases that might result in modifying this stub.
+ if get_current_epoch(state) <= GENESIS_EPOCH + 1:
+ return
+ previous_indices = get_unslashed_participating_indices(
+ state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state)
+ )
+ current_indices = get_unslashed_participating_indices(
+ state, TIMELY_TARGET_FLAG_INDEX, get_current_epoch(state)
+ )
+ total_active_balance = get_total_active_balance(state)
+ previous_target_balance = get_total_balance(state, previous_indices)
+ current_target_balance = get_total_balance(state, current_indices)
+ weigh_justification_and_finalization(
+ state, total_active_balance, previous_target_balance, current_target_balance
+ )
+
+
+- name: process_light_client_finality_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientFinalityUpdateFromBeaconState(
+ spec: |
+
+ def process_light_client_finality_update(
+ store: LightClientStore,
+ finality_update: LightClientFinalityUpdate,
+ current_slot: Slot,
+ genesis_validators_root: Root,
+ ) -> None:
+ update = LightClientUpdate(
+ attested_header=finality_update.attested_header,
+ next_sync_committee=SyncCommittee(),
+ next_sync_committee_branch=NextSyncCommitteeBranch(),
+ finalized_header=finality_update.finalized_header,
+ finality_branch=finality_update.finality_branch,
+ sync_aggregate=finality_update.sync_aggregate,
+ signature_slot=finality_update.signature_slot,
+ )
+ process_light_client_update(store, update, current_slot, genesis_validators_root)
+
+
+- name: process_light_client_optimistic_update
+ sources:
+ - file: beacon-chain/core/light-client/lightclient.go
+ search: func NewLightClientOptimisticUpdateFromBeaconState(
+ spec: |
+
+ def process_light_client_optimistic_update(
+ store: LightClientStore,
+ optimistic_update: LightClientOptimisticUpdate,
+ current_slot: Slot,
+ genesis_validators_root: Root,
+ ) -> None:
+ update = LightClientUpdate(
+ attested_header=optimistic_update.attested_header,
+ next_sync_committee=SyncCommittee(),
+ next_sync_committee_branch=NextSyncCommitteeBranch(),
+ finalized_header=LightClientHeader(),
+ finality_branch=FinalityBranch(),
+ sync_aggregate=optimistic_update.sync_aggregate,
+ signature_slot=optimistic_update.signature_slot,
+ )
+ process_light_client_update(store, update, current_slot, genesis_validators_root)
+
+
+- name: process_light_client_store_force_update
+ sources: []
+ spec: |
+
+ def process_light_client_store_force_update(store: LightClientStore, current_slot: Slot) -> None:
+ if (
+ current_slot > store.finalized_header.beacon.slot + UPDATE_TIMEOUT
+ and store.best_valid_update is not None
+ ):
+ # Forced best update when the update timeout has elapsed.
+ # Because the apply logic waits for `finalized_header.beacon.slot` to indicate sync committee finality,
+ # the `attested_header` may be treated as `finalized_header` in extended periods of non-finality
+ # to guarantee progression into later sync committee periods according to `is_better_update`.
+ if (
+ store.best_valid_update.finalized_header.beacon.slot
+ <= store.finalized_header.beacon.slot
+ ):
+ store.best_valid_update.finalized_header = store.best_valid_update.attested_header
+ apply_light_client_update(store, store.best_valid_update)
+ store.best_valid_update = None
+
+
+- name: process_light_client_update
+ sources: []
+ spec: |
+
+ def process_light_client_update(
+ store: LightClientStore,
+ update: LightClientUpdate,
+ current_slot: Slot,
+ genesis_validators_root: Root,
+ ) -> None:
+ validate_light_client_update(store, update, current_slot, genesis_validators_root)
+
+ sync_committee_bits = update.sync_aggregate.sync_committee_bits
+
+ # Update the best update in case we have to force-update to it if the timeout elapses
+ if store.best_valid_update is None or is_better_update(update, store.best_valid_update):
+ store.best_valid_update = update
+
+ # 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),
+ )
+
+ # Update the optimistic header
+ if (
+ sum(sync_committee_bits) > get_safety_threshold(store)
+ and update.attested_header.beacon.slot > store.optimistic_header.beacon.slot
+ ):
+ store.optimistic_header = update.attested_header
+
+ # Update finalized header
+ update_has_finalized_next_sync_committee = (
+ not is_next_sync_committee_known(store)
+ and is_sync_committee_update(update)
+ and is_finality_update(update)
+ and (
+ compute_sync_committee_period_at_slot(update.finalized_header.beacon.slot)
+ == compute_sync_committee_period_at_slot(update.attested_header.beacon.slot)
+ )
+ )
+ if sum(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
+ ):
+ # Normal update through 2/3 threshold
+ apply_light_client_update(store, update)
+ store.best_valid_update = None
+
+
+- name: process_operations#phase0
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessOperationsNoVerifyAttsSigs(
+ spec: |
+
+ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
+ # Verify that outstanding deposits are processed up to the maximum number of deposits
+ assert len(body.deposits) == min(
+ MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index
+ )
+
+ def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
+ for operation in operations:
+ fn(state, operation)
+
+ for_ops(body.proposer_slashings, process_proposer_slashing)
+ for_ops(body.attester_slashings, process_attester_slashing)
+ for_ops(body.attestations, process_attestation)
+ for_ops(body.deposits, process_deposit)
+ for_ops(body.voluntary_exits, process_voluntary_exit)
+
+
+- name: process_operations#capella
+ sources:
+ - file: beacon-chain/core/transition/transition_no_verify_sig.go
+ search: func ProcessOperationsNoVerifyAttsSigs(
+ spec: |
+
+ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
+ # Verify that outstanding deposits are processed up to the maximum number of deposits
+ assert len(body.deposits) == min(
+ MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index
+ )
+
+ def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
+ for operation in operations:
+ fn(state, operation)
+
+ for_ops(body.proposer_slashings, process_proposer_slashing)
+ for_ops(body.attester_slashings, process_attester_slashing)
+ for_ops(body.attestations, process_attestation)
+ for_ops(body.deposits, process_deposit)
+ for_ops(body.voluntary_exits, process_voluntary_exit)
+ # [New in Capella]
+ for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
+
+
+- name: process_operations#electra
+ sources:
+ - file: beacon-chain/core/electra/transition_no_verify_sig.go
+ search: func ProcessOperations(
+ spec: |
+
+ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
+ # [Modified in Electra:EIP6110]
+ # Disable former deposit mechanism once all prior deposits are processed
+ eth1_deposit_index_limit = min(
+ state.eth1_data.deposit_count, state.deposit_requests_start_index
+ )
+ if state.eth1_deposit_index < eth1_deposit_index_limit:
+ assert len(body.deposits) == min(
+ MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index
+ )
+ else:
+ assert len(body.deposits) == 0
+
+ def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
+ for operation in operations:
+ fn(state, operation)
+
+ for_ops(body.proposer_slashings, process_proposer_slashing)
+ for_ops(body.attester_slashings, process_attester_slashing)
+ # [Modified in Electra:EIP7549]
+ for_ops(body.attestations, process_attestation)
+ for_ops(body.deposits, process_deposit)
+ # [Modified in Electra:EIP7251]
+ for_ops(body.voluntary_exits, process_voluntary_exit)
+ for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
+ # [New in Electra:EIP6110]
+ for_ops(body.execution_requests.deposits, process_deposit_request)
+ # [New in Electra:EIP7002:EIP7251]
+ for_ops(body.execution_requests.withdrawals, process_withdrawal_request)
+ # [New in Electra:EIP7251]
+ for_ops(body.execution_requests.consolidations, process_consolidation_request)
+
+
+- name: process_participation_flag_updates
+ sources:
+ - 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 = [
+ ParticipationFlags(0b0000_0000) for _ in range(len(state.validators))
+ ]
+
+
+- name: process_participation_record_updates
+ sources:
+ - 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 = []
+
+
+- name: process_pending_consolidations
+ sources:
+ - 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
+ for pending_consolidation in state.pending_consolidations:
+ source_validator = state.validators[pending_consolidation.source_index]
+ if source_validator.slashed:
+ next_pending_consolidation += 1
+ continue
+ if source_validator.withdrawable_epoch > next_epoch:
+ break
+
+ # Calculate the consolidated balance
+ source_effective_balance = min(
+ state.balances[pending_consolidation.source_index], source_validator.effective_balance
+ )
+
+ # Move active balance to target. Excess balance is withdrawable.
+ decrease_balance(state, pending_consolidation.source_index, source_effective_balance)
+ increase_balance(state, pending_consolidation.target_index, source_effective_balance)
+ next_pending_consolidation += 1
+
+ state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:]
+
+
+- name: process_pending_deposits
+ sources:
+ - 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(
+ state
+ )
+ processed_amount = 0
+ next_deposit_index = 0
+ deposits_to_postpone = []
+ is_churn_limit_reached = False
+ finalized_slot = compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
+
+ for deposit in state.pending_deposits:
+ # Do not process deposit requests if Eth1 bridge deposits are not yet applied.
+ if (
+ # Is deposit request
+ deposit.slot > GENESIS_SLOT
+ and
+ # There are pending Eth1 bridge deposits
+ state.eth1_deposit_index < state.deposit_requests_start_index
+ ):
+ break
+
+ # Check if deposit has been finalized, otherwise, stop processing.
+ if deposit.slot > finalized_slot:
+ break
+
+ # Check if number of processed deposits has not reached the limit, otherwise, stop processing.
+ if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH:
+ break
+
+ # Read validator state
+ is_validator_exited = False
+ is_validator_withdrawn = False
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ if deposit.pubkey in validator_pubkeys:
+ validator = state.validators[ValidatorIndex(validator_pubkeys.index(deposit.pubkey))]
+ is_validator_exited = validator.exit_epoch < FAR_FUTURE_EPOCH
+ is_validator_withdrawn = validator.withdrawable_epoch < next_epoch
+
+ if is_validator_withdrawn:
+ # Deposited balance will never become active. Increase balance but do not consume churn
+ apply_pending_deposit(state, deposit)
+ elif is_validator_exited:
+ # Validator is exiting, postpone the deposit until after withdrawable epoch
+ deposits_to_postpone.append(deposit)
+ else:
+ # Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch.
+ is_churn_limit_reached = processed_amount + deposit.amount > available_for_processing
+ if is_churn_limit_reached:
+ break
+
+ # Consume churn and apply deposit.
+ processed_amount += deposit.amount
+ apply_pending_deposit(state, deposit)
+
+ # 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
+
+ # Accumulate churn only if the churn limit has been hit.
+ if is_churn_limit_reached:
+ state.deposit_balance_to_consume = available_for_processing - processed_amount
+ else:
+ state.deposit_balance_to_consume = Gwei(0)
+
+
+- name: process_proposer_lookahead
+ sources:
+ - file: beacon-chain/core/fulu/transition.go
+ search: func processProposerLookahead(
+ spec: |
+
+ def process_proposer_lookahead(state: BeaconState) -> None:
+ last_epoch_start = len(state.proposer_lookahead) - SLOTS_PER_EPOCH
+ # Shift out proposers in the first epoch
+ state.proposer_lookahead[:last_epoch_start] = state.proposer_lookahead[SLOTS_PER_EPOCH:]
+ # Fill in the last epoch with new proposer indices
+ last_epoch_proposers = get_beacon_proposer_indices(
+ state, Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD + 1)
+ )
+ state.proposer_lookahead[last_epoch_start:] = last_epoch_proposers
+
+
+- name: process_proposer_slashing
+ sources:
+ - file: beacon-chain/core/blocks/proposer_slashing.go
+ search: func ProcessProposerSlashing(
+ spec: |
+
+ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
+ header_1 = proposer_slashing.signed_header_1.message
+ header_2 = proposer_slashing.signed_header_2.message
+
+ # Verify header slots match
+ assert header_1.slot == header_2.slot
+ # Verify header proposer indices match
+ assert header_1.proposer_index == header_2.proposer_index
+ # Verify the headers are different
+ assert header_1 != header_2
+ # Verify the proposer is slashable
+ proposer = state.validators[header_1.proposer_index]
+ assert is_slashable_validator(proposer, get_current_epoch(state))
+ # Verify signatures
+ for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2):
+ domain = get_domain(
+ state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)
+ )
+ signing_root = compute_signing_root(signed_header.message, domain)
+ assert bls.Verify(proposer.pubkey, signing_root, signed_header.signature)
+
+ slash_validator(state, header_1.proposer_index)
+
+
+- name: process_randao
+ sources:
+ - file: beacon-chain/core/blocks/randao.go
+ search: func ProcessRandao(
+ spec: |
+
+ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
+ epoch = get_current_epoch(state)
+ # Verify RANDAO reveal
+ proposer = state.validators[get_beacon_proposer_index(state)]
+ signing_root = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO))
+ assert bls.Verify(proposer.pubkey, signing_root, body.randao_reveal)
+ # Mix in RANDAO reveal
+ mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
+ state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
+
+
+- name: process_randao_mixes_reset
+ sources:
+ - file: beacon-chain/core/epoch/epoch_processing.go
+ search: func ProcessRandaoMixesReset(
+ spec: |
+
+ def process_randao_mixes_reset(state: BeaconState) -> None:
+ current_epoch = get_current_epoch(state)
+ next_epoch = Epoch(current_epoch + 1)
+ # Set randao mix
+ state.randao_mixes[next_epoch % EPOCHS_PER_HISTORICAL_VECTOR] = get_randao_mix(
+ state, current_epoch
+ )
+
+
+- name: process_registry_updates#phase0
+ sources:
+ - file: beacon-chain/core/epoch/epoch_processing.go
+ search: func ProcessRegistryUpdates(
+ spec: |
+
+ def process_registry_updates(state: BeaconState) -> None:
+ # Process activation eligibility and ejections
+ for index, validator in enumerate(state.validators):
+ if is_eligible_for_activation_queue(validator):
+ validator.activation_eligibility_epoch = get_current_epoch(state) + 1
+
+ if (
+ is_active_validator(validator, get_current_epoch(state))
+ and validator.effective_balance <= EJECTION_BALANCE
+ ):
+ initiate_validator_exit(state, ValidatorIndex(index))
+
+ # Queue validators eligible for activation and not yet dequeued for activation
+ activation_queue = sorted(
+ [
+ index
+ for index, validator in enumerate(state.validators)
+ if is_eligible_for_activation(state, validator)
+ ],
+ # Order by the sequence of activation_eligibility_epoch setting and then index
+ key=lambda index: (state.validators[index].activation_eligibility_epoch, index),
+ )
+ # Dequeued validators for activation up to churn limit
+ for index in activation_queue[: get_validator_churn_limit(state)]:
+ validator = state.validators[index]
+ validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
+
+
+- name: process_registry_updates#deneb
+ sources:
+ - file: beacon-chain/core/epoch/epoch_processing.go
+ search: func ProcessRegistryUpdates(
+ spec: |
+
+ def process_registry_updates(state: BeaconState) -> None:
+ # Process activation eligibility and ejections
+ for index, validator in enumerate(state.validators):
+ if is_eligible_for_activation_queue(validator):
+ validator.activation_eligibility_epoch = get_current_epoch(state) + 1
+
+ if (
+ is_active_validator(validator, get_current_epoch(state))
+ and validator.effective_balance <= EJECTION_BALANCE
+ ):
+ initiate_validator_exit(state, ValidatorIndex(index))
+
+ # Queue validators eligible for activation and not yet dequeued for activation
+ activation_queue = sorted(
+ [
+ index
+ for index, validator in enumerate(state.validators)
+ if is_eligible_for_activation(state, validator)
+ ],
+ # Order by the sequence of activation_eligibility_epoch setting and then index
+ key=lambda index: (state.validators[index].activation_eligibility_epoch, index),
+ )
+ # Dequeued validators for activation up to activation churn limit
+ # [Modified in Deneb:EIP7514]
+ for index in activation_queue[: get_validator_activation_churn_limit(state)]:
+ validator = state.validators[index]
+ validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
+
+
+- name: process_registry_updates#electra
+ sources:
+ - file: beacon-chain/core/electra/registry_updates.go
+ search: func ProcessRegistryUpdates(
+ spec: |
+
+ def process_registry_updates(state: BeaconState) -> None:
+ current_epoch = get_current_epoch(state)
+ activation_epoch = compute_activation_exit_epoch(current_epoch)
+
+ # Process activation eligibility, ejections, and activations
+ for index, validator in enumerate(state.validators):
+ # [Modified in Electra:EIP7251]
+ if is_eligible_for_activation_queue(validator):
+ validator.activation_eligibility_epoch = current_epoch + 1
+ elif (
+ is_active_validator(validator, current_epoch)
+ and validator.effective_balance <= EJECTION_BALANCE
+ ):
+ # [Modified in Electra:EIP7251]
+ initiate_validator_exit(state, ValidatorIndex(index))
+ elif is_eligible_for_activation(state, validator):
+ validator.activation_epoch = activation_epoch
+
+
+- name: process_rewards_and_penalties#phase0
+ sources:
+ - file: beacon-chain/core/epoch/precompute/reward_penalty.go
+ search: func ProcessRewardsAndPenaltiesPrecompute(
+ spec: |
+
+ def process_rewards_and_penalties(state: BeaconState) -> None:
+ # No rewards are applied at the end of `GENESIS_EPOCH` because rewards are for work done in the previous epoch
+ if get_current_epoch(state) == GENESIS_EPOCH:
+ return
+
+ rewards, penalties = get_attestation_deltas(state)
+ for index in range(len(state.validators)):
+ increase_balance(state, ValidatorIndex(index), rewards[index])
+ decrease_balance(state, ValidatorIndex(index), penalties[index])
+
+
+- name: process_rewards_and_penalties#altair
+ sources:
+ - file: beacon-chain/core/altair/epoch_precompute.go
+ search: func ProcessRewardsAndPenaltiesPrecompute(
+ spec: |
+
+ def process_rewards_and_penalties(state: BeaconState) -> None:
+ # No rewards are applied at the end of `GENESIS_EPOCH` because rewards are for work done in the previous epoch
+ if get_current_epoch(state) == GENESIS_EPOCH:
+ return
+
+ flag_deltas = [
+ get_flag_index_deltas(state, flag_index)
+ for flag_index in range(len(PARTICIPATION_FLAG_WEIGHTS))
+ ]
+ deltas = flag_deltas + [get_inactivity_penalty_deltas(state)]
+ for rewards, penalties in deltas:
+ for index in range(len(state.validators)):
+ increase_balance(state, ValidatorIndex(index), rewards[index])
+ decrease_balance(state, ValidatorIndex(index), penalties[index])
+
+
+- name: process_slashings#phase0
+ sources:
+ - 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)
+ adjusted_total_slashing_balance = min(
+ sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER, total_balance
+ )
+ for index, validator in enumerate(state.validators):
+ if (
+ 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
+ penalty_numerator = (
+ validator.effective_balance // increment * adjusted_total_slashing_balance
+ )
+ penalty = penalty_numerator // total_balance * increment
+ decrease_balance(state, ValidatorIndex(index), penalty)
+
+
+- name: process_slashings#altair
+ sources:
+ - 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)
+ adjusted_total_slashing_balance = min(
+ sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR, total_balance
+ )
+ for index, validator in enumerate(state.validators):
+ if (
+ 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
+ penalty_numerator = (
+ validator.effective_balance // increment * adjusted_total_slashing_balance
+ )
+ penalty = penalty_numerator // total_balance * increment
+ decrease_balance(state, ValidatorIndex(index), penalty)
+
+
+- name: process_slashings#bellatrix
+ sources:
+ - 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)
+ adjusted_total_slashing_balance = min(
+ sum(state.slashings)
+ # [Modified in Bellatrix]
+ * PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX,
+ total_balance,
+ )
+ for index, validator in enumerate(state.validators):
+ if (
+ 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
+ penalty_numerator = (
+ validator.effective_balance // increment * adjusted_total_slashing_balance
+ )
+ penalty = penalty_numerator // total_balance * increment
+ decrease_balance(state, ValidatorIndex(index), penalty)
+
+
+- name: process_slashings#electra
+ sources:
+ - 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)
+ adjusted_total_slashing_balance = min(
+ sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, total_balance
+ )
+ increment = (
+ EFFECTIVE_BALANCE_INCREMENT # Factored out from total balance to avoid uint64 overflow
+ )
+ penalty_per_effective_balance_increment = adjusted_total_slashing_balance // (
+ total_balance // increment
+ )
+ for index, validator in enumerate(state.validators):
+ if (
+ validator.slashed
+ and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch
+ ):
+ effective_balance_increments = validator.effective_balance // increment
+ # [Modified in Electra:EIP7251]
+ penalty = penalty_per_effective_balance_increment * effective_balance_increments
+ decrease_balance(state, ValidatorIndex(index), penalty)
+
+
+- name: process_slashings_reset
+ sources:
+ - file: beacon-chain/core/epoch/epoch_processing.go
+ search: func ProcessSlashingsReset(
+ spec: |
+
+ def process_slashings_reset(state: BeaconState) -> None:
+ next_epoch = Epoch(get_current_epoch(state) + 1)
+ # Reset slashings
+ state.slashings[next_epoch % EPOCHS_PER_SLASHINGS_VECTOR] = Gwei(0)
+
+
+- name: process_slot
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessSlot(
+ spec: |
+
+ def process_slot(state: BeaconState) -> None:
+ # Cache state root
+ previous_state_root = hash_tree_root(state)
+ state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
+ # Cache latest block header state root
+ if state.latest_block_header.state_root == Bytes32():
+ state.latest_block_header.state_root = previous_state_root
+ # Cache block root
+ previous_block_root = hash_tree_root(state.latest_block_header)
+ state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
+
+
+- name: process_slots
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ProcessSlots(
+ spec: |
+
+ def process_slots(state: BeaconState, slot: Slot) -> None:
+ assert state.slot < slot
+ while state.slot < slot:
+ process_slot(state)
+ # Process epoch on the start slot of the next epoch
+ if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
+ process_epoch(state)
+ state.slot = Slot(state.slot + 1)
+
+
+- name: process_sync_aggregate
+ sources:
+ - 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
+ participant_pubkeys = [
+ pubkey for pubkey, bit in zip(committee_pubkeys, sync_aggregate.sync_committee_bits) if bit
+ ]
+ previous_slot = max(state.slot, Slot(1)) - Slot(1)
+ domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot))
+ signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain)
+ assert eth_fast_aggregate_verify(
+ participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature
+ )
+
+ # Compute participant and proposer rewards
+ total_active_increments = get_total_active_balance(state) // EFFECTIVE_BALANCE_INCREMENT
+ total_base_rewards = Gwei(get_base_reward_per_increment(state) * total_active_increments)
+ max_participant_rewards = Gwei(
+ total_base_rewards * SYNC_REWARD_WEIGHT // WEIGHT_DENOMINATOR // SLOTS_PER_EPOCH
+ )
+ participant_reward = Gwei(max_participant_rewards // SYNC_COMMITTEE_SIZE)
+ proposer_reward = Gwei(
+ participant_reward * PROPOSER_WEIGHT // (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)
+ )
+
+ # Apply participant and proposer rewards
+ all_pubkeys = [v.pubkey for v in state.validators]
+ committee_indices = [
+ ValidatorIndex(all_pubkeys.index(pubkey)) for pubkey in state.current_sync_committee.pubkeys
+ ]
+ for participant_index, participation_bit in zip(
+ committee_indices, sync_aggregate.sync_committee_bits
+ ):
+ if participation_bit:
+ increase_balance(state, participant_index, participant_reward)
+ increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
+ else:
+ decrease_balance(state, participant_index, participant_reward)
+
+
+- name: process_sync_committee_contributions
+ sources: []
+ spec: |
+
+ def process_sync_committee_contributions(
+ block: BeaconBlock, contributions: Set[SyncCommitteeContribution]
+ ) -> None:
+ sync_aggregate = SyncAggregate()
+ signatures = []
+ sync_subcommittee_size = SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT
+
+ for contribution in contributions:
+ subcommittee_index = contribution.subcommittee_index
+ for index, participated in enumerate(contribution.aggregation_bits):
+ if participated:
+ participant_index = sync_subcommittee_size * subcommittee_index + index
+ sync_aggregate.sync_committee_bits[participant_index] = True
+ signatures.append(contribution.signature)
+
+ sync_aggregate.sync_committee_signature = bls.Aggregate(signatures)
+
+ block.body.sync_aggregate = sync_aggregate
+
+
+- name: process_sync_committee_updates
+ sources:
+ - file: beacon-chain/core/altair/epoch_spec.go
+ search: func ProcessSyncCommitteeUpdates(
+ spec: |
+
+ def process_sync_committee_updates(state: BeaconState) -> None:
+ next_epoch = get_current_epoch(state) + Epoch(1)
+ if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
+ state.current_sync_committee = state.next_sync_committee
+ state.next_sync_committee = get_next_sync_committee(state)
+
+
+- name: process_voluntary_exit#phase0
+ sources:
+ - file: beacon-chain/core/blocks/exit.go
+ search: func ProcessVoluntaryExits(
+ spec: |
+
+ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
+ voluntary_exit = signed_voluntary_exit.message
+ validator = state.validators[voluntary_exit.validator_index]
+ # Verify the validator is active
+ assert is_active_validator(validator, get_current_epoch(state))
+ # Verify exit has not been initiated
+ assert validator.exit_epoch == FAR_FUTURE_EPOCH
+ # Exits must specify an epoch when they become valid; they are not valid before then
+ assert get_current_epoch(state) >= voluntary_exit.epoch
+ # Verify the validator has been active long enough
+ assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
+ # Verify signature
+ domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
+ signing_root = compute_signing_root(voluntary_exit, domain)
+ assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
+ # Initiate exit
+ initiate_validator_exit(state, voluntary_exit.validator_index)
+
+
+- name: process_voluntary_exit#deneb
+ sources:
+ - file: beacon-chain/core/blocks/exit.go
+ search: func ProcessVoluntaryExits(
+ spec: |
+
+ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
+ voluntary_exit = signed_voluntary_exit.message
+ validator = state.validators[voluntary_exit.validator_index]
+ # Verify the validator is active
+ assert is_active_validator(validator, get_current_epoch(state))
+ # Verify exit has not been initiated
+ assert validator.exit_epoch == FAR_FUTURE_EPOCH
+ # Exits must specify an epoch when they become valid; they are not valid before then
+ assert get_current_epoch(state) >= voluntary_exit.epoch
+ # Verify the validator has been active long enough
+ assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
+ # Verify signature
+ # [Modified in Deneb:EIP7044]
+ domain = compute_domain(
+ DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root
+ )
+ signing_root = compute_signing_root(voluntary_exit, domain)
+ assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
+ # Initiate exit
+ initiate_validator_exit(state, voluntary_exit.validator_index)
+
+
+- name: process_voluntary_exit#electra
+ sources:
+ - file: beacon-chain/core/blocks/exit.go
+ search: func ProcessVoluntaryExits(
+ spec: |
+
+ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
+ voluntary_exit = signed_voluntary_exit.message
+ validator = state.validators[voluntary_exit.validator_index]
+ # Verify the validator is active
+ assert is_active_validator(validator, get_current_epoch(state))
+ # Verify exit has not been initiated
+ assert validator.exit_epoch == FAR_FUTURE_EPOCH
+ # Exits must specify an epoch when they become valid; they are not valid before then
+ assert get_current_epoch(state) >= voluntary_exit.epoch
+ # Verify the validator has been active long enough
+ assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
+ # [New in Electra:EIP7251]
+ # Only exit validator if it has no pending withdrawals in the queue
+
+ assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0
+ # Verify signature
+ domain = compute_domain(
+ DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root
+ )
+ signing_root = compute_signing_root(voluntary_exit, domain)
+ assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
+ # Initiate exit
+ initiate_validator_exit(state, voluntary_exit.validator_index)
+
+
+- name: process_withdrawal_request
+ sources:
+ - file: beacon-chain/core/electra/withdrawals.go
+ search: func ProcessWithdrawalRequests(
+ spec: |
+
+ def process_withdrawal_request(state: BeaconState, withdrawal_request: WithdrawalRequest) -> None:
+ amount = withdrawal_request.amount
+ is_full_exit_request = amount == FULL_EXIT_REQUEST_AMOUNT
+
+ # If partial withdrawal queue is full, only full exits are processed
+ if (
+ len(state.pending_partial_withdrawals) == PENDING_PARTIAL_WITHDRAWALS_LIMIT
+ and not is_full_exit_request
+ ):
+ return
+
+ validator_pubkeys = [v.pubkey for v in state.validators]
+ # Verify pubkey exists
+ request_pubkey = withdrawal_request.validator_pubkey
+ if request_pubkey not in validator_pubkeys:
+ return
+ index = ValidatorIndex(validator_pubkeys.index(request_pubkey))
+ validator = state.validators[index]
+
+ # Verify withdrawal credentials
+ has_correct_credential = has_execution_withdrawal_credential(validator)
+ is_correct_source_address = (
+ validator.withdrawal_credentials[12:] == withdrawal_request.source_address
+ )
+ if not (has_correct_credential and is_correct_source_address):
+ return
+ # Verify the validator is active
+ if not is_active_validator(validator, get_current_epoch(state)):
+ return
+ # Verify exit has not been initiated
+ if validator.exit_epoch != FAR_FUTURE_EPOCH:
+ return
+ # Verify the validator has been active long enough
+ if get_current_epoch(state) < validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
+ return
+
+ pending_balance_to_withdraw = get_pending_balance_to_withdraw(state, index)
+
+ if is_full_exit_request:
+ # Only exit validator if it has no pending withdrawals in the queue
+ if pending_balance_to_withdraw == 0:
+ initiate_validator_exit(state, index)
+ return
+
+ has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
+ has_excess_balance = (
+ state.balances[index] > MIN_ACTIVATION_BALANCE + pending_balance_to_withdraw
+ )
+
+ # Only allow partial withdrawals with compounding withdrawal credentials
+ if (
+ has_compounding_withdrawal_credential(validator)
+ and has_sufficient_effective_balance
+ and has_excess_balance
+ ):
+ to_withdraw = min(
+ state.balances[index] - MIN_ACTIVATION_BALANCE - pending_balance_to_withdraw, amount
+ )
+ exit_queue_epoch = compute_exit_epoch_and_update_churn(state, to_withdraw)
+ withdrawable_epoch = Epoch(exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
+ state.pending_partial_withdrawals.append(
+ PendingPartialWithdrawal(
+ validator_index=index,
+ amount=to_withdraw,
+ withdrawable_epoch=withdrawable_epoch,
+ )
+ )
+
+
+- name: process_withdrawals#capella
+ sources:
+ - file: beacon-chain/core/blocks/withdrawals.go
+ search: func ProcessWithdrawals(
+ spec: |
+
+ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
+ expected_withdrawals = get_expected_withdrawals(state)
+ assert payload.withdrawals == expected_withdrawals
+
+ for withdrawal in expected_withdrawals:
+ decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
+
+ # Update the next withdrawal index if this block contained withdrawals
+ if len(expected_withdrawals) != 0:
+ latest_withdrawal = expected_withdrawals[-1]
+ state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
+
+ # Update the next validator index to start the next withdrawal sweep
+ if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
+ # Next sweep starts after the latest withdrawal's validator index
+ next_validator_index = ValidatorIndex(
+ (expected_withdrawals[-1].validator_index + 1) % len(state.validators)
+ )
+ state.next_withdrawal_validator_index = next_validator_index
+ else:
+ # Advance sweep by the max length of the sweep if there was not a full set of withdrawals
+ next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
+ next_validator_index = ValidatorIndex(next_index % len(state.validators))
+ state.next_withdrawal_validator_index = next_validator_index
+
+
+- name: process_withdrawals#electra
+ sources:
+ - file: beacon-chain/core/blocks/withdrawals.go
+ search: func ProcessWithdrawals(
+ spec: |
+
+ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
+ # [Modified in Electra:EIP7251]
+ expected_withdrawals, processed_partial_withdrawals_count = get_expected_withdrawals(state)
+
+ assert payload.withdrawals == expected_withdrawals
+
+ for withdrawal in expected_withdrawals:
+ decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
+
+ # [New in Electra:EIP7251] Update pending partial withdrawals
+ state.pending_partial_withdrawals = state.pending_partial_withdrawals[
+ processed_partial_withdrawals_count:
+ ]
+
+ # Update the next withdrawal index if this block contained withdrawals
+ if len(expected_withdrawals) != 0:
+ latest_withdrawal = expected_withdrawals[-1]
+ state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
+
+ # Update the next validator index to start the next withdrawal sweep
+ if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
+ # Next sweep starts after the latest withdrawal's validator index
+ next_validator_index = ValidatorIndex(
+ (expected_withdrawals[-1].validator_index + 1) % len(state.validators)
+ )
+ state.next_withdrawal_validator_index = next_validator_index
+ else:
+ # Advance sweep by the max length of the sweep if there was not a full set of withdrawals
+ next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
+ next_validator_index = ValidatorIndex(next_index % len(state.validators))
+ state.next_withdrawal_validator_index = next_validator_index
+
+
+- name: queue_excess_active_balance
+ sources:
+ - file: beacon-chain/core/electra/validator.go
+ search: func QueueExcessActiveBalance(
+ spec: |
+
+ def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> None:
+ balance = state.balances[index]
+ if balance > MIN_ACTIVATION_BALANCE:
+ excess_balance = balance - MIN_ACTIVATION_BALANCE
+ state.balances[index] = MIN_ACTIVATION_BALANCE
+ validator = state.validators[index]
+ # Use bls.G2_POINT_AT_INFINITY as a signature field placeholder
+ # and GENESIS_SLOT to distinguish from a pending deposit request
+ state.pending_deposits.append(
+ PendingDeposit(
+ pubkey=validator.pubkey,
+ withdrawal_credentials=validator.withdrawal_credentials,
+ amount=excess_balance,
+ signature=bls.G2_POINT_AT_INFINITY,
+ slot=GENESIS_SLOT,
+ )
+ )
+
+
+- name: recover_matrix
+ sources: []
+ spec: |
+
+ def recover_matrix(
+ 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``.
+ 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)
+ for cell_index, (cell, proof) in enumerate(zip(recovered_cells, recovered_proofs)):
+ matrix.append(
+ MatrixEntry(
+ cell=cell,
+ kzg_proof=proof,
+ row_index=blob_index,
+ column_index=cell_index,
+ )
+ )
+ return matrix
+
+
+- name: saturating_sub
+ sources:
+ - file: consensus-types/primitives/slot.go
+ search: func (s Slot) SafeSub(
+ spec: |
+
+ def saturating_sub(a: int, b: int) -> int:
+ """
+ Computes a - b, saturating at numeric bounds.
+ """
+ return a - b if a > b else 0
+
+
+- name: set_or_append_list
+ sources: []
+ spec: |
+
+ def set_or_append_list(list: List, index: ValidatorIndex, value: Any) -> None:
+ if index == len(list):
+ list.append(value)
+ else:
+ list[index] = value
+
+
+- name: should_override_forkchoice_update
+ sources:
+ - file: beacon-chain/forkchoice/ro.go
+ search: func (ro *ROForkChoice) ShouldOverrideFCU(
+ spec: |
+
+ def should_override_forkchoice_update(store: Store, head_root: Root) -> bool:
+ head_block = store.blocks[head_root]
+ parent_root = head_block.parent_root
+ parent_block = store.blocks[parent_root]
+ current_slot = get_current_slot(store)
+ proposal_slot = head_block.slot + Slot(1)
+
+ # Only re-org the head_block block if it arrived later than the attestation deadline.
+ head_late = is_head_late(store, head_root)
+
+ # Shuffling stable.
+ shuffling_stable = is_shuffling_stable(proposal_slot)
+
+ # FFG information of the new head_block will be competitive with the current head.
+ ffg_competitive = is_ffg_competitive(store, head_root, parent_root)
+
+ # Do not re-org if the chain is not finalizing with acceptable frequency.
+ finalization_ok = is_finalization_ok(store, proposal_slot)
+
+ # Only suppress the fork choice update if we are confident that we will propose the next block.
+ parent_state_advanced = store.block_states[parent_root].copy()
+ process_slots(parent_state_advanced, proposal_slot)
+ proposer_index = get_beacon_proposer_index(parent_state_advanced)
+ proposing_reorg_slot = validator_is_connected(proposer_index)
+
+ # Single slot re-org.
+ parent_slot_ok = parent_block.slot + 1 == head_block.slot
+ proposing_on_time = is_proposing_on_time(store)
+
+ # Note that this condition is different from `get_proposer_head`
+ current_time_ok = head_block.slot == current_slot or (
+ proposal_slot == current_slot and proposing_on_time
+ )
+ single_slot_reorg = parent_slot_ok and current_time_ok
+
+ # Check the head weight only if the attestations from the head slot have already been applied.
+ # Implementations may want to do this in different ways, e.g. by advancing
+ # `store.time` early, or by counting queued attestations during the head block's slot.
+ if current_slot > head_block.slot:
+ head_weak = is_head_weak(store, head_root)
+ parent_strong = is_parent_strong(store, parent_root)
+ else:
+ head_weak = True
+ parent_strong = True
+
+ return all(
+ [
+ head_late,
+ shuffling_stable,
+ ffg_competitive,
+ finalization_ok,
+ proposing_reorg_slot,
+ single_slot_reorg,
+ head_weak,
+ parent_strong,
+ ]
+ )
+
+
+- name: slash_validator#phase0
+ sources:
+ - file: beacon-chain/core/validators/validator.go
+ search: func SlashValidator(
+ spec: |
+
+ def slash_validator(
+ state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex = None
+ ) -> None:
+ """
+ Slash the validator with index ``slashed_index``.
+ """
+ epoch = get_current_epoch(state)
+ initiate_validator_exit(state, slashed_index)
+ validator = state.validators[slashed_index]
+ validator.slashed = True
+ validator.withdrawable_epoch = max(
+ validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR)
+ )
+ state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
+ decrease_balance(
+ state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT
+ )
+
+ # Apply proposer and whistleblower rewards
+ proposer_index = get_beacon_proposer_index(state)
+ if whistleblower_index is None:
+ whistleblower_index = proposer_index
+ whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
+ proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
+ increase_balance(state, proposer_index, proposer_reward)
+ increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
+
+
+- name: slash_validator#altair
+ sources:
+ - file: beacon-chain/core/validators/validator.go
+ search: func SlashValidator(
+ spec: |
+
+ def slash_validator(
+ state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex = None
+ ) -> None:
+ """
+ Slash the validator with index ``slashed_index``.
+ """
+ epoch = get_current_epoch(state)
+ initiate_validator_exit(state, slashed_index)
+ validator = state.validators[slashed_index]
+ validator.slashed = True
+ validator.withdrawable_epoch = max(
+ validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR)
+ )
+ state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
+ decrease_balance(
+ state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
+ )
+
+ # Apply proposer and whistleblower rewards
+ proposer_index = get_beacon_proposer_index(state)
+ if whistleblower_index is None:
+ whistleblower_index = proposer_index
+ whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
+ proposer_reward = Gwei(whistleblower_reward * PROPOSER_WEIGHT // WEIGHT_DENOMINATOR)
+ increase_balance(state, proposer_index, proposer_reward)
+ increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
+
+
+- name: slash_validator#bellatrix
+ sources:
+ - file: beacon-chain/core/validators/validator.go
+ search: func SlashValidator(
+ spec: |
+
+ def slash_validator(
+ state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex = None
+ ) -> None:
+ """
+ Slash the validator with index ``slashed_index``.
+ """
+ epoch = get_current_epoch(state)
+ initiate_validator_exit(state, slashed_index)
+ validator = state.validators[slashed_index]
+ validator.slashed = True
+ validator.withdrawable_epoch = max(
+ validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR)
+ )
+ state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
+ # [Modified in Bellatrix]
+ slashing_penalty = validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX
+ decrease_balance(state, slashed_index, slashing_penalty)
+
+ # Apply proposer and whistleblower rewards
+ proposer_index = get_beacon_proposer_index(state)
+ if whistleblower_index is None:
+ whistleblower_index = proposer_index
+ whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
+ proposer_reward = Gwei(whistleblower_reward * PROPOSER_WEIGHT // WEIGHT_DENOMINATOR)
+ increase_balance(state, proposer_index, proposer_reward)
+ increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
+
+
+- name: slash_validator#electra
+ sources:
+ - file: beacon-chain/core/validators/validator.go
+ search: func SlashValidator(
+ spec: |
+
+ def slash_validator(
+ state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex = None
+ ) -> None:
+ """
+ Slash the validator with index ``slashed_index``.
+ """
+ epoch = get_current_epoch(state)
+ initiate_validator_exit(state, slashed_index)
+ validator = state.validators[slashed_index]
+ validator.slashed = True
+ validator.withdrawable_epoch = max(
+ validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR)
+ )
+ state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
+ # [Modified in Electra:EIP7251]
+ slashing_penalty = validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA
+ decrease_balance(state, slashed_index, slashing_penalty)
+
+ # Apply proposer and whistleblower rewards
+ proposer_index = get_beacon_proposer_index(state)
+ if whistleblower_index is None:
+ whistleblower_index = proposer_index
+ # [Modified in Electra:EIP7251]
+ whistleblower_reward = Gwei(
+ validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA
+ )
+ proposer_reward = Gwei(whistleblower_reward * PROPOSER_WEIGHT // WEIGHT_DENOMINATOR)
+ increase_balance(state, proposer_index, proposer_reward)
+ increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
+
+
+- name: state_transition
+ sources:
+ - file: beacon-chain/core/transition/transition.go
+ search: func ExecuteStateTransition(
+ spec: |
+
+ def state_transition(
+ state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool = True
+ ) -> None:
+ block = signed_block.message
+ # Process slots (including those with no blocks) since block
+ process_slots(state, block.slot)
+ # Verify signature
+ if validate_result:
+ assert verify_block_signature(state, signed_block)
+ # Process block
+ process_block(state, block)
+ # Verify state root
+ if validate_result:
+ assert block.state_root == hash_tree_root(state)
+
+
+- name: store_target_checkpoint_state
+ sources: []
+ spec: |
+
+ def store_target_checkpoint_state(store: Store, target: Checkpoint) -> None:
+ # Store target checkpoint state if not yet seen
+ if target not in store.checkpoint_states:
+ base_state = copy(store.block_states[target.root])
+ if base_state.slot < compute_start_slot_at_epoch(target.epoch):
+ process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
+ store.checkpoint_states[target] = base_state
+
+
+- name: switch_to_compounding_validator
+ sources:
+ - file: beacon-chain/core/electra/validator.go
+ search: func SwitchToCompoundingValidator(
+ spec: |
+
+ def switch_to_compounding_validator(state: BeaconState, index: ValidatorIndex) -> None:
+ validator = state.validators[index]
+ validator.withdrawal_credentials = (
+ COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
+ )
+ queue_excess_active_balance(state, index)
+
+
+- name: translate_participation
+ sources:
+ - file: beacon-chain/core/altair/upgrade.go
+ search: func TranslateParticipation(
+ spec: |
+
+ def translate_participation(
+ state: BeaconState, pending_attestations: Sequence[phase0.PendingAttestation]
+ ) -> None:
+ for attestation in pending_attestations:
+ data = attestation.data
+ inclusion_delay = attestation.inclusion_delay
+ # Translate attestation inclusion info to flag indices
+ participation_flag_indices = get_attestation_participation_flag_indices(
+ state, data, inclusion_delay
+ )
+
+ # Apply flags to all attesting validators
+ epoch_participation = state.previous_epoch_participation
+ for index in get_attesting_indices(state, attestation):
+ for flag_index in participation_flag_indices:
+ epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
+
+
+- name: update_checkpoints
+ sources:
+ - file: beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go
+ search: func (f *ForkChoice) updateCheckpoints(
+ spec: |
+
+ def update_checkpoints(
+ store: Store, justified_checkpoint: Checkpoint, finalized_checkpoint: Checkpoint
+ ) -> None:
+ """
+ Update checkpoints in store if necessary
+ """
+ # Update justified checkpoint
+ if justified_checkpoint.epoch > store.justified_checkpoint.epoch:
+ store.justified_checkpoint = justified_checkpoint
+
+ # Update finalized checkpoint
+ if finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
+ store.finalized_checkpoint = finalized_checkpoint
+
+
+- name: update_latest_messages
+ sources: []
+ spec: |
+
+ def update_latest_messages(
+ store: Store, attesting_indices: Sequence[ValidatorIndex], attestation: Attestation
+ ) -> None:
+ target = attestation.data.target
+ beacon_block_root = attestation.data.beacon_block_root
+ non_equivocating_attesting_indices = [
+ i for i in attesting_indices if i not in store.equivocating_indices
+ ]
+ for i in non_equivocating_attesting_indices:
+ if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch:
+ store.latest_messages[i] = LatestMessage(epoch=target.epoch, root=beacon_block_root)
+
+
+- name: update_unrealized_checkpoints
+ sources:
+ - file: beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification.go
+ search: func (f *ForkChoice) updateUnrealizedCheckpoints(
+ spec: |
+
+ def update_unrealized_checkpoints(
+ store: Store,
+ unrealized_justified_checkpoint: Checkpoint,
+ unrealized_finalized_checkpoint: Checkpoint,
+ ) -> None:
+ """
+ Update unrealized checkpoints in store if necessary
+ """
+ # Update unrealized justified checkpoint
+ if unrealized_justified_checkpoint.epoch > store.unrealized_justified_checkpoint.epoch:
+ store.unrealized_justified_checkpoint = unrealized_justified_checkpoint
+
+ # Update unrealized finalized checkpoint
+ if unrealized_finalized_checkpoint.epoch > store.unrealized_finalized_checkpoint.epoch:
+ store.unrealized_finalized_checkpoint = unrealized_finalized_checkpoint
+
+
+- name: upgrade_lc_bootstrap_to_capella
+ sources: []
+ spec: |
+
+ def upgrade_lc_bootstrap_to_capella(pre: bellatrix.LightClientBootstrap) -> LightClientBootstrap:
+ return LightClientBootstrap(
+ header=upgrade_lc_header_to_capella(pre.header),
+ current_sync_committee=pre.current_sync_committee,
+ current_sync_committee_branch=pre.current_sync_committee_branch,
+ )
+
+
+- name: upgrade_lc_bootstrap_to_deneb
+ sources: []
+ spec: |
+
+ def upgrade_lc_bootstrap_to_deneb(pre: capella.LightClientBootstrap) -> LightClientBootstrap:
+ return LightClientBootstrap(
+ header=upgrade_lc_header_to_deneb(pre.header),
+ current_sync_committee=pre.current_sync_committee,
+ current_sync_committee_branch=pre.current_sync_committee_branch,
+ )
+
+
+- name: upgrade_lc_bootstrap_to_electra
+ sources: []
+ spec: |
+
+ def upgrade_lc_bootstrap_to_electra(pre: deneb.LightClientBootstrap) -> LightClientBootstrap:
+ return LightClientBootstrap(
+ header=upgrade_lc_header_to_electra(pre.header),
+ current_sync_committee=pre.current_sync_committee,
+ current_sync_committee_branch=normalize_merkle_branch(
+ pre.current_sync_committee_branch, CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA
+ ),
+ )
+
+
+- name: upgrade_lc_finality_update_to_capella
+ sources: []
+ spec: |
+
+ def upgrade_lc_finality_update_to_capella(
+ pre: bellatrix.LightClientFinalityUpdate,
+ ) -> LightClientFinalityUpdate:
+ return LightClientFinalityUpdate(
+ attested_header=upgrade_lc_header_to_capella(pre.attested_header),
+ finalized_header=upgrade_lc_header_to_capella(pre.finalized_header),
+ finality_branch=pre.finality_branch,
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_finality_update_to_deneb
+ sources: []
+ spec: |
+
+ def upgrade_lc_finality_update_to_deneb(
+ pre: capella.LightClientFinalityUpdate,
+ ) -> LightClientFinalityUpdate:
+ return LightClientFinalityUpdate(
+ attested_header=upgrade_lc_header_to_deneb(pre.attested_header),
+ finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header),
+ finality_branch=pre.finality_branch,
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_finality_update_to_electra
+ sources: []
+ spec: |
+
+ def upgrade_lc_finality_update_to_electra(
+ pre: deneb.LightClientFinalityUpdate,
+ ) -> LightClientFinalityUpdate:
+ return LightClientFinalityUpdate(
+ attested_header=upgrade_lc_header_to_electra(pre.attested_header),
+ finalized_header=upgrade_lc_header_to_electra(pre.finalized_header),
+ finality_branch=normalize_merkle_branch(pre.finality_branch, FINALIZED_ROOT_GINDEX_ELECTRA),
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_header_to_capella
+ sources: []
+ spec: |
+
+ def upgrade_lc_header_to_capella(pre: bellatrix.LightClientHeader) -> LightClientHeader:
+ return LightClientHeader(
+ beacon=pre.beacon,
+ )
+
+
+- name: upgrade_lc_header_to_deneb
+ sources: []
+ spec: |
+
+ def upgrade_lc_header_to_deneb(pre: capella.LightClientHeader) -> LightClientHeader:
+ return LightClientHeader(
+ beacon=pre.beacon,
+ execution=ExecutionPayloadHeader(
+ parent_hash=pre.execution.parent_hash,
+ fee_recipient=pre.execution.fee_recipient,
+ state_root=pre.execution.state_root,
+ receipts_root=pre.execution.receipts_root,
+ logs_bloom=pre.execution.logs_bloom,
+ prev_randao=pre.execution.prev_randao,
+ block_number=pre.execution.block_number,
+ gas_limit=pre.execution.gas_limit,
+ gas_used=pre.execution.gas_used,
+ timestamp=pre.execution.timestamp,
+ extra_data=pre.execution.extra_data,
+ base_fee_per_gas=pre.execution.base_fee_per_gas,
+ block_hash=pre.execution.block_hash,
+ transactions_root=pre.execution.transactions_root,
+ withdrawals_root=pre.execution.withdrawals_root,
+ # [New in Deneb:EIP4844]
+ blob_gas_used=uint64(0),
+ # [New in Deneb:EIP4844]
+ excess_blob_gas=uint64(0),
+ ),
+ execution_branch=pre.execution_branch,
+ )
+
+
+- name: upgrade_lc_header_to_electra
+ sources: []
+ spec: |
+
+ def upgrade_lc_header_to_electra(pre: deneb.LightClientHeader) -> LightClientHeader:
+ return LightClientHeader(
+ beacon=pre.beacon,
+ execution=pre.execution,
+ execution_branch=pre.execution_branch,
+ )
+
+
+- name: upgrade_lc_optimistic_update_to_capella
+ sources: []
+ spec: |
+
+ def upgrade_lc_optimistic_update_to_capella(
+ pre: bellatrix.LightClientOptimisticUpdate,
+ ) -> LightClientOptimisticUpdate:
+ return LightClientOptimisticUpdate(
+ attested_header=upgrade_lc_header_to_capella(pre.attested_header),
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_optimistic_update_to_deneb
+ sources: []
+ spec: |
+
+ def upgrade_lc_optimistic_update_to_deneb(
+ pre: capella.LightClientOptimisticUpdate,
+ ) -> LightClientOptimisticUpdate:
+ return LightClientOptimisticUpdate(
+ attested_header=upgrade_lc_header_to_deneb(pre.attested_header),
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_optimistic_update_to_electra
+ sources: []
+ spec: |
+
+ def upgrade_lc_optimistic_update_to_electra(
+ pre: deneb.LightClientOptimisticUpdate,
+ ) -> LightClientOptimisticUpdate:
+ return LightClientOptimisticUpdate(
+ attested_header=upgrade_lc_header_to_electra(pre.attested_header),
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_store_to_capella
+ sources: []
+ spec: |
+
+ def upgrade_lc_store_to_capella(pre: bellatrix.LightClientStore) -> LightClientStore:
+ if pre.best_valid_update is None:
+ best_valid_update = None
+ else:
+ best_valid_update = upgrade_lc_update_to_capella(pre.best_valid_update)
+ return LightClientStore(
+ finalized_header=upgrade_lc_header_to_capella(pre.finalized_header),
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ best_valid_update=best_valid_update,
+ optimistic_header=upgrade_lc_header_to_capella(pre.optimistic_header),
+ previous_max_active_participants=pre.previous_max_active_participants,
+ current_max_active_participants=pre.current_max_active_participants,
+ )
+
+
+- name: upgrade_lc_store_to_deneb
+ sources: []
+ spec: |
+
+ def upgrade_lc_store_to_deneb(pre: capella.LightClientStore) -> LightClientStore:
+ if pre.best_valid_update is None:
+ best_valid_update = None
+ else:
+ best_valid_update = upgrade_lc_update_to_deneb(pre.best_valid_update)
+ return LightClientStore(
+ finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header),
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ best_valid_update=best_valid_update,
+ optimistic_header=upgrade_lc_header_to_deneb(pre.optimistic_header),
+ previous_max_active_participants=pre.previous_max_active_participants,
+ current_max_active_participants=pre.current_max_active_participants,
+ )
+
+
+- name: upgrade_lc_store_to_electra
+ sources: []
+ spec: |
+
+ def upgrade_lc_store_to_electra(pre: deneb.LightClientStore) -> LightClientStore:
+ if pre.best_valid_update is None:
+ best_valid_update = None
+ else:
+ best_valid_update = upgrade_lc_update_to_electra(pre.best_valid_update)
+ return LightClientStore(
+ finalized_header=upgrade_lc_header_to_electra(pre.finalized_header),
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ best_valid_update=best_valid_update,
+ optimistic_header=upgrade_lc_header_to_electra(pre.optimistic_header),
+ previous_max_active_participants=pre.previous_max_active_participants,
+ current_max_active_participants=pre.current_max_active_participants,
+ )
+
+
+- name: upgrade_lc_update_to_capella
+ sources: []
+ spec: |
+
+ def upgrade_lc_update_to_capella(pre: bellatrix.LightClientUpdate) -> LightClientUpdate:
+ return LightClientUpdate(
+ attested_header=upgrade_lc_header_to_capella(pre.attested_header),
+ next_sync_committee=pre.next_sync_committee,
+ next_sync_committee_branch=pre.next_sync_committee_branch,
+ finalized_header=upgrade_lc_header_to_capella(pre.finalized_header),
+ finality_branch=pre.finality_branch,
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_update_to_deneb
+ sources: []
+ spec: |
+
+ def upgrade_lc_update_to_deneb(pre: capella.LightClientUpdate) -> LightClientUpdate:
+ return LightClientUpdate(
+ attested_header=upgrade_lc_header_to_deneb(pre.attested_header),
+ next_sync_committee=pre.next_sync_committee,
+ next_sync_committee_branch=pre.next_sync_committee_branch,
+ finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header),
+ finality_branch=pre.finality_branch,
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_lc_update_to_electra
+ sources: []
+ spec: |
+
+ def upgrade_lc_update_to_electra(pre: deneb.LightClientUpdate) -> LightClientUpdate:
+ return LightClientUpdate(
+ attested_header=upgrade_lc_header_to_electra(pre.attested_header),
+ next_sync_committee=pre.next_sync_committee,
+ next_sync_committee_branch=normalize_merkle_branch(
+ pre.next_sync_committee_branch, NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA
+ ),
+ finalized_header=upgrade_lc_header_to_electra(pre.finalized_header),
+ finality_branch=normalize_merkle_branch(pre.finality_branch, FINALIZED_ROOT_GINDEX_ELECTRA),
+ sync_aggregate=pre.sync_aggregate,
+ signature_slot=pre.signature_slot,
+ )
+
+
+- name: upgrade_to_altair
+ sources:
+ - 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(
+ genesis_time=pre.genesis_time,
+ genesis_validators_root=pre.genesis_validators_root,
+ slot=pre.slot,
+ fork=Fork(
+ previous_version=pre.fork.current_version,
+ current_version=ALTAIR_FORK_VERSION,
+ epoch=epoch,
+ ),
+ latest_block_header=pre.latest_block_header,
+ block_roots=pre.block_roots,
+ state_roots=pre.state_roots,
+ historical_roots=pre.historical_roots,
+ 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,
+ randao_mixes=pre.randao_mixes,
+ slashings=pre.slashings,
+ previous_epoch_participation=[
+ ParticipationFlags(0b0000_0000) for _ in range(len(pre.validators))
+ ],
+ current_epoch_participation=[
+ 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))],
+ )
+ # Fill in previous epoch participation from the pre state's pending attestations
+ translate_participation(post, pre.previous_epoch_attestations)
+
+ # Fill in sync committees
+ # Note: A duplicate committee is assigned for the current and next committee at the fork boundary
+ post.current_sync_committee = get_next_sync_committee(post)
+ post.next_sync_committee = get_next_sync_committee(post)
+ return post
+
+
+- name: upgrade_to_bellatrix
+ sources:
+ - file: beacon-chain/core/execution/upgrade.go
+ search: func UpgradeToBellatrix(
+ spec: |
+
+ def upgrade_to_bellatrix(pre: altair.BeaconState) -> BeaconState:
+ epoch = altair.get_current_epoch(pre)
+ post = BeaconState(
+ genesis_time=pre.genesis_time,
+ genesis_validators_root=pre.genesis_validators_root,
+ slot=pre.slot,
+ fork=Fork(
+ previous_version=pre.fork.current_version,
+ # [New in Bellatrix]
+ current_version=BELLATRIX_FORK_VERSION,
+ epoch=epoch,
+ ),
+ latest_block_header=pre.latest_block_header,
+ block_roots=pre.block_roots,
+ state_roots=pre.state_roots,
+ historical_roots=pre.historical_roots,
+ 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,
+ randao_mixes=pre.randao_mixes,
+ slashings=pre.slashings,
+ previous_epoch_participation=pre.previous_epoch_participation,
+ current_epoch_participation=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,
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ # [New in Bellatrix]
+ latest_execution_payload_header=ExecutionPayloadHeader(),
+ )
+
+ return post
+
+
+- name: upgrade_to_capella
+ sources:
+ - 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(
+ parent_hash=pre.latest_execution_payload_header.parent_hash,
+ fee_recipient=pre.latest_execution_payload_header.fee_recipient,
+ state_root=pre.latest_execution_payload_header.state_root,
+ receipts_root=pre.latest_execution_payload_header.receipts_root,
+ logs_bloom=pre.latest_execution_payload_header.logs_bloom,
+ prev_randao=pre.latest_execution_payload_header.prev_randao,
+ block_number=pre.latest_execution_payload_header.block_number,
+ gas_limit=pre.latest_execution_payload_header.gas_limit,
+ gas_used=pre.latest_execution_payload_header.gas_used,
+ timestamp=pre.latest_execution_payload_header.timestamp,
+ extra_data=pre.latest_execution_payload_header.extra_data,
+ base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas,
+ block_hash=pre.latest_execution_payload_header.block_hash,
+ transactions_root=pre.latest_execution_payload_header.transactions_root,
+ # [New in Capella]
+ withdrawals_root=Root(),
+ )
+ post = BeaconState(
+ genesis_time=pre.genesis_time,
+ genesis_validators_root=pre.genesis_validators_root,
+ slot=pre.slot,
+ fork=Fork(
+ previous_version=pre.fork.current_version,
+ current_version=CAPELLA_FORK_VERSION,
+ epoch=epoch,
+ ),
+ latest_block_header=pre.latest_block_header,
+ block_roots=pre.block_roots,
+ state_roots=pre.state_roots,
+ historical_roots=pre.historical_roots,
+ 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,
+ randao_mixes=pre.randao_mixes,
+ slashings=pre.slashings,
+ previous_epoch_participation=pre.previous_epoch_participation,
+ current_epoch_participation=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,
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ latest_execution_payload_header=latest_execution_payload_header,
+ # [New in Capella]
+ next_withdrawal_index=WithdrawalIndex(0),
+ # [New in Capella]
+ next_withdrawal_validator_index=ValidatorIndex(0),
+ # [New in Capella]
+ historical_summaries=List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT]([]),
+ )
+
+ return post
+
+
+- name: upgrade_to_deneb
+ sources:
+ - 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(
+ parent_hash=pre.latest_execution_payload_header.parent_hash,
+ fee_recipient=pre.latest_execution_payload_header.fee_recipient,
+ state_root=pre.latest_execution_payload_header.state_root,
+ receipts_root=pre.latest_execution_payload_header.receipts_root,
+ logs_bloom=pre.latest_execution_payload_header.logs_bloom,
+ prev_randao=pre.latest_execution_payload_header.prev_randao,
+ block_number=pre.latest_execution_payload_header.block_number,
+ gas_limit=pre.latest_execution_payload_header.gas_limit,
+ gas_used=pre.latest_execution_payload_header.gas_used,
+ timestamp=pre.latest_execution_payload_header.timestamp,
+ extra_data=pre.latest_execution_payload_header.extra_data,
+ base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas,
+ block_hash=pre.latest_execution_payload_header.block_hash,
+ transactions_root=pre.latest_execution_payload_header.transactions_root,
+ withdrawals_root=pre.latest_execution_payload_header.withdrawals_root,
+ # [New in Deneb:EIP4844]
+ blob_gas_used=uint64(0),
+ # [New in Deneb:EIP4844]
+ excess_blob_gas=uint64(0),
+ )
+ post = BeaconState(
+ genesis_time=pre.genesis_time,
+ genesis_validators_root=pre.genesis_validators_root,
+ slot=pre.slot,
+ fork=Fork(
+ previous_version=pre.fork.current_version,
+ # [Modified in Deneb]
+ current_version=DENEB_FORK_VERSION,
+ epoch=epoch,
+ ),
+ latest_block_header=pre.latest_block_header,
+ block_roots=pre.block_roots,
+ state_roots=pre.state_roots,
+ historical_roots=pre.historical_roots,
+ 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,
+ randao_mixes=pre.randao_mixes,
+ slashings=pre.slashings,
+ previous_epoch_participation=pre.previous_epoch_participation,
+ current_epoch_participation=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,
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ # [Modified in Deneb:EIP4844]
+ latest_execution_payload_header=latest_execution_payload_header,
+ next_withdrawal_index=pre.next_withdrawal_index,
+ next_withdrawal_validator_index=pre.next_withdrawal_validator_index,
+ historical_summaries=pre.historical_summaries,
+ )
+
+ return post
+
+
+- name: upgrade_to_electra
+ sources:
+ - 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)
+
+ earliest_exit_epoch = compute_activation_exit_epoch(get_current_epoch(pre))
+ for validator in pre.validators:
+ if validator.exit_epoch != FAR_FUTURE_EPOCH:
+ if validator.exit_epoch > earliest_exit_epoch:
+ earliest_exit_epoch = validator.exit_epoch
+ earliest_exit_epoch += Epoch(1)
+
+ post = BeaconState(
+ genesis_time=pre.genesis_time,
+ genesis_validators_root=pre.genesis_validators_root,
+ slot=pre.slot,
+ fork=Fork(
+ previous_version=pre.fork.current_version,
+ # [Modified in Electra]
+ current_version=ELECTRA_FORK_VERSION,
+ epoch=epoch,
+ ),
+ latest_block_header=pre.latest_block_header,
+ block_roots=pre.block_roots,
+ state_roots=pre.state_roots,
+ historical_roots=pre.historical_roots,
+ 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,
+ randao_mixes=pre.randao_mixes,
+ slashings=pre.slashings,
+ previous_epoch_participation=pre.previous_epoch_participation,
+ current_epoch_participation=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,
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ latest_execution_payload_header=pre.latest_execution_payload_header,
+ next_withdrawal_index=pre.next_withdrawal_index,
+ next_withdrawal_validator_index=pre.next_withdrawal_validator_index,
+ historical_summaries=pre.historical_summaries,
+ # [New in Electra:EIP6110]
+ deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX,
+ # [New in Electra:EIP7251]
+ deposit_balance_to_consume=0,
+ # [New in Electra:EIP7251]
+ exit_balance_to_consume=0,
+ # [New in Electra:EIP7251]
+ earliest_exit_epoch=earliest_exit_epoch,
+ # [New in Electra:EIP7251]
+ consolidation_balance_to_consume=0,
+ # [New in Electra:EIP7251]
+ earliest_consolidation_epoch=compute_activation_exit_epoch(get_current_epoch(pre)),
+ # [New in Electra:EIP7251]
+ pending_deposits=[],
+ # [New in Electra:EIP7251]
+ pending_partial_withdrawals=[],
+ # [New in Electra:EIP7251]
+ pending_consolidations=[],
+ )
+
+ post.exit_balance_to_consume = get_activation_exit_churn_limit(post)
+ post.consolidation_balance_to_consume = get_consolidation_churn_limit(post)
+
+ # [New in Electra:EIP7251]
+ # add validators that are not yet active to pending balance deposits
+ pre_activation = sorted(
+ [
+ index
+ for index, validator in enumerate(post.validators)
+ if validator.activation_epoch == FAR_FUTURE_EPOCH
+ ],
+ key=lambda index: (post.validators[index].activation_eligibility_epoch, index),
+ )
+
+ for index in pre_activation:
+ balance = post.balances[index]
+ post.balances[index] = 0
+ validator = post.validators[index]
+ validator.effective_balance = 0
+ validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH
+ # Use bls.G2_POINT_AT_INFINITY as a signature field placeholder
+ # and GENESIS_SLOT to distinguish from a pending deposit request
+ post.pending_deposits.append(
+ PendingDeposit(
+ pubkey=validator.pubkey,
+ withdrawal_credentials=validator.withdrawal_credentials,
+ amount=balance,
+ signature=bls.G2_POINT_AT_INFINITY,
+ slot=GENESIS_SLOT,
+ )
+ )
+
+ # Ensure early adopters of compounding credentials go through the activation churn
+ for index, validator in enumerate(post.validators):
+ if has_compounding_withdrawal_credential(validator):
+ queue_excess_active_balance(post, ValidatorIndex(index))
+
+ return post
+
+
+- name: upgrade_to_fulu
+ sources:
+ - file: beacon-chain/core/fulu/upgrade.go
+ search: func UpgradeToFulu(
+ spec: |
+
+ def upgrade_to_fulu(pre: electra.BeaconState) -> BeaconState:
+ epoch = electra.get_current_epoch(pre)
+ post = BeaconState(
+ genesis_time=pre.genesis_time,
+ genesis_validators_root=pre.genesis_validators_root,
+ slot=pre.slot,
+ fork=Fork(
+ previous_version=pre.fork.current_version,
+ # [Modified in Fulu]
+ current_version=FULU_FORK_VERSION,
+ epoch=epoch,
+ ),
+ latest_block_header=pre.latest_block_header,
+ block_roots=pre.block_roots,
+ state_roots=pre.state_roots,
+ historical_roots=pre.historical_roots,
+ 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,
+ randao_mixes=pre.randao_mixes,
+ slashings=pre.slashings,
+ previous_epoch_participation=pre.previous_epoch_participation,
+ current_epoch_participation=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,
+ current_sync_committee=pre.current_sync_committee,
+ next_sync_committee=pre.next_sync_committee,
+ latest_execution_payload_header=pre.latest_execution_payload_header,
+ next_withdrawal_index=pre.next_withdrawal_index,
+ next_withdrawal_validator_index=pre.next_withdrawal_validator_index,
+ historical_summaries=pre.historical_summaries,
+ deposit_requests_start_index=pre.deposit_requests_start_index,
+ deposit_balance_to_consume=pre.deposit_balance_to_consume,
+ exit_balance_to_consume=pre.exit_balance_to_consume,
+ 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,
+ # [New in Fulu:EIP7917]
+ proposer_lookahead=initialize_proposer_lookahead(pre),
+ )
+
+ return post
+
+
+- name: validate_light_client_update
+ sources: []
+ spec: |
+
+ def validate_light_client_update(
+ store: LightClientStore,
+ update: LightClientUpdate,
+ current_slot: Slot,
+ genesis_validators_root: Root,
+ ) -> None:
+ # Verify sync committee has sufficient participants
+ sync_aggregate = update.sync_aggregate
+ assert sum(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)
+ update_attested_slot = update.attested_header.beacon.slot
+ update_finalized_slot = update.finalized_header.beacon.slot
+ assert current_slot >= update.signature_slot > update_attested_slot >= update_finalized_slot
+ store_period = compute_sync_committee_period_at_slot(store.finalized_header.beacon.slot)
+ update_signature_period = compute_sync_committee_period_at_slot(update.signature_slot)
+ if is_next_sync_committee_known(store):
+ assert update_signature_period in (store_period, store_period + 1)
+ else:
+ assert update_signature_period == store_period
+
+ # Verify update is relevant
+ update_attested_period = compute_sync_committee_period_at_slot(update_attested_slot)
+ update_has_next_sync_committee = not is_next_sync_committee_known(store) and (
+ is_sync_committee_update(update) and update_attested_period == store_period
+ )
+ assert (
+ update_attested_slot > store.finalized_header.beacon.slot or update_has_next_sync_committee
+ )
+
+ # Verify that the `finality_branch`, if present, confirms `finalized_header`
+ # to match the finalized checkpoint root saved in the state of `attested_header`.
+ # Note that the genesis finalized checkpoint root is represented as a zero hash.
+ if not is_finality_update(update):
+ assert update.finalized_header == LightClientHeader()
+ else:
+ if update_finalized_slot == GENESIS_SLOT:
+ assert update.finalized_header == LightClientHeader()
+ finalized_root = Bytes32()
+ else:
+ assert is_valid_light_client_header(update.finalized_header)
+ finalized_root = hash_tree_root(update.finalized_header.beacon)
+ assert is_valid_normalized_merkle_branch(
+ leaf=finalized_root,
+ branch=update.finality_branch,
+ gindex=finalized_root_gindex_at_slot(update.attested_header.beacon.slot),
+ root=update.attested_header.beacon.state_root,
+ )
+
+ # Verify that the `next_sync_committee`, if present, actually is the next sync committee saved in the
+ # state of the `attested_header`
+ if not is_sync_committee_update(update):
+ assert update.next_sync_committee == SyncCommittee()
+ else:
+ if update_attested_period == store_period and is_next_sync_committee_known(store):
+ assert update.next_sync_committee == store.next_sync_committee
+ assert is_valid_normalized_merkle_branch(
+ leaf=hash_tree_root(update.next_sync_committee),
+ branch=update.next_sync_committee_branch,
+ gindex=next_sync_committee_gindex_at_slot(update.attested_header.beacon.slot),
+ root=update.attested_header.beacon.state_root,
+ )
+
+ # Verify sync committee aggregate signature
+ if update_signature_period == store_period:
+ sync_committee = store.current_sync_committee
+ else:
+ sync_committee = store.next_sync_committee
+ participant_pubkeys = [
+ pubkey
+ for (bit, pubkey) in zip(sync_aggregate.sync_committee_bits, sync_committee.pubkeys)
+ if bit
+ ]
+ fork_version_slot = max(update.signature_slot, Slot(1)) - Slot(1)
+ fork_version = compute_fork_version(compute_epoch_at_slot(fork_version_slot))
+ domain = compute_domain(DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root)
+ signing_root = compute_signing_root(update.attested_header.beacon, domain)
+ assert bls.FastAggregateVerify(
+ participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature
+ )
+
+
+- name: validate_merge_block
+ sources:
+ - file: beacon-chain/blockchain/pow_block.go
+ search: func (s *Service) validateMergeBlock(
+ spec: |
+
+ def validate_merge_block(block: BeaconBlock) -> None:
+ """
+ Check the parent PoW block of execution payload is a valid terminal PoW block.
+
+ Note: Unavailable PoW block(s) may later become available,
+ and a client software MAY delay a call to ``validate_merge_block``
+ until the PoW block(s) become available.
+ """
+ if TERMINAL_BLOCK_HASH != Hash32():
+ # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
+ assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
+ assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
+ return
+
+ pow_block = get_pow_block(block.body.execution_payload.parent_hash)
+ # Check if `pow_block` is available
+ assert pow_block is not None
+ pow_parent = get_pow_block(pow_block.parent_hash)
+ # Check if `pow_parent` is available
+ assert pow_parent is not None
+ # Check if `pow_block` is a valid terminal PoW block
+ assert is_valid_terminal_pow_block(pow_block, pow_parent)
+
+
+- name: validate_on_attestation
+ sources: []
+ spec: |
+
+ def validate_on_attestation(store: Store, attestation: Attestation, is_from_block: bool) -> None:
+ target = attestation.data.target
+
+ # If the given attestation is not from a beacon block message, we have to check the target epoch scope.
+ if not is_from_block:
+ validate_target_epoch_against_current_time(store, attestation)
+
+ # Check that the epoch number and slot number are matching
+ assert target.epoch == compute_epoch_at_slot(attestation.data.slot)
+
+ # Attestation target must be for a known block. If target block is unknown, delay consideration until block is found
+ assert target.root in store.blocks
+
+ # Attestations must be for a known block. If block is unknown, delay consideration until the block is found
+ assert attestation.data.beacon_block_root in store.blocks
+ # Attestations must not be for blocks in the future. If not, the attestation should not be considered
+ assert store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot
+
+ # LMD vote must be consistent with FFG vote target
+ assert target.root == get_checkpoint_block(
+ store, attestation.data.beacon_block_root, target.epoch
+ )
+
+ # Attestations can only affect the fork choice of subsequent slots.
+ # Delay consideration in the fork choice until their slot is in the past.
+ assert get_current_slot(store) >= attestation.data.slot + 1
+
+
+- name: validate_target_epoch_against_current_time
+ sources: []
+ spec: |
+
+ def validate_target_epoch_against_current_time(store: Store, attestation: Attestation) -> None:
+ target = attestation.data.target
+
+ # Attestations must be from the current or previous epoch
+ current_epoch = get_current_store_epoch(store)
+ # Use GENESIS_EPOCH for previous when genesis to avoid underflow
+ previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH
+ # If attestation target is from a future epoch, delay consideration until the epoch arrives
+ assert target.epoch in [current_epoch, previous_epoch]
+
+
+- name: verify_blob_sidecar_inclusion_proof
+ sources:
+ - file: consensus-types/blocks/kzg.go
+ search: func VerifyKZGInclusionProof(
+ spec: |
+
+ def verify_blob_sidecar_inclusion_proof(blob_sidecar: BlobSidecar) -> bool:
+ gindex = get_subtree_index(
+ get_generalized_index(BeaconBlockBody, "blob_kzg_commitments", blob_sidecar.index)
+ )
+ return is_valid_merkle_branch(
+ leaf=blob_sidecar.kzg_commitment.hash_tree_root(),
+ branch=blob_sidecar.kzg_commitment_inclusion_proof,
+ depth=KZG_COMMITMENT_INCLUSION_PROOF_DEPTH,
+ index=gindex,
+ root=blob_sidecar.signed_block_header.message.body_root,
+ )
+
+
+- name: verify_block_signature
+ sources:
+ - file: beacon-chain/core/blocks/signature.go
+ search: func VerifyBlockSignature(
+ spec: |
+
+ def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool:
+ proposer = state.validators[signed_block.message.proposer_index]
+ signing_root = compute_signing_root(
+ signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)
+ )
+ return bls.Verify(proposer.pubkey, signing_root, signed_block.signature)
+
+
+- name: verify_data_column_sidecar
+ sources:
+ - 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.
+ """
+ # The sidecar index must be within the valid range
+ if sidecar.index >= NUMBER_OF_COLUMNS:
+ return False
+
+ # A sidecar for zero blobs is invalid
+ if len(sidecar.kzg_commitments) == 0:
+ 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
+ ):
+ return False
+
+ return True
+
+
+- name: verify_data_column_sidecar_inclusion_proof
+ sources:
+ - file: beacon-chain/core/peerdas/p2p_interface.go
+ search: func VerifyDataColumnSidecarInclusionProof(
+ spec: |
+
+ def verify_data_column_sidecar_inclusion_proof(sidecar: DataColumnSidecar) -> bool:
+ """
+ Verify if the given KZG commitments included in the given beacon block.
+ """
+ gindex = get_subtree_index(get_generalized_index(BeaconBlockBody, "blob_kzg_commitments"))
+ return is_valid_merkle_branch(
+ leaf=hash_tree_root(sidecar.kzg_commitments),
+ branch=sidecar.kzg_commitments_inclusion_proof,
+ depth=KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH,
+ index=gindex,
+ root=sidecar.signed_block_header.message.body_root,
+ )
+
+
+- name: verify_data_column_sidecar_kzg_proofs
+ sources:
+ - file: beacon-chain/core/peerdas/p2p_interface.go
+ search: func VerifyDataColumnsSidecarKZGProofs(
+ spec: |
+
+ def verify_data_column_sidecar_kzg_proofs(sidecar: DataColumnSidecar) -> bool:
+ """
+ Verify if the KZG proofs are correct.
+ """
+ # The column index also represents the cell index
+ 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(
+ commitments_bytes=sidecar.kzg_commitments,
+ cell_indices=cell_indices,
+ cells=sidecar.column,
+ proofs_bytes=sidecar.kzg_proofs,
+ )
+
+
+- name: voting_period_start_time
+ sources:
+ - file: time/slots/slottime.go
+ search: func VotingPeriodStartTime(
+ spec: |
+
+ 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)
+ )
+ return compute_time_at_slot(state, eth1_voting_period_start_slot)
+
+
+- name: weigh_justification_and_finalization
+ sources:
+ - file: beacon-chain/core/epoch/precompute/justification_finalization.go
+ search: func weighJustificationAndFinalization(
+ spec: |
+
+ def weigh_justification_and_finalization(
+ state: BeaconState,
+ total_active_balance: Gwei,
+ previous_epoch_target_balance: Gwei,
+ current_epoch_target_balance: Gwei,
+ ) -> None:
+ previous_epoch = get_previous_epoch(state)
+ current_epoch = get_current_epoch(state)
+ old_previous_justified_checkpoint = state.previous_justified_checkpoint
+ old_current_justified_checkpoint = state.current_justified_checkpoint
+
+ # Process justifications
+ state.previous_justified_checkpoint = state.current_justified_checkpoint
+ state.justification_bits[1:] = state.justification_bits[: JUSTIFICATION_BITS_LENGTH - 1]
+ state.justification_bits[0] = 0b0
+ if previous_epoch_target_balance * 3 >= total_active_balance * 2:
+ state.current_justified_checkpoint = Checkpoint(
+ epoch=previous_epoch, root=get_block_root(state, previous_epoch)
+ )
+ state.justification_bits[1] = 0b1
+ if current_epoch_target_balance * 3 >= total_active_balance * 2:
+ state.current_justified_checkpoint = Checkpoint(
+ epoch=current_epoch, root=get_block_root(state, current_epoch)
+ )
+ state.justification_bits[0] = 0b1
+
+ # Process finalizations
+ bits = state.justification_bits
+ # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
+ if all(bits[1:4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch:
+ state.finalized_checkpoint = old_previous_justified_checkpoint
+ # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
+ if all(bits[1:3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch:
+ state.finalized_checkpoint = old_previous_justified_checkpoint
+ # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
+ if all(bits[0:3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch:
+ state.finalized_checkpoint = old_current_justified_checkpoint
+ # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
+ if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
+ state.finalized_checkpoint = old_current_justified_checkpoint
+
+
+- name: xor
+ sources: []
+ spec: |
+
+ def xor(bytes_1: Bytes32, bytes_2: Bytes32) -> Bytes32:
+ """
+ Return the exclusive-or of two 32-byte strings.
+ """
+ return Bytes32(a ^ b for a, b in zip(bytes_1, bytes_2))
+
diff --git a/specrefs/presets.yml b/specrefs/presets.yml
new file mode 100644
index 000000000000..fc14e9ff4c9a
--- /dev/null
+++ b/specrefs/presets.yml
@@ -0,0 +1,716 @@
+- name: BASE_REWARD_FACTOR
+ sources:
+ - file: config/params/config.go
+ search: BaseRewardFactor\s+.*yaml:"BASE_REWARD_FACTOR"
+ regex: true
+ spec: |
+
+ BASE_REWARD_FACTOR: uint64 = 64
+
+
+- name: BYTES_PER_LOGS_BLOOM
+ sources:
+ - file: config/params/config.go
+ search: BytesPerLogsBloom\s+.*yaml:"BYTES_PER_LOGS_BLOOM"
+ regex: true
+ spec: |
+
+ BYTES_PER_LOGS_BLOOM: uint64 = 256
+
+
+- name: CELLS_PER_EXT_BLOB
+ sources: []
+ spec: |
+
+ CELLS_PER_EXT_BLOB = 128
+
+
+- name: EFFECTIVE_BALANCE_INCREMENT
+ sources:
+ - file: config/params/config.go
+ search: EffectiveBalanceIncrement\s+.*yaml:"EFFECTIVE_BALANCE_INCREMENT"
+ regex: true
+ spec: |
+
+ EFFECTIVE_BALANCE_INCREMENT: Gwei = 1000000000
+
+
+- name: EPOCHS_PER_ETH1_VOTING_PERIOD
+ sources:
+ - file: config/params/config.go
+ search: EpochsPerEth1VotingPeriod\s+.*yaml:"EPOCHS_PER_ETH1_VOTING_PERIOD"
+ regex: true
+ spec: |
+
+ EPOCHS_PER_ETH1_VOTING_PERIOD: uint64 = 64
+
+
+- name: EPOCHS_PER_HISTORICAL_VECTOR
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: RandaoMixesLength\s*=
+ regex: true
+ spec: |
+
+ EPOCHS_PER_HISTORICAL_VECTOR: uint64 = 65536
+
+
+- name: EPOCHS_PER_SLASHINGS_VECTOR
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: SlashingsLength\s*=
+ regex: true
+ spec: |
+
+ EPOCHS_PER_SLASHINGS_VECTOR: uint64 = 8192
+
+
+- name: EPOCHS_PER_SYNC_COMMITTEE_PERIOD
+ sources:
+ - file: config/params/config.go
+ search: EpochsPerSyncCommitteePeriod\s+.*yaml:"EPOCHS_PER_SYNC_COMMITTEE_PERIOD"
+ regex: true
+ spec: |
+
+ EPOCHS_PER_SYNC_COMMITTEE_PERIOD: uint64 = 256
+
+
+- name: FIELD_ELEMENTS_PER_BLOB
+ sources:
+ - file: config/params/config.go
+ search: FieldElementsPerBlob\s+.*yaml:"FIELD_ELEMENTS_PER_BLOB"
+ regex: true
+ spec: |
+
+ FIELD_ELEMENTS_PER_BLOB: uint64 = 4096
+
+
+- name: FIELD_ELEMENTS_PER_CELL
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: CellsPerBlob\s*=
+ regex: true
+ spec: |
+
+ FIELD_ELEMENTS_PER_CELL: uint64 = 64
+
+
+- name: FIELD_ELEMENTS_PER_EXT_BLOB
+ sources:
+ - file: proto/ssz_proto_library.bzl
+ search: mainnet\s*=\s*\{[^}]*"field_elements_per_ext_blob\.size".*[^}]*\}
+ regex: true
+ spec: |
+
+ FIELD_ELEMENTS_PER_EXT_BLOB = 8192
+
+
+- name: HISTORICAL_ROOTS_LIMIT
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: HistoricalRootsLength\s*=
+ regex: true
+ spec: |
+
+ HISTORICAL_ROOTS_LIMIT: uint64 = 16777216
+
+
+- name: HYSTERESIS_DOWNWARD_MULTIPLIER
+ sources:
+ - file: config/params/config.go
+ search: HysteresisDownwardMultiplier\s+.*yaml:"HYSTERESIS_DOWNWARD_MULTIPLIER"
+ regex: true
+ spec: |
+
+ HYSTERESIS_DOWNWARD_MULTIPLIER: uint64 = 1
+
+
+- name: HYSTERESIS_QUOTIENT
+ sources:
+ - file: config/params/config.go
+ search: HysteresisQuotient\s+.*yaml:"HYSTERESIS_QUOTIENT"
+ regex: true
+ spec: |
+
+ HYSTERESIS_QUOTIENT: uint64 = 4
+
+
+- name: HYSTERESIS_UPWARD_MULTIPLIER
+ sources:
+ - file: config/params/config.go
+ search: HysteresisUpwardMultiplier\s+.*yaml:"HYSTERESIS_UPWARD_MULTIPLIER"
+ regex: true
+ spec: |
+
+ HYSTERESIS_UPWARD_MULTIPLIER: uint64 = 5
+
+
+- name: INACTIVITY_PENALTY_QUOTIENT
+ sources:
+ - file: config/params/config.go
+ search: InactivityPenaltyQuotient\s+.*yaml:"INACTIVITY_PENALTY_QUOTIENT"
+ regex: true
+ spec: |
+
+ INACTIVITY_PENALTY_QUOTIENT: uint64 = 67108864
+
+
+- name: INACTIVITY_PENALTY_QUOTIENT_ALTAIR
+ sources:
+ - file: config/params/config.go
+ search: InactivityPenaltyQuotientAltair\s+.*yaml:"INACTIVITY_PENALTY_QUOTIENT_ALTAIR"
+ regex: true
+ spec: |
+
+ INACTIVITY_PENALTY_QUOTIENT_ALTAIR: uint64 = 50331648
+
+
+- name: INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
+ sources:
+ - file: config/params/config.go
+ search: InactivityPenaltyQuotientBellatrix\s+.*yaml:"INACTIVITY_PENALTY_QUOTIENT_BELLATRIX"
+ regex: true
+ spec: |
+
+ INACTIVITY_PENALTY_QUOTIENT_BELLATRIX: uint64 = 16777216
+
+
+- name: KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH
+ sources:
+ - file: proto/ssz_proto_library.bzl
+ search: mainnet\s*=\s*\{[^}]*"kzg_commitments_inclusion_proof_depth\.size":.*[^}]*\}
+ regex: true
+ spec: |
+
+ KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: uint64 = 4
+
+
+- name: KZG_COMMITMENT_INCLUSION_PROOF_DEPTH
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: KzgCommitmentInclusionProofDepth\s*=
+ regex: true
+ spec: |
+
+ KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: uint64 = 17
+
+
+- name: MAX_ATTESTATIONS
+ sources:
+ - file: config/params/config.go
+ search: MaxAttestations\s+.*yaml:"MAX_ATTESTATIONS"
+ regex: true
+ spec: |
+
+ MAX_ATTESTATIONS = 128
+
+
+- name: MAX_ATTESTATIONS_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: MaxAttestationsElectra\s+.*yaml:"MAX_ATTESTATIONS_ELECTRA"
+ regex: true
+ spec: |
+
+ MAX_ATTESTATIONS_ELECTRA = 8
+
+
+- name: MAX_ATTESTER_SLASHINGS
+ sources:
+ - file: config/params/config.go
+ search: MaxAttesterSlashings\s+.*yaml:"MAX_ATTESTER_SLASHINGS"
+ regex: true
+ spec: |
+
+ MAX_ATTESTER_SLASHINGS = 2
+
+
+- name: MAX_ATTESTER_SLASHINGS_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: MaxAttesterSlashingsElectra\s+.*yaml:"MAX_ATTESTER_SLASHINGS_ELECTRA"
+ regex: true
+ spec: |
+
+ MAX_ATTESTER_SLASHINGS_ELECTRA = 1
+
+
+- name: MAX_BLOB_COMMITMENTS_PER_BLOCK
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: MaxBlobCommitmentsPerBlock\s*=
+ regex: true
+ spec: |
+
+ MAX_BLOB_COMMITMENTS_PER_BLOCK: uint64 = 4096
+
+
+- name: MAX_BLS_TO_EXECUTION_CHANGES
+ sources:
+ - file: config/params/config.go
+ search: MaxBlsToExecutionChanges\s+.*yaml:"MAX_BLS_TO_EXECUTION_CHANGES"
+ regex: true
+ spec: |
+
+ MAX_BLS_TO_EXECUTION_CHANGES = 16
+
+
+- name: MAX_BYTES_PER_TRANSACTION
+ sources:
+ - file: config/params/config.go
+ search: MaxBytesPerTransaction\s+.*yaml:"MAX_BYTES_PER_TRANSACTION"
+ regex: true
+ spec: |
+
+ MAX_BYTES_PER_TRANSACTION: uint64 = 1073741824
+
+
+- name: MAX_COMMITTEES_PER_SLOT#phase0
+ sources:
+ - file: config/params/config.go
+ search: MaxCommitteesPerSlot\s+.*yaml:"MAX_COMMITTEES_PER_SLOT"
+ regex: true
+ spec: |
+
+ MAX_COMMITTEES_PER_SLOT: uint64 = 64
+
+
+- name: MAX_COMMITTEES_PER_SLOT#electra
+ sources:
+ - file: config/params/config.go
+ search: MaxCommitteesPerSlot\s+.*yaml:"MAX_COMMITTEES_PER_SLOT"
+ regex: true
+ spec: |
+
+ MAX_COMMITTEES_PER_SLOT: uint64 = 64
+
+
+- name: MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD
+ sources:
+ - file: config/params/config.go
+ search: MaxConsolidationsRequestsPerPayload\s+.*yaml:"MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD"
+ regex: true
+ spec: |
+
+ MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: uint64 = 2
+
+
+- name: MAX_DEPOSITS
+ sources:
+ - file: config/params/config.go
+ search: MaxDeposits\s+.*yaml:"MAX_DEPOSITS"
+ regex: true
+ spec: |
+
+ MAX_DEPOSITS = 16
+
+
+- name: MAX_DEPOSIT_REQUESTS_PER_PAYLOAD
+ sources:
+ - file: config/params/config.go
+ search: MaxDepositRequestsPerPayload\s+.*yaml:"MAX_DEPOSIT_REQUESTS_PER_PAYLOAD"
+ regex: true
+ spec: |
+
+ MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: uint64 = 8192
+
+
+- name: MAX_EFFECTIVE_BALANCE
+ sources:
+ - file: config/params/config.go
+ search: MaxEffectiveBalance\s+.*yaml:"MAX_EFFECTIVE_BALANCE"
+ regex: true
+ spec: |
+
+ MAX_EFFECTIVE_BALANCE: Gwei = 32000000000
+
+
+- name: MAX_EFFECTIVE_BALANCE_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: MaxEffectiveBalanceElectra\s+.*yaml:"MAX_EFFECTIVE_BALANCE_ELECTRA"
+ regex: true
+ spec: |
+
+ MAX_EFFECTIVE_BALANCE_ELECTRA: Gwei = 2048000000000
+
+
+- name: MAX_EXTRA_DATA_BYTES
+ sources:
+ - file: config/params/config.go
+ search: MaxExtraDataBytes\s+.*yaml:"MAX_EXTRA_DATA_BYTES"
+ regex: true
+ spec: |
+
+ MAX_EXTRA_DATA_BYTES = 32
+
+
+- name: MAX_PENDING_DEPOSITS_PER_EPOCH
+ sources:
+ - file: config/params/config.go
+ search: MaxPendingDepositsPerEpoch\s+.*yaml:"MAX_PENDING_DEPOSITS_PER_EPOCH"
+ regex: true
+ spec: |
+
+ MAX_PENDING_DEPOSITS_PER_EPOCH: uint64 = 16
+
+
+- name: MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP
+ sources:
+ - file: config/params/config.go
+ search: MaxPendingPartialsPerWithdrawalsSweep\s+.*yaml:"MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP"
+ regex: true
+ spec: |
+
+ MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: uint64 = 8
+
+
+- name: MAX_PROPOSER_SLASHINGS
+ sources:
+ - file: config/params/config.go
+ search: MaxProposerSlashings\s+.*yaml:"MAX_PROPOSER_SLASHINGS"
+ regex: true
+ spec: |
+
+ MAX_PROPOSER_SLASHINGS = 16
+
+
+- name: MAX_SEED_LOOKAHEAD
+ sources:
+ - file: config/params/config.go
+ search: MaxSeedLookahead\s+.*yaml:"MAX_SEED_LOOKAHEAD"
+ regex: true
+ spec: |
+
+ MAX_SEED_LOOKAHEAD: uint64 = 4
+
+
+- name: MAX_TRANSACTIONS_PER_PAYLOAD
+ sources:
+ - file: config/params/config.go
+ search: MaxTransactionsPerPayload\s+.*yaml:"MAX_TRANSACTIONS_PER_PAYLOAD"
+ regex: true
+ spec: |
+
+ MAX_TRANSACTIONS_PER_PAYLOAD: uint64 = 1048576
+
+
+- name: MAX_VALIDATORS_PER_COMMITTEE#phase0
+ sources:
+ - file: config/params/config.go
+ search: MaxValidatorsPerCommittee\s+.*yaml:"MAX_VALIDATORS_PER_COMMITTEE"
+ regex: true
+ spec: |
+
+ MAX_VALIDATORS_PER_COMMITTEE: uint64 = 2048
+
+
+- name: MAX_VALIDATORS_PER_COMMITTEE#electra
+ sources:
+ - file: config/params/config.go
+ search: MaxValidatorsPerCommittee\s+.*yaml:"MAX_VALIDATORS_PER_COMMITTEE"
+ regex: true
+ spec: |
+
+ MAX_VALIDATORS_PER_COMMITTEE: uint64 = 2048
+
+
+- name: MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
+ sources:
+ - file: config/params/config.go
+ search: MaxValidatorsPerWithdrawalsSweep\s+.*yaml:"MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP"
+ regex: true
+ spec: |
+
+ MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP = 16384
+
+
+- name: MAX_VOLUNTARY_EXITS
+ sources:
+ - file: config/params/config.go
+ search: MaxVoluntaryExits\s+.*yaml:"MAX_VOLUNTARY_EXITS"
+ regex: true
+ spec: |
+
+ MAX_VOLUNTARY_EXITS = 16
+
+
+- name: MAX_WITHDRAWALS_PER_PAYLOAD
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: MaxWithdrawalsPerPayload\s*=
+ regex: true
+ spec: |
+
+ MAX_WITHDRAWALS_PER_PAYLOAD: uint64 = 16
+
+
+- name: MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD
+ sources:
+ - file: config/params/config.go
+ search: MaxWithdrawalRequestsPerPayload\s+.*yaml:"MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD"
+ regex: true
+ spec: |
+
+ MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: uint64 = 16
+
+
+- name: MIN_ACTIVATION_BALANCE
+ sources:
+ - file: config/params/config.go
+ search: MinActivationBalance\s+.*yaml:"MIN_ACTIVATION_BALANCE"
+ regex: true
+ spec: |
+
+ MIN_ACTIVATION_BALANCE: Gwei = 32000000000
+
+
+- name: MIN_ATTESTATION_INCLUSION_DELAY
+ sources:
+ - file: config/params/config.go
+ search: MinAttestationInclusionDelay\s+.*yaml:"MIN_ATTESTATION_INCLUSION_DELAY"
+ regex: true
+ spec: |
+
+ MIN_ATTESTATION_INCLUSION_DELAY: uint64 = 1
+
+
+- name: MIN_DEPOSIT_AMOUNT
+ sources:
+ - file: config/params/config.go
+ search: MinDepositAmount\s+.*yaml:"MIN_DEPOSIT_AMOUNT"
+ regex: true
+ spec: |
+
+ MIN_DEPOSIT_AMOUNT: Gwei = 1000000000
+
+
+- name: MIN_EPOCHS_TO_INACTIVITY_PENALTY
+ sources:
+ - file: config/params/config.go
+ search: MinEpochsToInactivityPenalty\s+.*yaml:"MIN_EPOCHS_TO_INACTIVITY_PENALTY"
+ regex: true
+ spec: |
+
+ MIN_EPOCHS_TO_INACTIVITY_PENALTY: uint64 = 4
+
+
+- name: MIN_SEED_LOOKAHEAD
+ sources:
+ - file: config/params/config.go
+ search: MinSeedLookahead\s+.*yaml:"MIN_SEED_LOOKAHEAD"
+ regex: true
+ spec: |
+
+ MIN_SEED_LOOKAHEAD: uint64 = 1
+
+
+- name: MIN_SLASHING_PENALTY_QUOTIENT
+ sources:
+ - file: config/params/config.go
+ search: MinSlashingPenaltyQuotient\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT"
+ regex: true
+ spec: |
+
+ MIN_SLASHING_PENALTY_QUOTIENT: uint64 = 128
+
+
+- name: MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
+ sources:
+ - file: config/params/config.go
+ search: MinSlashingPenaltyQuotientAltair\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR"
+ regex: true
+ spec: |
+
+ MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: uint64 = 64
+
+
+- name: MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX
+ sources:
+ - file: config/params/config.go
+ search: MinSlashingPenaltyQuotientBellatrix\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX"
+ regex: true
+ spec: |
+
+ MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX: uint64 = 32
+
+
+- name: MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: MinSlashingPenaltyQuotientElectra\s+.*yaml:"MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA"
+ regex: true
+ spec: |
+
+ MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: uint64 = 4096
+
+
+- name: MIN_SYNC_COMMITTEE_PARTICIPANTS
+ sources:
+ - file: config/params/config.go
+ search: MinSyncCommitteeParticipants\s+.*yaml:"MIN_SYNC_COMMITTEE_PARTICIPANTS"
+ regex: true
+ spec: |
+
+ MIN_SYNC_COMMITTEE_PARTICIPANTS = 1
+
+
+- name: NUMBER_OF_COLUMNS
+ sources:
+ - file: config/params/config.go
+ search: NumberOfColumns\s+uint64
+ regex: true
+ spec: |
+
+ NUMBER_OF_COLUMNS: uint64 = 128
+
+
+- name: PENDING_CONSOLIDATIONS_LIMIT
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: PendingConsolidationsLimit\s*=
+ regex: true
+ spec: |
+
+ PENDING_CONSOLIDATIONS_LIMIT: uint64 = 262144
+
+
+- name: PENDING_DEPOSITS_LIMIT
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: PendingDepositsLimit\s*=
+ regex: true
+ spec: |
+
+ PENDING_DEPOSITS_LIMIT: uint64 = 134217728
+
+
+- name: PENDING_PARTIAL_WITHDRAWALS_LIMIT
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: PendingPartialWithdrawalsLimit\s*=
+ regex: true
+ spec: |
+
+ PENDING_PARTIAL_WITHDRAWALS_LIMIT: uint64 = 134217728
+
+
+- name: PROPORTIONAL_SLASHING_MULTIPLIER
+ sources:
+ - file: config/params/config.go
+ search: ProportionalSlashingMultiplier\s+.*yaml:"PROPORTIONAL_SLASHING_MULTIPLIER"
+ regex: true
+ spec: |
+
+ PROPORTIONAL_SLASHING_MULTIPLIER: uint64 = 1
+
+
+- name: PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
+ sources:
+ - file: config/params/config.go
+ search: ProportionalSlashingMultiplierAltair\s+.*yaml:"PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR"
+ regex: true
+ spec: |
+
+ PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: uint64 = 2
+
+
+- name: PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX
+ sources:
+ - file: config/params/config.go
+ search: ProportionalSlashingMultiplierBellatrix\s+.*yaml:"PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX"
+ regex: true
+ spec: |
+
+ PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX: uint64 = 3
+
+
+- name: PROPOSER_REWARD_QUOTIENT
+ sources:
+ - file: config/params/config.go
+ search: ProposerRewardQuotient\s+.*yaml:"PROPOSER_REWARD_QUOTIENT"
+ regex: true
+ spec: |
+
+ PROPOSER_REWARD_QUOTIENT: uint64 = 8
+
+
+- name: SHUFFLE_ROUND_COUNT
+ sources:
+ - file: config/params/config.go
+ search: ShuffleRoundCount\s+.*yaml:"SHUFFLE_ROUND_COUNT"
+ regex: true
+ spec: |
+
+ SHUFFLE_ROUND_COUNT: uint64 = 90
+
+
+- name: SLOTS_PER_EPOCH
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: SlotsPerEpoch\s*=
+ regex: true
+ spec: |
+
+ SLOTS_PER_EPOCH: uint64 = 32
+
+
+- name: SLOTS_PER_HISTORICAL_ROOT
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: BlockRootsLength\s*=
+ regex: true
+ spec: |
+
+ SLOTS_PER_HISTORICAL_ROOT: uint64 = 8192
+
+
+- name: SYNC_COMMITTEE_SIZE
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: SyncCommitteeLength\s*=
+ regex: true
+ spec: |
+
+ SYNC_COMMITTEE_SIZE: uint64 = 512
+
+
+- name: TARGET_COMMITTEE_SIZE
+ sources:
+ - file: config/params/config.go
+ search: TargetCommitteeSize\s+.*yaml:"TARGET_COMMITTEE_SIZE"
+ regex: true
+ spec: |
+
+ TARGET_COMMITTEE_SIZE: uint64 = 128
+
+
+- name: VALIDATOR_REGISTRY_LIMIT
+ sources:
+ - file: config/fieldparams/mainnet.go
+ search: ValidatorRegistryLimit\s*=
+ regex: true
+ spec: |
+
+ VALIDATOR_REGISTRY_LIMIT: uint64 = 1099511627776
+
+
+- name: WHISTLEBLOWER_REWARD_QUOTIENT
+ sources:
+ - file: config/params/config.go
+ search: WhistleBlowerRewardQuotient\s+.*yaml:"WHISTLEBLOWER_REWARD_QUOTIENT"
+ regex: true
+ spec: |
+
+ WHISTLEBLOWER_REWARD_QUOTIENT: uint64 = 512
+
+
+- name: WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA
+ sources:
+ - file: config/params/config.go
+ search: WhistleBlowerRewardQuotientElectra\s+.*yaml:"WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA"
+ regex: true
+ spec: |
+
+ WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: uint64 = 4096
+