diff --git a/.ethspecify.yml b/.ethspecify.yml index 728fb97b4e25..e42563b4c44f 100644 --- a/.ethspecify.yml +++ b/.ethspecify.yml @@ -1,4 +1,4 @@ -version: v1.7.0-alpha.2 +version: v1.7.0-alpha.4 style: full specrefs: @@ -23,6 +23,8 @@ exceptions: - PTC_SIZE#gloas constants: + # heze + - DOMAIN_INCLUSION_LIST_COMMITTEE#heze # phase0 - BASIS_POINTS#phase0 - ENDIANNESS#phase0 @@ -72,10 +74,30 @@ exceptions: - GLOAS_FORK_EPOCH#gloas - GLOAS_FORK_VERSION#gloas - SYNC_MESSAGE_DUE_BPS_GLOAS#gloas + # heze + - HEZE_FORK_EPOCH#heze + - HEZE_FORK_VERSION#heze + - INCLUSION_LIST_SUBMISSION_DUE_BPS#heze + - MAX_BYTES_PER_INCLUSION_LIST#heze + - MAX_REQUEST_INCLUSION_LIST#heze + - PROPOSER_INCLUSION_LIST_CUTOFF_BPS#heze + - VIEW_FREEZE_CUTOFF_BPS#heze ssz_objects: # phase0 - Eth1Block#phase0 + # fulu + - PartialDataColumnHeader#fulu + - PartialDataColumnPartsMetadata#fulu + - PartialDataColumnSidecar#fulu + # gloas + - PartialDataColumnHeader#gloas + # heze + - BeaconState#heze + - ExecutionPayloadBid#heze + - InclusionList#heze + - SignedExecutionPayloadBid#heze + - SignedInclusionList#heze # capella - LightClientBootstrap#capella - LightClientFinalityUpdate#capella @@ -105,6 +127,7 @@ exceptions: dataclasses: # phase0 - LatestMessage#phase0 + - Seen#phase0 - Store#phase0 # altair - LightClientStore#altair @@ -121,6 +144,11 @@ exceptions: - ExpectedWithdrawals#gloas - LatestMessage#gloas - Store#gloas + # heze + - GetInclusionListResponse#heze + - InclusionListStore#heze + - PayloadAttributes#heze + - Store#heze functions: # Functions implemented by KZG library for EIP-4844 @@ -177,11 +205,22 @@ exceptions: - verify_cell_kzg_proof_batch_impl#fulu # phase0 + - compute_attestation_subnet_prefix_bits#phase0 + - compute_min_epochs_for_block_requests#phase0 + - compute_time_at_slot_ms#phase0 + - is_not_from_future_slot#phase0 + - is_within_slot_range#phase0 - update_proposer_boost_root#phase0 - is_proposer_equivocation#phase0 - record_block_timeliness#phase0 - compute_proposer_score#phase0 - get_attestation_score#phase0 + - validate_attester_slashing_gossip#phase0 + - validate_beacon_aggregate_and_proof_gossip#phase0 + - validate_beacon_attestation_gossip#phase0 + - validate_beacon_block_gossip#phase0 + - validate_proposer_slashing_gossip#phase0 + - validate_voluntary_exit_gossip#phase0 - calculate_committee_fraction#phase0 - compute_fork_version#phase0 - compute_pulled_up_tip#phase0 @@ -272,6 +311,7 @@ exceptions: - upgrade_lc_store_to_capella#capella - upgrade_lc_update_to_capella#capella # deneb + - compute_max_request_blob_sidecars#deneb - get_lc_execution_root#deneb - is_valid_light_client_header#deneb - prepare_execution_payload#deneb @@ -282,6 +322,7 @@ exceptions: - upgrade_lc_store_to_deneb#deneb - upgrade_lc_update_to_deneb#deneb # electra + - compute_max_request_blob_sidecars#electra - compute_weak_subjectivity_period#electra - current_sync_committee_gindex_at_slot#electra - finalized_root_gindex_at_slot#electra @@ -303,12 +344,20 @@ exceptions: - upgrade_lc_store_to_electra#electra - upgrade_lc_update_to_electra#electra # fulu + - compute_max_request_data_column_sidecars#fulu - compute_matrix#fulu + - verify_partial_data_column_header_inclusion_proof#fulu + - verify_partial_data_column_sidecar_kzg_proofs#fulu - get_blob_parameters#fulu - get_data_column_sidecars_from_block#fulu - get_data_column_sidecars_from_column_sidecar#fulu - recover_matrix#fulu # gloas + - compute_ptc#gloas + - initialize_ptc_window#gloas + - is_payload_data_available#gloas + - is_pending_validator#gloas + - process_ptc_window#gloas - compute_balance_weighted_acceptance#gloas - compute_balance_weighted_selection#gloas - compute_fork_version#gloas @@ -406,6 +455,28 @@ exceptions: - update_next_withdrawal_builder_index#gloas - update_payload_expected_withdrawals#gloas - update_proposer_boost_root#gloas + # heze + - compute_fork_version#heze + - get_forkchoice_store#heze + - get_inclusion_list_bits#heze + - get_inclusion_list_committee_assignment#heze + - get_inclusion_list_committee#heze + - get_inclusion_list_signature#heze + - get_inclusion_list_store#heze + - get_inclusion_list_submission_due_ms#heze + - get_inclusion_list_transactions#heze + - get_proposer_inclusion_list_cutoff_ms#heze + - get_view_freeze_cutoff_ms#heze + - is_inclusion_list_bits_inclusive#heze + - is_payload_inclusion_list_satisfied#heze + - is_valid_inclusion_list_signature#heze + - on_execution_payload#heze + - on_inclusion_list#heze + - prepare_execution_payload#heze + - process_inclusion_list#heze + - record_payload_inclusion_list_satisfaction#heze + - should_extend_payload#heze + - upgrade_to_heze#heze presets: # gloas @@ -414,3 +485,5 @@ exceptions: - MAX_BUILDERS_PER_WITHDRAWALS_SWEEP#gloas - MAX_PAYLOAD_ATTESTATIONS#gloas - PTC_SIZE#gloas + # heze + - INCLUSION_LIST_COMMITTEE_SIZE#heze diff --git a/WORKSPACE b/WORKSPACE index e79919e0003c..75fa7a15ff5d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -273,16 +273,16 @@ filegroup( url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz", ) -consensus_spec_version = "v1.7.0-alpha.2" +consensus_spec_version = "v1.7.0-alpha.4" load("@prysm//tools:download_spectests.bzl", "consensus_spec_tests") consensus_spec_tests( name = "consensus_spec_tests", flavors = { - "general": "sha256-iGQsGZ1cHah+2CSod9jC3kN8Ku4n6KO0hIwfINrn/po=", - "minimal": "sha256-TgcYt8N8sXSttdHTGvOa+exUZ1zn1UzlAMz0V7i37xc=", - "mainnet": "sha256-LnXyiLoJtrvEvbqLDSAAqpLMdN/lXv92SAgYG8fNjCs=", + "general": "sha256-kNJxuhCtW4RbuS9nb4U6JXHlPgTSg6G3hWeHFVB9gZ4=", + "minimal": "sha256-U1tCkXxtdI6mkEdk80i8z9LU2hAyf7Ztz5SBYo5oMzo=", + "mainnet": "sha256-Ga8VDOcNhTTdXDj8tSyBVYrwya9f1HO94ehJ5vv91r4=", }, version = consensus_spec_version, ) @@ -298,7 +298,7 @@ filegroup( visibility = ["//visibility:public"], ) """, - integrity = "sha256-Y/67Dg393PksZj5rTFNLntiJ6hNdB7Rxbu5gZE2gebY=", + integrity = "sha256-XHu5K/65mue+5po63L9yGTFjGfU1RGj4S56dmcHc2Rs=", strip_prefix = "consensus-specs-" + consensus_spec_version[1:], url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version, ) diff --git a/beacon-chain/blockchain/BUILD.bazel b/beacon-chain/blockchain/BUILD.bazel index f6d529317c6a..09e41c1ad71c 100644 --- a/beacon-chain/blockchain/BUILD.bazel +++ b/beacon-chain/blockchain/BUILD.bazel @@ -154,7 +154,6 @@ go_test( "//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/feed/state:go_default_library", - "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/peerdas:go_default_library", "//beacon-chain/core/signing:go_default_library", diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index 574372145ad1..c993dceddd12 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -17,10 +17,10 @@ import ( "github.com/OffchainLabs/prysm/v7/genesis" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" - "github.com/OffchainLabs/prysm/v7/time/slots" "github.com/OffchainLabs/prysm/v7/testing/assert" "github.com/OffchainLabs/prysm/v7/testing/require" "github.com/OffchainLabs/prysm/v7/testing/util" + "github.com/OffchainLabs/prysm/v7/time/slots" "google.golang.org/protobuf/proto" ) diff --git a/beacon-chain/blockchain/process_block.go b/beacon-chain/blockchain/process_block.go index 7e502ad0c307..033f21909e50 100644 --- a/beacon-chain/blockchain/process_block.go +++ b/beacon-chain/blockchain/process_block.go @@ -686,7 +686,7 @@ func (s *Service) handleBlockPayloadAttestations(ctx context.Context, blk interf if len(atts) == 0 { return nil } - committee, err := gloas.PayloadCommittee(ctx, st, blk.Slot()-1) + committee, err := st.PayloadCommitteeReadOnly(blk.Slot() - 1) if err != nil { return err } diff --git a/beacon-chain/blockchain/process_block_test.go b/beacon-chain/blockchain/process_block_test.go index 809025bc96e2..af4d802e91c1 100644 --- a/beacon-chain/blockchain/process_block_test.go +++ b/beacon-chain/blockchain/process_block_test.go @@ -14,7 +14,6 @@ import ( "github.com/OffchainLabs/prysm/v7/beacon-chain/cache" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks" statefeed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/state" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing" @@ -3556,7 +3555,7 @@ func TestHandleBlockPayloadAttestations(t *testing.T) { base, insertBlk := testGloasState(t, 1, parentRoot, blockHash) insertGloasBlock(t, s, base, insertBlk, blockRoot) - ptc, err := gloas.PayloadCommittee(ctx, headState, 1) + ptc, err := headState.PayloadCommitteeReadOnly(1) require.NoError(t, err) require.NotEqual(t, 0, len(ptc)) diff --git a/beacon-chain/blockchain/receive_payload_attestation_message_test.go b/beacon-chain/blockchain/receive_payload_attestation_message_test.go index 2559ec187984..b5f251fb5a83 100644 --- a/beacon-chain/blockchain/receive_payload_attestation_message_test.go +++ b/beacon-chain/blockchain/receive_payload_attestation_message_test.go @@ -3,7 +3,6 @@ package blockchain import ( "testing" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" mockExecution "github.com/OffchainLabs/prysm/v7/beacon-chain/execution/testing" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" "github.com/OffchainLabs/prysm/v7/config/params" @@ -51,7 +50,7 @@ func TestReceivePayloadAttestationMessage_ValidatorNotInPTC(t *testing.T) { require.NoError(t, err) s.head = &head{root: blockRoot, block: wsb, state: headState, slot: 1} - ptc, err := gloas.PayloadCommittee(ctx, headState, 1) + ptc, err := headState.PayloadCommitteeReadOnly(1) require.NoError(t, err) // Pick a validator index not in the PTC. @@ -100,7 +99,7 @@ func TestReceivePayloadAttestationMessage_OK(t *testing.T) { require.NoError(t, err) s.head = &head{root: blockRoot, block: wsb, state: headState, slot: 1} - ptc, err := gloas.PayloadCommittee(ctx, headState, 1) + ptc, err := headState.PayloadCommitteeReadOnly(1) require.NoError(t, err) require.NotEqual(t, 0, len(ptc)) diff --git a/beacon-chain/core/gloas/BUILD.bazel b/beacon-chain/core/gloas/BUILD.bazel index d35f090adb62..f5ce1efcad50 100644 --- a/beacon-chain/core/gloas/BUILD.bazel +++ b/beacon-chain/core/gloas/BUILD.bazel @@ -35,6 +35,7 @@ go_library( "//crypto/bls/common:go_default_library", "//crypto/hash:go_default_library", "//encoding/bytesutil:go_default_library", + "//monitoring/tracing/trace:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/version:go_default_library", diff --git a/beacon-chain/core/gloas/deposit_request.go b/beacon-chain/core/gloas/deposit_request.go index 26420a4f5975..affc25eef6f0 100644 --- a/beacon-chain/core/gloas/deposit_request.go +++ b/beacon-chain/core/gloas/deposit_request.go @@ -29,7 +29,7 @@ func processDepositRequests(ctx context.Context, beaconState state.BeaconState, // processDepositRequest processes the specific deposit request // -// +// // def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None: // # [New in Gloas:EIP7732] // builder_pubkeys = [b.pubkey for b in state.builders] @@ -40,8 +40,11 @@ func processDepositRequests(ctx context.Context, beaconState state.BeaconState, // # already exists with this pubkey, apply the deposit to their balance // is_builder = deposit_request.pubkey in builder_pubkeys // is_validator = deposit_request.pubkey in validator_pubkeys -// is_builder_prefix = is_builder_withdrawal_credential(deposit_request.withdrawal_credentials) -// if is_builder or (is_builder_prefix and not is_validator): +// if is_builder or ( +// is_builder_withdrawal_credential(deposit_request.withdrawal_credentials) +// and not is_validator +// and not is_pending_validator(state, deposit_request.pubkey) +// ): // # Apply builder deposits immediately // apply_deposit_for_builder( // state, diff --git a/beacon-chain/core/gloas/payload_attestation.go b/beacon-chain/core/gloas/payload_attestation.go index 27c84b4556f3..aea9a41309b8 100644 --- a/beacon-chain/core/gloas/payload_attestation.go +++ b/beacon-chain/core/gloas/payload_attestation.go @@ -19,6 +19,7 @@ import ( "github.com/OffchainLabs/prysm/v7/crypto/bls" "github.com/OffchainLabs/prysm/v7/crypto/hash" "github.com/OffchainLabs/prysm/v7/encoding/bytesutil" + "github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace" eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" "github.com/OffchainLabs/prysm/v7/time/slots" "github.com/pkg/errors" @@ -80,7 +81,7 @@ func ProcessPayloadAttestations(ctx context.Context, st state.BeaconState, body // indexedPayloadAttestation converts a payload attestation into its indexed form. func indexedPayloadAttestation(ctx context.Context, st state.ReadOnlyBeaconState, att *eth.PayloadAttestation) (*consensus_types.IndexedPayloadAttestation, error) { - committee, err := PayloadCommittee(ctx, st, att.Data.Slot) + committee, err := st.PayloadCommitteeReadOnly(att.Data.Slot) if err != nil { return nil, err } @@ -99,10 +100,10 @@ func indexedPayloadAttestation(ctx context.Context, st state.ReadOnlyBeaconState }, nil } -// PayloadCommittee returns the payload timeliness committee for a given slot for the state. +// computePTC computes the payload timeliness committee for a given slot. // -// -// def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: +// +// def compute_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: // """ // Get the payload timeliness committee for the given ``slot``. // """ @@ -118,7 +119,7 @@ func indexedPayloadAttestation(ctx context.Context, st state.ReadOnlyBeaconState // state, indices, seed, size=PTC_SIZE, shuffle_indices=False // ) // -func PayloadCommittee(ctx context.Context, st state.ReadOnlyBeaconState, slot primitives.Slot) ([]primitives.ValidatorIndex, error) { +func computePTC(ctx context.Context, st state.ReadOnlyBeaconState, slot primitives.Slot) ([]primitives.ValidatorIndex, error) { epoch := slots.ToEpoch(slot) seed, err := ptcSeed(st, epoch, slot) if err != nil { @@ -166,7 +167,7 @@ func PayloadCommitteeIndex( slot primitives.Slot, validatorIndex primitives.ValidatorIndex, ) (uint64, error) { - ptc, err := PayloadCommittee(ctx, st, slot) + ptc, err := st.PayloadCommitteeReadOnly(slot) if err != nil { return 0, err } @@ -342,3 +343,43 @@ func validIndexedPayloadAttestation(st state.ReadOnlyBeaconState, att *consensus } return nil } + +// ProcessPTCWindow rotates the cached PTC window at epoch boundaries by computing +// PTC assignments for the new lookahead epoch and shifting the window. +// +// +// def process_ptc_window(state: BeaconState) -> None: +// """ +// Update the cached PTC window. +// """ +// # Shift all epochs forward by one +// state.ptc_window[: len(state.ptc_window) - SLOTS_PER_EPOCH] = state.ptc_window[SLOTS_PER_EPOCH:] +// # Fill in the last epoch +// next_epoch = Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD + 1) +// start_slot = compute_start_slot_at_epoch(next_epoch) +// state.ptc_window[len(state.ptc_window) - SLOTS_PER_EPOCH :] = [ +// compute_ptc(state, Slot(slot)) for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH) +// ] +// +func ProcessPTCWindow(ctx context.Context, st state.BeaconState) error { + _, span := trace.StartSpan(ctx, "gloas.ProcessPTCWindow") + defer span.End() + + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + lastEpoch := slots.ToEpoch(st.Slot()) + params.BeaconConfig().MinSeedLookahead + 1 + startSlot, err := slots.EpochStart(lastEpoch) + if err != nil { + return err + } + + newSlots := make([]*eth.PTCs, slotsPerEpoch) + for i := range slotsPerEpoch { + ptc, err := computePTC(ctx, st, startSlot+primitives.Slot(i)) + if err != nil { + return err + } + newSlots[i] = ð.PTCs{ValidatorIndices: ptc} + } + + return st.RotatePTCWindow(newSlots) +} diff --git a/beacon-chain/core/gloas/payload_attestation_test.go b/beacon-chain/core/gloas/payload_attestation_test.go index 5c609ffd566c..e42a09804d5b 100644 --- a/beacon-chain/core/gloas/payload_attestation_test.go +++ b/beacon-chain/core/gloas/payload_attestation_test.go @@ -2,13 +2,14 @@ package gloas_test import ( "bytes" + "slices" "testing" "github.com/OffchainLabs/go-bitfield" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" + fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams" "github.com/OffchainLabs/prysm/v7/config/params" "github.com/OffchainLabs/prysm/v7/consensus-types/blocks" "github.com/OffchainLabs/prysm/v7/consensus-types/interfaces" @@ -119,7 +120,6 @@ func TestProcessPayloadAttestations_EmptyAggregationBits(t *testing.T) { } func TestProcessPayloadAttestations_HappyPath(t *testing.T) { - helpers.ClearCache() setupTestConfig(t) sk1, pk1 := newKey(t) @@ -150,7 +150,6 @@ func TestProcessPayloadAttestations_HappyPath(t *testing.T) { } func TestProcessPayloadAttestations_MultipleAttestations(t *testing.T) { - helpers.ClearCache() setupTestConfig(t) sk1, pk1 := newKey(t) @@ -211,12 +210,30 @@ func TestProcessPayloadAttestations_IndexedVerificationError(t *testing.T) { errIndex: 0, } err := gloas.ProcessPayloadAttestations(t.Context(), errState, body) - require.ErrorContains(t, "failed to convert to indexed form", err) - require.ErrorContains(t, "failed to sample beacon committee 0", err) + require.ErrorContains(t, "failed to verify indexed form", err) require.ErrorContains(t, "validator 0", err) } func newTestState(t *testing.T, vals []*eth.Validator, slot primitives.Slot) state.BeaconState { + t.Helper() + + st, err := testutil.NewBeaconStateGloas(func(seed *eth.BeaconStateGloas) error { + seed.Slot = slot + seed.Validators = vals + seed.Balances = make([]uint64, len(vals)) + for i, v := range vals { + seed.Balances[i] = v.EffectiveBalance + } + seed.PtcWindow = deterministicPTCWindow(len(vals)) + return nil + }) + require.NoError(t, err) + return st +} + +func newPhase0TestState(t *testing.T, vals []*eth.Validator, slot primitives.Slot) state.BeaconState { + t.Helper() + st, err := testutil.NewBeaconState() require.NoError(t, err) for _, v := range vals { @@ -224,10 +241,25 @@ func newTestState(t *testing.T, vals []*eth.Validator, slot primitives.Slot) sta require.NoError(t, st.AppendBalance(v.EffectiveBalance)) } require.NoError(t, st.SetSlot(slot)) - require.NoError(t, helpers.UpdateCommitteeCache(t.Context(), st, slots.ToEpoch(slot))) return st } +func deterministicPTCWindow(validatorCount int) []*eth.PTCs { + window := make([]*eth.PTCs, 3*params.BeaconConfig().SlotsPerEpoch) + indices := make([]primitives.ValidatorIndex, fieldparams.PTCSize) + if validatorCount > 0 { + for i := range indices { + indices[i] = primitives.ValidatorIndex(i % validatorCount) + } + } + for i := range window { + window[i] = ð.PTCs{ + ValidatorIndices: slices.Clone(indices), + } + } + return window +} + func setupTestConfig(t *testing.T) { params.SetupTestConfigCleanup(t) cfg := params.BeaconConfig().Copy() @@ -292,6 +324,50 @@ func signAttestation(t *testing.T, st state.ReadOnlyBeaconState, data *eth.Paylo return agg.Marshal() } +func TestProcessPTCWindow(t *testing.T) { + fuluSt, _ := testutil.DeterministicGenesisStateFulu(t, 256) + st, err := gloas.UpgradeToGloas(fuluSt) + require.NoError(t, err) + + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + + // Get original window. + origWindow, err := st.PTCWindow() + require.NoError(t, err) + windowSize := int(slotsPerEpoch.Mul(uint64(2 + params.BeaconConfig().MinSeedLookahead))) + require.Equal(t, windowSize, len(origWindow)) + + // Advance state to next epoch boundary so process_ptc_window sees a new epoch. + require.NoError(t, st.SetSlot(slotsPerEpoch)) + + // Process PTC window — should rotate. + require.NoError(t, gloas.ProcessPTCWindow(t.Context(), st)) + + newWindow, err := st.PTCWindow() + require.NoError(t, err) + require.Equal(t, windowSize, len(newWindow)) + + // The first two epochs should be the old epochs 1 and 2 (shifted left by one epoch). + for i := range 2 * slotsPerEpoch { + require.DeepEqual(t, origWindow[slotsPerEpoch+i], newWindow[i]) + } + + // The last epoch should be freshly computed — not all zeros. + lastStart := 2 * slotsPerEpoch + for i := range slotsPerEpoch { + ptcSlot := newWindow[lastStart+i] + require.NotNil(t, ptcSlot) + nonZero := false + for _, idx := range ptcSlot.ValidatorIndices { + if idx != 0 { + nonZero = true + break + } + } + require.Equal(t, true, nonZero, "last epoch slot %d should have non-zero validator indices", i) + } +} + type validatorLookupErrState struct { state.BeaconState errIndex primitives.ValidatorIndex diff --git a/beacon-chain/core/gloas/upgrade.go b/beacon-chain/core/gloas/upgrade.go index d72c4d7d663f..40229589887e 100644 --- a/beacon-chain/core/gloas/upgrade.go +++ b/beacon-chain/core/gloas/upgrade.go @@ -1,6 +1,8 @@ package gloas import ( + "context" + "github.com/OffchainLabs/prysm/v7/beacon-chain/core/time" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native" @@ -9,12 +11,13 @@ import ( "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" + "github.com/OffchainLabs/prysm/v7/time/slots" "github.com/pkg/errors" ) // UpgradeToGloas updates inputs a generic state to return the version Gloas state. // -// +// // def upgrade_to_gloas(pre: fulu.BeaconState) -> BeaconState: // epoch = fulu.get_current_epoch(pre) // @@ -81,6 +84,8 @@ import ( // latest_block_hash=pre.latest_execution_payload_header.block_hash, // # [New in Gloas:EIP7732] // payload_expected_withdrawals=[], +// # [New in Gloas:EIP7732] +// ptc_window=initialize_ptc_window(pre), // ) // // # [New in Gloas:EIP7732] @@ -143,12 +148,73 @@ func UpgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { if err != nil { return nil, errors.Wrap(err, "could not convert to gloas") } + ptcWindow, err := initializePTCWindow(context.Background(), s) + if err != nil { + return nil, errors.Wrap(err, "failed to initialize ptc window") + } + if err := s.SetPTCWindow(ptcWindow); err != nil { + return nil, errors.Wrap(err, "failed to set ptc window") + } if err := s.OnboardBuildersFromPendingDeposits(); err != nil { return nil, errors.Wrap(err, "failed to onboard builders from pending deposits") } return s, nil } +// initializePTCWindow builds the initial PTC window for the Gloas fork upgrade. +// +// +// def initialize_ptc_window( +// state: BeaconState, +// ) -> Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH]: +// """ +// Return the cached PTC window starting from the current epoch. +// Used to initialize the ``ptc_window`` field in the beacon state at genesis and after forks. +// """ +// empty_previous_epoch = [ +// Vector[ValidatorIndex, PTC_SIZE]([ValidatorIndex(0) for _ in range(PTC_SIZE)]) +// for _ in range(SLOTS_PER_EPOCH) +// ] +// +// ptcs = [] +// current_epoch = get_current_epoch(state) +// for e in range(1 + MIN_SEED_LOOKAHEAD): +// epoch = Epoch(current_epoch + e) +// start_slot = compute_start_slot_at_epoch(epoch) +// ptcs += [compute_ptc(state, Slot(start_slot + i)) for i in range(SLOTS_PER_EPOCH)] +// +// return empty_previous_epoch + ptcs +// +func initializePTCWindow(ctx context.Context, st state.ReadOnlyBeaconState) ([]*ethpb.PTCs, error) { + currentEpoch := slots.ToEpoch(st.Slot()) + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + windowSize := slotsPerEpoch.Mul(uint64(2 + params.BeaconConfig().MinSeedLookahead)) + window := make([]*ethpb.PTCs, 0, windowSize) + + // Previous epoch has no cached data at fork time — fill with empty slots. + for range slotsPerEpoch { + window = append(window, ðpb.PTCs{ + ValidatorIndices: make([]primitives.ValidatorIndex, fieldparams.PTCSize), + }) + } + + // Compute PTC for current epoch through lookahead. + startSlot, err := slots.EpochStart(currentEpoch) + if err != nil { + return nil, err + } + totalSlots := slotsPerEpoch.Mul(uint64(1 + params.BeaconConfig().MinSeedLookahead)) + for i := range totalSlots { + ptc, err := computePTC(ctx, st, startSlot+i) + if err != nil { + return nil, err + } + window = append(window, ðpb.PTCs{ValidatorIndices: ptc}) + } + + return window, nil +} + func upgradeToGloas(beaconState state.BeaconState) (state.BeaconState, error) { currentSyncCommittee, err := beaconState.CurrentSyncCommittee() if err != nil { diff --git a/beacon-chain/core/gloas/upgrade_test.go b/beacon-chain/core/gloas/upgrade_test.go index 58de5ecdd3e8..193d41f9b102 100644 --- a/beacon-chain/core/gloas/upgrade_test.go +++ b/beacon-chain/core/gloas/upgrade_test.go @@ -103,7 +103,7 @@ func TestUpgradeToGloas_Basic(t *testing.T) { } func TestUpgradeToGloas_OnboardsBuilderDeposit(t *testing.T) { - st, _ := util.DeterministicGenesisStateFulu(t, 4) + st, _ := util.DeterministicGenesisStateFulu(t, params.BeaconConfig().MaxValidatorsPerCommittee) sk, err := bls.RandKey() require.NoError(t, err) diff --git a/beacon-chain/core/transition/gloas.go b/beacon-chain/core/transition/gloas.go index 382cbf327374..6046a16172df 100644 --- a/beacon-chain/core/transition/gloas.go +++ b/beacon-chain/core/transition/gloas.go @@ -130,7 +130,7 @@ func gloasOperations(ctx context.Context, st state.BeaconState, block interfaces // // Spec definition: // -// +// // def process_epoch(state: BeaconState) -> None: // process_justification_and_finalization(state) // process_inactivity_updates(state) @@ -149,6 +149,8 @@ func gloasOperations(ctx context.Context, st state.BeaconState, block interfaces // process_participation_flag_updates(state) // process_sync_committee_updates(state) // process_proposer_lookahead(state) +// # [New in Gloas:EIP7732] +// process_ptc_window(state) // func processEpochGloas(ctx context.Context, state state.BeaconState) error { _, span := trace.StartSpan(ctx, "gloas.ProcessEpoch") @@ -222,5 +224,5 @@ func processEpochGloas(ctx context.Context, state state.BeaconState) error { if err := fulu.ProcessProposerLookahead(ctx, state); err != nil { return err } - return nil + return gloas.ProcessPTCWindow(ctx, state) } diff --git a/beacon-chain/rpc/core/BUILD.bazel b/beacon-chain/rpc/core/BUILD.bazel index d5d63be88a81..b982a3a1c2e6 100644 --- a/beacon-chain/rpc/core/BUILD.bazel +++ b/beacon-chain/rpc/core/BUILD.bazel @@ -20,7 +20,6 @@ go_library( "//beacon-chain/core/epoch/precompute:go_default_library", "//beacon-chain/core/feed:go_default_library", "//beacon-chain/core/feed/operation:go_default_library", - "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/time:go_default_library", "//beacon-chain/core/transition:go_default_library", diff --git a/beacon-chain/rpc/core/duties.go b/beacon-chain/rpc/core/duties.go index 5218da6ecb58..42cdc33e16fa 100644 --- a/beacon-chain/rpc/core/duties.go +++ b/beacon-chain/rpc/core/duties.go @@ -5,7 +5,6 @@ import ( "context" "sort" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" coreTime "github.com/OffchainLabs/prysm/v7/beacon-chain/core/time" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" @@ -221,7 +220,7 @@ func (s *Service) PTCDuties(ctx context.Context, st state.BeaconState, epoch pri return nil, &RpcError{Err: ctx.Err(), Reason: Internal} } - ptc, err := gloas.PayloadCommittee(ctx, st, slot) + ptc, err := st.PayloadCommitteeReadOnly(slot) if err != nil { return nil, &RpcError{Err: err, Reason: Internal} } diff --git a/beacon-chain/rpc/eth/validator/BUILD.bazel b/beacon-chain/rpc/eth/validator/BUILD.bazel index 8a5139530dfa..5b9a8bc01604 100644 --- a/beacon-chain/rpc/eth/validator/BUILD.bazel +++ b/beacon-chain/rpc/eth/validator/BUILD.bazel @@ -19,7 +19,6 @@ go_library( "//beacon-chain/builder:go_default_library", "//beacon-chain/cache:go_default_library", "//beacon-chain/core/feed/operation:go_default_library", - "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/operations/attestations:go_default_library", @@ -67,7 +66,6 @@ go_test( "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/builder/testing:go_default_library", "//beacon-chain/cache:go_default_library", - "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/transition:go_default_library", "//beacon-chain/db/testing:go_default_library", diff --git a/beacon-chain/rpc/eth/validator/handlers.go b/beacon-chain/rpc/eth/validator/handlers.go index 56137cff6289..3119bf00ac48 100644 --- a/beacon-chain/rpc/eth/validator/handlers.go +++ b/beacon-chain/rpc/eth/validator/handlers.go @@ -17,7 +17,6 @@ import ( "github.com/OffchainLabs/prysm/v7/api/server/structs" "github.com/OffchainLabs/prysm/v7/beacon-chain/builder" "github.com/OffchainLabs/prysm/v7/beacon-chain/cache" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/core" rpchelpers "github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/eth/helpers" @@ -1261,7 +1260,7 @@ func ptcDuties( return nil, ctx.Err() } - ptc, err := gloas.PayloadCommittee(ctx, st, slot) + ptc, err := st.PayloadCommitteeReadOnly(slot) if err != nil { return nil, errors.Wrapf(err, "failed to get PTC for slot %d", slot) } diff --git a/beacon-chain/rpc/eth/validator/handlers_test.go b/beacon-chain/rpc/eth/validator/handlers_test.go index afba74635f0a..fb6bcd9add76 100644 --- a/beacon-chain/rpc/eth/validator/handlers_test.go +++ b/beacon-chain/rpc/eth/validator/handlers_test.go @@ -17,7 +17,6 @@ import ( mockChain "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing" builderTest "github.com/OffchainLabs/prysm/v7/beacon-chain/builder/testing" "github.com/OffchainLabs/prysm/v7/beacon-chain/cache" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition" dbutil "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing" @@ -3226,9 +3225,7 @@ func TestGetPTCDuties(t *testing.T) { genesisTime := time.Now() // Need enough validators for PTC selection (PTC_SIZE is 512 on mainnet, 2 on minimal) numVals := uint64(fieldparams.PTCSize * 2) - fuluSt, _ := util.DeterministicGenesisStateFulu(t, numVals) - st, err := gloas.UpgradeToGloas(fuluSt) - require.NoError(t, err) + st, _ := util.DeterministicGenesisStateGloas(t, numVals) require.NoError(t, st.SetGenesisTime(genesisTime)) // Initialize the committee cache for epoch 0. require.NoError(t, helpers.UpdateCommitteeCache(t.Context(), st, 0)) diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v2_test.go b/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v2_test.go index a84a885935c3..457847d38acd 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v2_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v2_test.go @@ -10,7 +10,6 @@ import ( "github.com/OffchainLabs/prysm/v7/beacon-chain/cache/depositsnapshot" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/execution" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition" mockExecution "github.com/OffchainLabs/prysm/v7/beacon-chain/execution/testing" @@ -124,18 +123,24 @@ func TestGetDutiesV2_NextEpochProposerSlots(t *testing.T) { params.OverrideBeaconConfig(cfg) genesis := util.NewBeaconBlock() - deposits, _, err := util.DeterministicDepositsAndKeys(params.BeaconConfig().MinGenesisActiveValidatorCount) - require.NoError(t, err) - eth1Data, err := util.DeterministicEth1Data(len(deposits)) - require.NoError(t, err) - bs, err := transition.GenesisBeaconState(t.Context(), deposits, 0, eth1Data) - require.NoError(t, err) + var bs beaconstate.BeaconState + if tt.gloasForkEpoch == 0 { + bs, _ = util.DeterministicGenesisStateGloas(t, params.BeaconConfig().MinGenesisActiveValidatorCount) + } else { + deposits, _, err := util.DeterministicDepositsAndKeys(params.BeaconConfig().MinGenesisActiveValidatorCount) + require.NoError(t, err) + eth1Data, err := util.DeterministicEth1Data(len(deposits)) + require.NoError(t, err) + bs, err = transition.GenesisBeaconState(t.Context(), deposits, 0, eth1Data) + require.NoError(t, err) + } genesisRoot, err := genesis.Block.HashTreeRoot() require.NoError(t, err) - pubKeys := make([][]byte, len(deposits)) - for i := range deposits { - pubKeys[i] = deposits[i].Data.PublicKey + pubKeys := make([][]byte, len(bs.Validators())) + for i := range bs.Validators() { + pk := bs.PubkeyAtIndex(primitives.ValidatorIndex(i)) + pubKeys[i] = pk[:] } chain := &mockChain.ChainService{ @@ -649,13 +654,12 @@ func TestGetDutiesV2_SyncNotReady(t *testing.T) { // GloasForkEpoch and MaxEffectiveBalanceElectra in the beacon config. func ptcTestState(t *testing.T) (beaconstate.BeaconState, [][]byte) { t.Helper() - numVals := params.BeaconConfig().MinGenesisActiveValidatorCount - fuluSt, keys := util.DeterministicGenesisStateFulu(t, numVals) - st, err := gloas.UpgradeToGloas(fuluSt) - require.NoError(t, err) - pubKeys := make([][]byte, numVals) - for i := range numVals { - pubKeys[i] = keys[i].PublicKey().Marshal() + depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount + st, _ := util.DeterministicGenesisStateGloas(t, depChainStart) + pubKeys := make([][]byte, depChainStart) + for i := range depChainStart { + pk := st.PubkeyAtIndex(primitives.ValidatorIndex(i)) + pubKeys[i] = pk[:] } return st, pubKeys } @@ -691,7 +695,7 @@ func TestPTCDuties_PreGloasEpoch(t *testing.T) { } // TestPTCDuties_EmptyIndices verifies that an empty validator -// index list short-circuits and returns an empty map without calling PayloadCommittee. +// index list short-circuits and returns an empty map without calling PayloadCommitteeReadOnly. func TestPTCDuties_EmptyIndices(t *testing.T) { ptcTestConfig(t) @@ -771,7 +775,7 @@ func TestPTCDuties_CollectsAllSlots(t *testing.T) { for valIdx, assignedSlots := range result { expected := make([]primitives.Slot, 0) for s := epochStart; s < epochEnd; s++ { - ptc, err := gloas.PayloadCommittee(t.Context(), st, s) + ptc, err := st.PayloadCommitteeReadOnly(s) require.NoError(t, err) found := slices.Contains(ptc, valIdx) if found { diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v3_test.go b/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v3_test.go index 614b80e8de34..d897cb1b9f06 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v3_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/duties_v3_test.go @@ -6,7 +6,6 @@ import ( mockChain "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers" "github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition" dbutil "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing" @@ -321,9 +320,7 @@ func TestGetPTCDuties_OK(t *testing.T) { params.OverrideBeaconConfig(cfg) numVals := uint64(fieldparams.PTCSize + 64) - fuluSt, _ := util.DeterministicGenesisStateFulu(t, numVals) - bs, err := gloas.UpgradeToGloas(fuluSt) - require.NoError(t, err) + bs, _ := util.DeterministicGenesisStateGloas(t, numVals) require.NoError(t, helpers.UpdateCommitteeCache(t.Context(), bs, 0)) genesisRoot := [32]byte{0xaa} diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/payload_attestation_test.go b/beacon-chain/rpc/prysm/v1alpha1/validator/payload_attestation_test.go index 3cffb8ec9754..babb6ed05df2 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/payload_attestation_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/payload_attestation_test.go @@ -5,7 +5,6 @@ import ( "testing" chainMock "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" payloadattestation "github.com/OffchainLabs/prysm/v7/beacon-chain/operations/payloadattestation" p2pmock "github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/testing" mockSync "github.com/OffchainLabs/prysm/v7/beacon-chain/sync/initial-sync/testing" @@ -90,8 +89,8 @@ func TestSubmitPayloadAttestation_OK(t *testing.T) { slot := primitives.Slot(0) root := bytesutil.PadTo([]byte{0xBB}, 32) - st, _ := util.DeterministicGenesisState(t, 64) - ptc, err := gloas.PayloadCommittee(t.Context(), st, slot) + st, _ := util.DeterministicGenesisStateGloas(t, 64) + ptc, err := st.PayloadCommitteeReadOnly(slot) require.NoError(t, err) require.NotEqual(t, 0, len(ptc)) diff --git a/beacon-chain/state/interfaces_gloas.go b/beacon-chain/state/interfaces_gloas.go index 55ab05552310..830b7b2a0153 100644 --- a/beacon-chain/state/interfaces_gloas.go +++ b/beacon-chain/state/interfaces_gloas.go @@ -11,6 +11,8 @@ import ( type writeOnlyGloasFields interface { // Bids. SetExecutionPayloadBid(h interfaces.ROExecutionPayloadBid) error + SetPTCWindow([]*ethpb.PTCs) error + RotatePTCWindow([]*ethpb.PTCs) error // Builder pending payments / withdrawals. SetBuilderPendingPayment(index primitives.Slot, payment *ethpb.BuilderPendingPayment) error @@ -43,6 +45,8 @@ type writeOnlyGloasFields interface { type readOnlyGloasFields interface { // Bids. LatestExecutionPayloadBid() (interfaces.ROExecutionPayloadBid, error) + PTCWindow() ([]*ethpb.PTCs, error) + PayloadCommitteeReadOnly(slot primitives.Slot) ([]primitives.ValidatorIndex, error) // Builder pending payments / withdrawals. BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment, error) diff --git a/beacon-chain/state/state-native/beacon_state.go b/beacon-chain/state/state-native/beacon_state.go index a879a26f21e8..741c1482741b 100644 --- a/beacon-chain/state/state-native/beacon_state.go +++ b/beacon-chain/state/state-native/beacon_state.go @@ -79,6 +79,7 @@ type BeaconState struct { builderPendingWithdrawals []*ethpb.BuilderPendingWithdrawal latestBlockHash []byte payloadExpectedWithdrawals []*enginev1.Withdrawal + ptcWindow []*ethpb.PTCs id uint64 lock sync.RWMutex @@ -143,6 +144,7 @@ type beaconStateMarshalable struct { BuilderPendingWithdrawals []*ethpb.BuilderPendingWithdrawal `json:"builder_pending_withdrawals" yaml:"builder_pending_withdrawals"` LatestBlockHash []byte `json:"latest_block_hash" yaml:"latest_block_hash"` PayloadExpectedWithdrawals []*enginev1.Withdrawal `json:"payload_expected_withdrawals" yaml:"payload_expected_withdrawals"` + PtcWindow []*ethpb.PTCs `json:"ptc_window" yaml:"ptc_window"` } func (b *BeaconState) MarshalJSON() ([]byte, error) { @@ -205,6 +207,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) { BuilderPendingWithdrawals: b.builderPendingWithdrawals, LatestBlockHash: b.latestBlockHash, PayloadExpectedWithdrawals: b.payloadExpectedWithdrawals, + PtcWindow: b.ptcWindow, } return json.Marshal(marshalable) } diff --git a/beacon-chain/state/state-native/getters_gloas.go b/beacon-chain/state/state-native/getters_gloas.go index 2b63e8c97da2..73ee12bada57 100644 --- a/beacon-chain/state/state-native/getters_gloas.go +++ b/beacon-chain/state/state-native/getters_gloas.go @@ -34,6 +34,18 @@ func (b *BeaconState) LatestBlockHash() ([32]byte, error) { return [32]byte(b.latestBlockHash), nil } +// PTCWindow returns a copy of the cached PTC window. +func (b *BeaconState) PTCWindow() ([]*ethpb.PTCs, error) { + if b.version < version.Gloas { + return nil, errNotSupported("PTCWindow", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.ptcWindowVal(), nil +} + // IsAttestationSameSlot checks if the attestation is for the same slot as the block root in the state. // Spec v1.7.0-alpha pseudocode: // @@ -689,3 +701,64 @@ func (b *BeaconState) NextWithdrawalBuilderIndex() (primitives.BuilderIndex, err return b.nextWithdrawalBuilderIndex, nil } + +// PayloadCommitteeReadOnly returns the payload timeliness committee for a given slot +// by looking up the cached PTC window in state. +// +// +// def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: +// """ +// Get the payload timeliness committee for the given ``slot``. +// """ +// epoch = compute_epoch_at_slot(slot) +// state_epoch = get_current_epoch(state) +// if epoch < state_epoch: +// assert epoch + 1 == state_epoch +// return state.ptc_window[slot % SLOTS_PER_EPOCH] +// assert epoch <= state_epoch + MIN_SEED_LOOKAHEAD +// offset = (epoch - state_epoch + 1) * SLOTS_PER_EPOCH +// return state.ptc_window[offset + slot % SLOTS_PER_EPOCH] +// +func (b *BeaconState) PayloadCommitteeReadOnly(slot primitives.Slot) ([]primitives.ValidatorIndex, error) { + if b.version < version.Gloas { + return nil, errNotSupported("PayloadCommitteeReadOnly", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + offset, err := ptcWindowOffset(b.slot, slot) + if err != nil { + return nil, err + } + + if uint64(offset) >= uint64(len(b.ptcWindow)) { + return nil, fmt.Errorf("ptc window offset %d out of range for size %d", offset, len(b.ptcWindow)) + } + ptcSlot := b.ptcWindow[offset] + if ptcSlot == nil { + return nil, fmt.Errorf("ptc window slot %d is nil", offset) + } + + return ptcSlot.ValidatorIndices, nil +} + +func ptcWindowOffset(stateSlot, slot primitives.Slot) (primitives.Slot, error) { + epoch := slots.ToEpoch(slot) + stateEpoch := slots.ToEpoch(stateSlot) + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + + if epoch < stateEpoch { + if epoch+1 != stateEpoch { + return 0, fmt.Errorf("ptc window only supports previous epoch lookups: state_epoch=%d slot_epoch=%d", stateEpoch, epoch) + } + return slot % slotsPerEpoch, nil + } + + if epoch > stateEpoch+params.BeaconConfig().MinSeedLookahead { + return 0, fmt.Errorf("ptc window lookup out of range: state_epoch=%d slot_epoch=%d", stateEpoch, epoch) + } + + offset := slotsPerEpoch.Mul(uint64(epoch-stateEpoch+1)) + (slot % slotsPerEpoch) + return offset, nil +} diff --git a/beacon-chain/state/state-native/getters_gloas_test.go b/beacon-chain/state/state-native/getters_gloas_test.go index 924b88bea91a..3c7526781bbd 100644 --- a/beacon-chain/state/state-native/getters_gloas_test.go +++ b/beacon-chain/state/state-native/getters_gloas_test.go @@ -2,6 +2,7 @@ package state_native import ( "bytes" + "fmt" "testing" fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams" @@ -910,3 +911,207 @@ func TestExecutionPayloadAvailabilityVector(t *testing.T) { require.DeepEqual(t, availability, got2) }) } + +// testPTCWindow creates a PTC window of the expected size where each slot's +// first validator index encodes the slot offset for easy identification. +func testPTCWindow(t *testing.T) []*ethpb.PTCs { + t.Helper() + size := int(expectedPTCWindowSize()) + window := make([]*ethpb.PTCs, size) + for i := range window { + indices := make([]primitives.ValidatorIndex, fieldparams.PTCSize) + indices[0] = primitives.ValidatorIndex(i) + 1 // non-zero marker + window[i] = ðpb.PTCs{ValidatorIndices: indices} + } + return window +} + +func TestPtcWindowOffset(t *testing.T) { + params.SetupTestConfigCleanup(t) + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + + t.Run("current epoch slot", func(t *testing.T) { + // State at epoch 2, query slot in epoch 2 → offset = (2-2+1)*32 + slot%32 = 32 + slot%32 + stateSlot := slotsPerEpoch * 2 // slot 64, epoch 2 + querySlot := stateSlot + 3 // slot 67, epoch 2 + offset, err := ptcWindowOffset(stateSlot, querySlot) + require.NoError(t, err) + expected := slotsPerEpoch + (querySlot % slotsPerEpoch) // offset in "current epoch" region + require.Equal(t, expected, offset) + }) + + t.Run("previous epoch slot", func(t *testing.T) { + stateSlot := slotsPerEpoch * 2 // epoch 2 + querySlot := slotsPerEpoch + 5 // slot 37, epoch 1 (previous) + offset, err := ptcWindowOffset(stateSlot, querySlot) + require.NoError(t, err) + require.Equal(t, querySlot%slotsPerEpoch, offset) // previous epoch region + }) + + t.Run("lookahead epoch slot", func(t *testing.T) { + stateSlot := slotsPerEpoch * 2 // epoch 2 + querySlot := slotsPerEpoch*3 + 10 // slot 106, epoch 3 (lookahead with MinSeedLookahead=1) + offset, err := ptcWindowOffset(stateSlot, querySlot) + require.NoError(t, err) + // epoch_diff = 3-2 = 1, offset = (1+1)*32 + 10 = 74 + expected := slotsPerEpoch.Mul(uint64(slots.ToEpoch(querySlot)-slots.ToEpoch(stateSlot)+1)) + (querySlot % slotsPerEpoch) + require.Equal(t, expected, offset) + }) + + t.Run("error: epoch too far in past", func(t *testing.T) { + stateSlot := slotsPerEpoch * 3 // epoch 3 + querySlot := slotsPerEpoch + 1 // slot 33, epoch 1 (two epochs back) + _, err := ptcWindowOffset(stateSlot, querySlot) + require.ErrorContains(t, "only supports previous epoch lookups", err) + }) + + t.Run("error: epoch too far in future", func(t *testing.T) { + stateSlot := slotsPerEpoch * 2 // epoch 2 + querySlot := slotsPerEpoch*4 + 1 // epoch 4 (beyond MinSeedLookahead=1 from epoch 2) + _, err := ptcWindowOffset(stateSlot, querySlot) + require.ErrorContains(t, "out of range", err) + }) +} + +func TestPayloadCommitteeReadOnly(t *testing.T) { + params.SetupTestConfigCleanup(t) + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + + t.Run("returns error before gloas", func(t *testing.T) { + st := &BeaconState{version: version.Fulu} + _, err := st.PayloadCommitteeReadOnly(0) + require.ErrorContains(t, "PayloadCommitteeReadOnly", err) + }) + + t.Run("returns committee from current epoch", func(t *testing.T) { + window := testPTCWindow(t) + st := &BeaconState{ + version: version.Gloas, + slot: slotsPerEpoch * 2, // epoch 2 + ptcWindow: window, + } + // Query slot 64 (first slot of epoch 2) → offset = 32 + ptc, err := st.PayloadCommitteeReadOnly(slotsPerEpoch * 2) + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(slotsPerEpoch+1), ptc[0]) + }) + + t.Run("returns committee from previous epoch", func(t *testing.T) { + window := testPTCWindow(t) + st := &BeaconState{ + version: version.Gloas, + slot: slotsPerEpoch * 2, // epoch 2 + ptcWindow: window, + } + // Query slot 35 (epoch 1, offset 3) → previous epoch region, offset = 3 + ptc, err := st.PayloadCommitteeReadOnly(slotsPerEpoch + 3) + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(4), ptc[0]) // window[3] has marker 4 + }) + + t.Run("error on nil ptc slot", func(t *testing.T) { + window := testPTCWindow(t) + window[slotsPerEpoch] = nil // nil out the first current-epoch slot + st := &BeaconState{ + version: version.Gloas, + slot: slotsPerEpoch * 2, + ptcWindow: window, + } + _, err := st.PayloadCommitteeReadOnly(slotsPerEpoch * 2) + require.ErrorContains(t, "is nil", err) + }) +} + +func TestSetPTCWindow(t *testing.T) { + params.SetupTestConfigCleanup(t) + + t.Run("returns error before gloas", func(t *testing.T) { + st := &BeaconState{version: version.Fulu} + err := st.SetPTCWindow(nil) + require.ErrorContains(t, "SetPTCWindow", err) + }) + + t.Run("rejects wrong size", func(t *testing.T) { + st, err := InitializeFromProtoGloas(ðpb.BeaconStateGloas{ + PtcWindow: testPTCWindow(t), + }) + require.NoError(t, err) + err = st.SetPTCWindow(make([]*ethpb.PTCs, 10)) + require.ErrorContains(t, "invalid size", err) + }) + + t.Run("sets and copies window", func(t *testing.T) { + st, err := InitializeFromProtoGloas(ðpb.BeaconStateGloas{ + PtcWindow: testPTCWindow(t), + }) + require.NoError(t, err) + + newWindow := testPTCWindow(t) + newWindow[0].ValidatorIndices[0] = 999 + require.NoError(t, st.SetPTCWindow(newWindow)) + + got, err := st.PTCWindow() + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(999), got[0].ValidatorIndices[0]) + + // Verify it's a copy — mutating the input doesn't affect state. + newWindow[0].ValidatorIndices[0] = 0 + got2, err := st.PTCWindow() + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(999), got2[0].ValidatorIndices[0]) + }) +} + +func TestRotatePTCWindow(t *testing.T) { + params.SetupTestConfigCleanup(t) + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + + t.Run("returns error before gloas", func(t *testing.T) { + st := &BeaconState{version: version.Fulu} + err := st.RotatePTCWindow(nil) + require.ErrorContains(t, "RotatePTCWindow", err) + }) + + t.Run("rejects wrong new epoch size", func(t *testing.T) { + st, err := InitializeFromProtoGloas(ðpb.BeaconStateGloas{ + PtcWindow: testPTCWindow(t), + }) + require.NoError(t, err) + err = st.RotatePTCWindow(make([]*ethpb.PTCs, 5)) + require.ErrorContains(t, "invalid new epoch slots size", err) + }) + + t.Run("rotates window correctly", func(t *testing.T) { + origWindow := testPTCWindow(t) + st, err := InitializeFromProtoGloas(ðpb.BeaconStateGloas{ + PtcWindow: origWindow, + }) + require.NoError(t, err) + + // Build new epoch slots with distinct markers. + newEpoch := make([]*ethpb.PTCs, slotsPerEpoch) + for i := range newEpoch { + indices := make([]primitives.ValidatorIndex, fieldparams.PTCSize) + indices[0] = primitives.ValidatorIndex(1000 + i) + newEpoch[i] = ðpb.PTCs{ValidatorIndices: indices} + } + require.NoError(t, st.RotatePTCWindow(newEpoch)) + + got, err := st.PTCWindow() + require.NoError(t, err) + + // First two epochs should be shifted from original epochs 1 and 2. + for i := range 2 * slotsPerEpoch { + expected := origWindow[slotsPerEpoch+i].ValidatorIndices[0] + require.Equal(t, expected, got[i].ValidatorIndices[0], + fmt.Sprintf("mismatch at shifted slot %d", i)) + } + + // Last epoch should be the new epoch slots. + lastStart := 2 * slotsPerEpoch + for i := range slotsPerEpoch { + require.Equal(t, primitives.ValidatorIndex(1000+i), got[lastStart+i].ValidatorIndices[0], + fmt.Sprintf("mismatch at new slot %d", i)) + } + }) +} diff --git a/beacon-chain/state/state-native/getters_state.go b/beacon-chain/state/state-native/getters_state.go index 7ceaaa731a88..7f9ac312b2b1 100644 --- a/beacon-chain/state/state-native/getters_state.go +++ b/beacon-chain/state/state-native/getters_state.go @@ -312,6 +312,7 @@ func (b *BeaconState) ToProtoUnsafe() any { BuilderPendingWithdrawals: b.builderPendingWithdrawals, LatestBlockHash: b.latestBlockHash, PayloadExpectedWithdrawals: b.payloadExpectedWithdrawals, + PtcWindow: b.ptcWindow, } default: return nil @@ -616,6 +617,7 @@ func (b *BeaconState) ToProto() any { BuilderPendingWithdrawals: b.builderPendingWithdrawalsVal(), LatestBlockHash: b.latestBlockHashVal(), PayloadExpectedWithdrawals: b.payloadExpectedWithdrawalsVal(), + PtcWindow: b.ptcWindowVal(), } default: return nil diff --git a/beacon-chain/state/state-native/gloas.go b/beacon-chain/state/state-native/gloas.go index 0b00374c0f50..22c6247be20f 100644 --- a/beacon-chain/state/state-native/gloas.go +++ b/beacon-chain/state/state-native/gloas.go @@ -91,3 +91,9 @@ func (b *BeaconState) payloadExpectedWithdrawalsVal() []*enginev1.Withdrawal { return withdrawals } + +// ptcWindowVal returns a copy of the cached PTC window. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) ptcWindowVal() []*ethpb.PTCs { + return ethpb.CopyPTCWindow(b.ptcWindow) +} diff --git a/beacon-chain/state/state-native/gloas_test.go b/beacon-chain/state/state-native/gloas_test.go index 2e74103fd198..fa5157cc0714 100644 --- a/beacon-chain/state/state-native/gloas_test.go +++ b/beacon-chain/state/state-native/gloas_test.go @@ -3,6 +3,7 @@ package state_native import ( "testing" + "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" "github.com/stretchr/testify/require" @@ -41,3 +42,23 @@ func TestPayloadExpectedWithdrawalsVal(t *testing.T) { require.Equal(t, st.payloadExpectedWithdrawals[0], got[0]) require.NotSame(t, st.payloadExpectedWithdrawals[0], got[0]) } + +func TestPTCWindowVal(t *testing.T) { + st := &BeaconState{} + + require.Nil(t, st.ptcWindowVal()) + + st.ptcWindow = []*ethpb.PTCs{ + {ValidatorIndices: []primitives.ValidatorIndex{1, 2}}, + nil, + } + + got := st.ptcWindowVal() + require.Len(t, got, 2) + require.Nil(t, got[1]) + require.Equal(t, st.ptcWindow[0], got[0]) + require.NotSame(t, st.ptcWindow[0], got[0]) + + got[0].ValidatorIndices[0] = 99 + require.Equal(t, primitives.ValidatorIndex(1), st.ptcWindow[0].ValidatorIndices[0]) +} diff --git a/beacon-chain/state/state-native/hasher.go b/beacon-chain/state/state-native/hasher.go index 3ca5f853734a..bca6a7fb5ff7 100644 --- a/beacon-chain/state/state-native/hasher.go +++ b/beacon-chain/state/state-native/hasher.go @@ -381,6 +381,13 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b } fieldRoots[types.PayloadExpectedWithdrawals.RealPosition()] = expectedWithdrawalsRoot[:] + + ptcWindowRoot, err := stateutil.PTCWindowRoot(state.ptcWindow) + if err != nil { + return nil, errors.Wrap(err, "could not compute ptc window merkleization") + } + + fieldRoots[types.PTCWindow.RealPosition()] = ptcWindowRoot[:] } return fieldRoots, nil } diff --git a/beacon-chain/state/state-native/setters_gloas.go b/beacon-chain/state/state-native/setters_gloas.go index ac4a3058eedd..e9232f3d710e 100644 --- a/beacon-chain/state/state-native/setters_gloas.go +++ b/beacon-chain/state/state-native/setters_gloas.go @@ -642,7 +642,7 @@ func decreaseBalanceWithVal(currBalance, delta primitives.Gwei) primitives.Gwei // OnboardBuildersFromPendingDeposits applies any pending builder deposits at the fork. // It mutates the state and prunes pending deposits accordingly. // -// +// // def onboard_builders_from_pending_deposits(state: BeaconState) -> None: // """ // Applies any pending deposit for builders, effectively @@ -767,3 +767,66 @@ func (b *BeaconState) OnboardBuildersFromPendingDeposits() error { return nil } + +// SetPTCWindow is a mutating call to the beacon state which sets the cached PTC window. +func (b *BeaconState) SetPTCWindow(window []*ethpb.PTCs) error { + if b.version < version.Gloas { + return errNotSupported("SetPTCWindow", b.version) + } + + expected := expectedPTCWindowSize() + if uint64(len(window)) != uint64(expected) { + return fmt.Errorf("invalid size for ptc window: got %d want %d", len(window), expected) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[types.PTCWindow].MinusRef() + b.sharedFieldReferences[types.PTCWindow] = stateutil.NewRef(1) + b.ptcWindow = ethpb.CopyPTCWindow(window) + b.markFieldAsDirty(types.PTCWindow) + return nil +} + +// RotatePTCWindow shifts the PTC window left by one epoch and fills the last epoch +// with the provided new slots. This performs the rotation in-place under lock. +func (b *BeaconState) RotatePTCWindow(newEpochSlots []*ethpb.PTCs) error { + if b.version < version.Gloas { + return errNotSupported("RotatePTCWindow", b.version) + } + + slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch + if uint64(len(newEpochSlots)) != uint64(slotsPerEpoch) { + return fmt.Errorf("invalid new epoch slots size: got %d want %d", len(newEpochSlots), slotsPerEpoch) + } + + b.lock.Lock() + defer b.lock.Unlock() + + expected := expectedPTCWindowSize() + if uint64(len(b.ptcWindow)) != uint64(expected) { + return fmt.Errorf("invalid ptc window size: got %d want %d", len(b.ptcWindow), expected) + } + + b.sharedFieldReferences[types.PTCWindow].MinusRef() + b.sharedFieldReferences[types.PTCWindow] = stateutil.NewRef(1) + + newWindow := make([]*ethpb.PTCs, expected) + + // Shift left by one epoch. + lastEpochStart := expected - slotsPerEpoch + copy(newWindow[:lastEpochStart], b.ptcWindow[slotsPerEpoch:]) + + // Fill the last epoch with copied new slots. + copy(newWindow[lastEpochStart:], ethpb.CopyPTCWindow(newEpochSlots)) + + b.ptcWindow = newWindow + + b.markFieldAsDirty(types.PTCWindow) + return nil +} + +func expectedPTCWindowSize() primitives.Slot { + return params.BeaconConfig().SlotsPerEpoch.Mul(uint64(2 + params.BeaconConfig().MinSeedLookahead)) +} diff --git a/beacon-chain/state/state-native/state_trie.go b/beacon-chain/state/state-native/state_trie.go index 959f9f725828..b43485b78e2c 100644 --- a/beacon-chain/state/state-native/state_trie.go +++ b/beacon-chain/state/state-native/state_trie.go @@ -128,6 +128,7 @@ var ( types.BuilderPendingWithdrawals, types.LatestBlockHash, types.PayloadExpectedWithdrawals, + types.PTCWindow, } gloasFields = slices.Concat( @@ -148,7 +149,7 @@ const ( denebSharedFieldRefCount = 7 electraSharedFieldRefCount = 10 fuluSharedFieldRefCount = 11 - gloasSharedFieldRefCount = 13 // Adds Builders + BuilderPendingWithdrawals to the shared-ref set and LatestExecutionPayloadHeader is removed + gloasSharedFieldRefCount = 14 // Adds Builders + BuilderPendingWithdrawals + PTCWindow to the shared-ref set and LatestExecutionPayloadHeader is removed ) // InitializeFromProtoPhase0 the beacon state from a protobuf representation. @@ -827,6 +828,7 @@ func InitializeFromProtoUnsafeGloas(st *ethpb.BeaconStateGloas) (state.BeaconSta builderPendingWithdrawals: st.BuilderPendingWithdrawals, latestBlockHash: st.LatestBlockHash, payloadExpectedWithdrawals: st.PayloadExpectedWithdrawals, + ptcWindow: st.PtcWindow, dirtyFields: make(map[types.FieldIndex]bool, fieldCount), dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount), stateFieldLeaves: make(map[types.FieldIndex]*fieldtrie.FieldTrie, fieldCount), @@ -868,6 +870,7 @@ func InitializeFromProtoUnsafeGloas(st *ethpb.BeaconStateGloas) (state.BeaconSta b.sharedFieldReferences[types.ProposerLookahead] = stateutil.NewRef(1) b.sharedFieldReferences[types.Builders] = stateutil.NewRef(1) // New in Gloas. b.sharedFieldReferences[types.BuilderPendingWithdrawals] = stateutil.NewRef(1) // New in Gloas. + b.sharedFieldReferences[types.PTCWindow] = stateutil.NewRef(1) // New in Gloas. state.Count.Inc() // Finalizer runs when dst is being destroyed in garbage collection. @@ -926,6 +929,7 @@ func (b *BeaconState) Copy() state.BeaconState { eth1DataVotes: b.eth1DataVotes, slashings: b.slashings, proposerLookahead: b.proposerLookahead, + ptcWindow: b.ptcWindow, // Large arrays, increases over time. balancesMultiValue: b.balancesMultiValue, @@ -1411,6 +1415,8 @@ func (b *BeaconState) rootSelector(ctx context.Context, field types.FieldIndex) return bytesutil.ToBytes32(b.latestBlockHash), nil case types.PayloadExpectedWithdrawals: return ssz.WithdrawalSliceRoot(b.payloadExpectedWithdrawals, fieldparams.MaxWithdrawalsPerPayload) + case types.PTCWindow: + return stateutil.PTCWindowRoot(b.ptcWindow) } return [32]byte{}, errors.New("invalid field index provided") } diff --git a/beacon-chain/state/state-native/types/types.go b/beacon-chain/state/state-native/types/types.go index 158f9d01aba1..d4adb875281a 100644 --- a/beacon-chain/state/state-native/types/types.go +++ b/beacon-chain/state/state-native/types/types.go @@ -130,6 +130,8 @@ func (f FieldIndex) String() string { return "latestBlockHash" case PayloadExpectedWithdrawals: return "payloadExpectedWithdrawals" + case PTCWindow: + return "ptcWindow" default: return fmt.Sprintf("unknown field index number: %d", f) } @@ -229,6 +231,8 @@ func (f FieldIndex) RealPosition() int { return 43 case PayloadExpectedWithdrawals: return 44 + case PTCWindow: + return 45 default: return -1 } @@ -302,6 +306,7 @@ const ( BuilderPendingWithdrawals // Gloas: EIP-7732 LatestBlockHash // Gloas: EIP-7732 PayloadExpectedWithdrawals // Gloas: EIP-7732 + PTCWindow // Gloas: EIP-7732 ) // Enumerator keeps track of the number of states created since the node's start. diff --git a/beacon-chain/state/stateutil/BUILD.bazel b/beacon-chain/state/stateutil/BUILD.bazel index 9f6d39887cf8..f3955b342c2e 100644 --- a/beacon-chain/state/stateutil/BUILD.bazel +++ b/beacon-chain/state/stateutil/BUILD.bazel @@ -22,6 +22,7 @@ go_library( "pending_deposits_root.go", "pending_partial_withdrawals_root.go", "proposer_lookahead_root.go", + "ptc_window_root.go", "reference.go", "sync_committee.root.go", "trie_helpers.go", diff --git a/beacon-chain/state/stateutil/ptc_window_root.go b/beacon-chain/state/stateutil/ptc_window_root.go new file mode 100644 index 000000000000..014f883f45f6 --- /dev/null +++ b/beacon-chain/state/stateutil/ptc_window_root.go @@ -0,0 +1,28 @@ +package stateutil + +import ( + "fmt" + + "github.com/OffchainLabs/prysm/v7/encoding/ssz" + ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" +) + +// PTCWindowRoot computes the merkle root of the cached PTC window. +func PTCWindowRoot(ptcs []*ethpb.PTCs) ([32]byte, error) { + roots := make([][32]byte, len(ptcs)) + + for i, ptc := range ptcs { + if ptc == nil { + return [32]byte{}, fmt.Errorf("invalid PTC at position %d", i) + } + + r, err := ptc.HashTreeRoot() + if err != nil { + return [32]byte{}, err + } + + roots[i] = r + } + + return ssz.MerkleizeVector(roots, uint64(len(roots))), nil +} diff --git a/beacon-chain/sync/BUILD.bazel b/beacon-chain/sync/BUILD.bazel index 9553ded53ab8..16c2e21af7d6 100644 --- a/beacon-chain/sync/BUILD.bazel +++ b/beacon-chain/sync/BUILD.bazel @@ -253,7 +253,6 @@ go_test( "//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/feed:go_default_library", "//beacon-chain/core/feed/operation:go_default_library", - "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/peerdas:go_default_library", "//beacon-chain/core/signing:go_default_library", diff --git a/beacon-chain/sync/subscriber_payload_attestation_test.go b/beacon-chain/sync/subscriber_payload_attestation_test.go index 206f30cf3eee..5c38d7053bb7 100644 --- a/beacon-chain/sync/subscriber_payload_attestation_test.go +++ b/beacon-chain/sync/subscriber_payload_attestation_test.go @@ -6,7 +6,6 @@ import ( mock "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing" "github.com/OffchainLabs/prysm/v7/beacon-chain/cache" - "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" "github.com/OffchainLabs/prysm/v7/beacon-chain/operations/payloadattestation" "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" @@ -33,8 +32,8 @@ func TestPayloadAttestationSubscriber_NilData(t *testing.T) { } func TestPayloadAttestationSubscriber_NoPool(t *testing.T) { - st, _ := util.DeterministicGenesisState(t, 64) - ptc, err := gloas.PayloadCommittee(t.Context(), st, 0) + st, _ := util.DeterministicGenesisStateGloas(t, 64) + ptc, err := st.PayloadCommitteeReadOnly(0) require.NoError(t, err) require.NotEmpty(t, ptc) @@ -81,8 +80,8 @@ func TestPayloadAttestationSubscriber_HeadStateError(t *testing.T) { } func TestPayloadAttestationSubscriber_ValidatorInPTC(t *testing.T) { - st, _ := util.DeterministicGenesisState(t, 64) - ptc, err := gloas.PayloadCommittee(t.Context(), st, 0) + st, _ := util.DeterministicGenesisStateGloas(t, 64) + ptc, err := st.PayloadCommitteeReadOnly(0) require.NoError(t, err) require.NotEmpty(t, ptc) @@ -108,8 +107,8 @@ func TestPayloadAttestationSubscriber_ValidatorInPTC(t *testing.T) { } func TestPayloadAttestationSubscriber_ValidatorNotInPTC(t *testing.T) { - st, _ := util.DeterministicGenesisState(t, 64) - ptc, err := gloas.PayloadCommittee(t.Context(), st, 0) + st, _ := util.DeterministicGenesisStateGloas(t, 64) + ptc, err := st.PayloadCommitteeReadOnly(0) require.NoError(t, err) ptcSet := make(map[primitives.ValidatorIndex]bool, len(ptc)) diff --git a/changelog/terence_gloas-cached-ptc-window.md b/changelog/terence_gloas-cached-ptc-window.md new file mode 100644 index 000000000000..3f4a040b1747 --- /dev/null +++ b/changelog/terence_gloas-cached-ptc-window.md @@ -0,0 +1,3 @@ +### Changed + +- Implement the Gloas cached payload timeliness committee window in state, including fork initialization, epoch rotation, and cached committee lookups. diff --git a/config/params/loader_test.go b/config/params/loader_test.go index e36a1e1a90a7..ea2e997698be 100644 --- a/config/params/loader_test.go +++ b/config/params/loader_test.go @@ -31,31 +31,24 @@ var placeholderFields = []string{ "EIP6110_FORK_VERSION", "EIP7002_FORK_EPOCH", "EIP7002_FORK_VERSION", - "EIP7441_FORK_EPOCH", - "EIP7441_FORK_VERSION", "EIP7732_FORK_EPOCH", "EIP7732_FORK_VERSION", - "EIP7805_FORK_EPOCH", - "EIP7805_FORK_VERSION", "EIP7928_FORK_EPOCH", "EIP7928_FORK_VERSION", - "EPOCHS_PER_SHUFFLING_PHASE", "FIELD_ELEMENTS_PER_CELL", // Configured as a constant in config/fieldparams/mainnet.go "FIELD_ELEMENTS_PER_EXT_BLOB", // Configured in proto/ssz_proto_library.bzl - "INCLUSION_LIST_SUBMISSION_DEADLINE", + "HEZE_FORK_EPOCH", + "HEZE_FORK_VERSION", + "INCLUSION_LIST_COMMITTEE_SIZE", "INCLUSION_LIST_SUBMISSION_DUE_BPS", "KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH", // Configured in proto/ssz_proto_library.bzl "MAX_BYTES_PER_INCLUSION_LIST", - "MAX_REQUEST_BLOB_SIDECARS_FULU", "MAX_REQUEST_INCLUSION_LIST", "NUMBER_OF_COLUMNS", // Configured as a constant in config/fieldparams/mainnet.go - "PROPOSER_INCLUSION_LIST_CUTOFF", "PROPOSER_INCLUSION_LIST_CUTOFF_BPS", - "PROPOSER_SELECTION_GAP", "TARGET_NUMBER_OF_PEERS", "UPDATE_TIMEOUT", "VIEW_FREEZE_CUTOFF_BPS", - "VIEW_FREEZE_DEADLINE", "WHISK_EPOCHS_PER_SHUFFLING_PHASE", "WHISK_FORK_EPOCH", "WHISK_FORK_VERSION", diff --git a/config/params/mainnet_config.go b/config/params/mainnet_config.go index 8d2ccb4eedd5..04ad7dc43a7b 100644 --- a/config/params/mainnet_config.go +++ b/config/params/mainnet_config.go @@ -220,7 +220,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ BeaconStateDenebFieldCount: 28, BeaconStateElectraFieldCount: 37, BeaconStateFuluFieldCount: 38, - BeaconStateGloasFieldCount: 45, + BeaconStateGloasFieldCount: 46, // Slasher related values. WeakSubjectivityPeriod: 54000, diff --git a/proto/prysm/v1alpha1/BUILD.bazel b/proto/prysm/v1alpha1/BUILD.bazel index 07d1b566349c..29b4f8a0b2ac 100644 --- a/proto/prysm/v1alpha1/BUILD.bazel +++ b/proto/prysm/v1alpha1/BUILD.bazel @@ -201,6 +201,7 @@ ssz_gloas_objs = [ "BuilderPendingWithdrawal", "DataColumnSidecarGloas", "ExecutionPayloadEnvelope", + "PTCs", "ProposerPreferences", "SignedProposerPreferences", "PayloadAttestation", diff --git a/proto/prysm/v1alpha1/cloners.go b/proto/prysm/v1alpha1/cloners.go index 0a2681e78e25..4c69ffdcdfaa 100644 --- a/proto/prysm/v1alpha1/cloners.go +++ b/proto/prysm/v1alpha1/cloners.go @@ -1,6 +1,7 @@ package eth import ( + "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" "github.com/OffchainLabs/prysm/v7/encoding/bytesutil" ) @@ -245,6 +246,28 @@ func copyBlindedExecutionPayloadEnvelope(env *BlindedExecutionPayloadEnvelope) * } } +// CopyPTCs creates a deep copy of a PTC slot. +func CopyPTCs(slot *PTCs) *PTCs { + if slot == nil { + return nil + } + indices := make([]primitives.ValidatorIndex, len(slot.ValidatorIndices)) + copy(indices, slot.ValidatorIndices) + return &PTCs{ValidatorIndices: indices} +} + +// CopyPTCWindow creates a deep copy of a PTC window. +func CopyPTCWindow(window []*PTCs) []*PTCs { + if window == nil { + return nil + } + copied := make([]*PTCs, len(window)) + for i, slot := range window { + copied[i] = CopyPTCs(slot) + } + return copied +} + // CopyBuilderPendingPayment creates a deep copy of a builder pending payment. func CopyBuilderPendingPayment(original *BuilderPendingPayment) *BuilderPendingPayment { if original == nil { diff --git a/proto/prysm/v1alpha1/gloas.pb.go b/proto/prysm/v1alpha1/gloas.pb.go index 07d18b7ea04c..81db34a72c60 100755 --- a/proto/prysm/v1alpha1/gloas.pb.go +++ b/proto/prysm/v1alpha1/gloas.pb.go @@ -860,6 +860,7 @@ type BeaconStateGloas struct { BuilderPendingWithdrawals []*BuilderPendingWithdrawal `protobuf:"bytes,14005,rep,name=builder_pending_withdrawals,json=builderPendingWithdrawals,proto3" json:"builder_pending_withdrawals,omitempty" ssz-max:"1048576"` LatestBlockHash []byte `protobuf:"bytes,14006,opt,name=latest_block_hash,json=latestBlockHash,proto3" json:"latest_block_hash,omitempty" ssz-size:"32"` PayloadExpectedWithdrawals []*v1.Withdrawal `protobuf:"bytes,14007,rep,name=payload_expected_withdrawals,json=payloadExpectedWithdrawals,proto3" json:"payload_expected_withdrawals,omitempty" ssz-max:"16"` + PtcWindow []*PTCs `protobuf:"bytes,14008,rep,name=ptc_window,json=ptcWindow,proto3" json:"ptc_window,omitempty" ssz-size:"96"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1209,6 +1210,57 @@ func (x *BeaconStateGloas) GetPayloadExpectedWithdrawals() []*v1.Withdrawal { return nil } +func (x *BeaconStateGloas) GetPtcWindow() []*PTCs { + if x != nil { + return x.PtcWindow + } + return nil +} + +type PTCs struct { + state protoimpl.MessageState `protogen:"open.v1"` + ValidatorIndices []github_com_OffchainLabs_prysm_v7_consensus_types_primitives.ValidatorIndex `protobuf:"varint,1,rep,packed,name=validator_indices,json=validatorIndices,proto3" json:"validator_indices,omitempty" cast-type:"github.com/OffchainLabs/prysm/v7/consensus-types/primitives.ValidatorIndex" ssz-size:"512"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PTCs) Reset() { + *x = PTCs{} + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PTCs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PTCs) ProtoMessage() {} + +func (x *PTCs) ProtoReflect() protoreflect.Message { + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PTCs.ProtoReflect.Descriptor instead. +func (*PTCs) Descriptor() ([]byte, []int) { + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{12} +} + +func (x *PTCs) GetValidatorIndices() []github_com_OffchainLabs_prysm_v7_consensus_types_primitives.ValidatorIndex { + if x != nil { + return x.ValidatorIndices + } + return []github_com_OffchainLabs_prysm_v7_consensus_types_primitives.ValidatorIndex(nil) +} + type BuilderPendingPayment struct { state protoimpl.MessageState `protogen:"open.v1"` Weight github_com_OffchainLabs_prysm_v7_consensus_types_primitives.Gwei `protobuf:"varint,1,opt,name=weight,proto3" json:"weight,omitempty" cast-type:"github.com/OffchainLabs/prysm/v7/consensus-types/primitives.Gwei"` @@ -1219,7 +1271,7 @@ type BuilderPendingPayment struct { func (x *BuilderPendingPayment) Reset() { *x = BuilderPendingPayment{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[12] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1231,7 +1283,7 @@ func (x *BuilderPendingPayment) String() string { func (*BuilderPendingPayment) ProtoMessage() {} func (x *BuilderPendingPayment) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[12] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1244,7 +1296,7 @@ func (x *BuilderPendingPayment) ProtoReflect() protoreflect.Message { // Deprecated: Use BuilderPendingPayment.ProtoReflect.Descriptor instead. func (*BuilderPendingPayment) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{12} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{13} } func (x *BuilderPendingPayment) GetWeight() github_com_OffchainLabs_prysm_v7_consensus_types_primitives.Gwei { @@ -1272,7 +1324,7 @@ type BuilderPendingWithdrawal struct { func (x *BuilderPendingWithdrawal) Reset() { *x = BuilderPendingWithdrawal{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1284,7 +1336,7 @@ func (x *BuilderPendingWithdrawal) String() string { func (*BuilderPendingWithdrawal) ProtoMessage() {} func (x *BuilderPendingWithdrawal) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1297,7 +1349,7 @@ func (x *BuilderPendingWithdrawal) ProtoReflect() protoreflect.Message { // Deprecated: Use BuilderPendingWithdrawal.ProtoReflect.Descriptor instead. func (*BuilderPendingWithdrawal) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{13} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{14} } func (x *BuilderPendingWithdrawal) GetFeeRecipient() []byte { @@ -1334,7 +1386,7 @@ type DataColumnSidecarGloas struct { func (x *DataColumnSidecarGloas) Reset() { *x = DataColumnSidecarGloas{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1346,7 +1398,7 @@ func (x *DataColumnSidecarGloas) String() string { func (*DataColumnSidecarGloas) ProtoMessage() {} func (x *DataColumnSidecarGloas) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1359,7 +1411,7 @@ func (x *DataColumnSidecarGloas) ProtoReflect() protoreflect.Message { // Deprecated: Use DataColumnSidecarGloas.ProtoReflect.Descriptor instead. func (*DataColumnSidecarGloas) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{14} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{15} } func (x *DataColumnSidecarGloas) GetIndex() uint64 { @@ -1411,7 +1463,7 @@ type ExecutionPayloadEnvelope struct { func (x *ExecutionPayloadEnvelope) Reset() { *x = ExecutionPayloadEnvelope{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1423,7 +1475,7 @@ func (x *ExecutionPayloadEnvelope) String() string { func (*ExecutionPayloadEnvelope) ProtoMessage() {} func (x *ExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1436,7 +1488,7 @@ func (x *ExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadEnvelope.ProtoReflect.Descriptor instead. func (*ExecutionPayloadEnvelope) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{15} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{16} } func (x *ExecutionPayloadEnvelope) GetPayload() *v1.ExecutionPayloadDeneb { @@ -1491,7 +1543,7 @@ type SignedExecutionPayloadEnvelope struct { func (x *SignedExecutionPayloadEnvelope) Reset() { *x = SignedExecutionPayloadEnvelope{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1503,7 +1555,7 @@ func (x *SignedExecutionPayloadEnvelope) String() string { func (*SignedExecutionPayloadEnvelope) ProtoMessage() {} func (x *SignedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1516,7 +1568,7 @@ func (x *SignedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { // Deprecated: Use SignedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead. func (*SignedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{16} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{17} } func (x *SignedExecutionPayloadEnvelope) GetMessage() *ExecutionPayloadEnvelope { @@ -1548,7 +1600,7 @@ type BlindedExecutionPayloadEnvelope struct { func (x *BlindedExecutionPayloadEnvelope) Reset() { *x = BlindedExecutionPayloadEnvelope{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1560,7 +1612,7 @@ func (x *BlindedExecutionPayloadEnvelope) String() string { func (*BlindedExecutionPayloadEnvelope) ProtoMessage() {} func (x *BlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1573,7 +1625,7 @@ func (x *BlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { // Deprecated: Use BlindedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead. func (*BlindedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{17} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{18} } func (x *BlindedExecutionPayloadEnvelope) GetBlockHash() []byte { @@ -1635,7 +1687,7 @@ type SignedBlindedExecutionPayloadEnvelope struct { func (x *SignedBlindedExecutionPayloadEnvelope) Reset() { *x = SignedBlindedExecutionPayloadEnvelope{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1647,7 +1699,7 @@ func (x *SignedBlindedExecutionPayloadEnvelope) String() string { func (*SignedBlindedExecutionPayloadEnvelope) ProtoMessage() {} func (x *SignedBlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1660,7 +1712,7 @@ func (x *SignedBlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Mess // Deprecated: Use SignedBlindedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead. func (*SignedBlindedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{18} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{19} } func (x *SignedBlindedExecutionPayloadEnvelope) GetMessage() *BlindedExecutionPayloadEnvelope { @@ -1691,7 +1743,7 @@ type Builder struct { func (x *Builder) Reset() { *x = Builder{} - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1703,7 +1755,7 @@ func (x *Builder) String() string { func (*Builder) ProtoMessage() {} func (x *Builder) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19] + mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1716,7 +1768,7 @@ func (x *Builder) ProtoReflect() protoreflect.Message { // Deprecated: Use Builder.ProtoReflect.Descriptor instead. func (*Builder) Descriptor() ([]byte, []int) { - return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{19} + return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{20} } func (x *Builder) GetPubkey() []byte { @@ -2020,7 +2072,7 @@ var file_proto_prysm_v1alpha1_gloas_proto_rawDesc = []byte{ 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x6c, 0x6f, 0x61, 0x73, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, - 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xa0, + 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xe5, 0x1f, 0x0a, 0x10, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x61, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x67, 0x65, 0x6e, 0x65, @@ -2271,61 +2323,112 @@ var file_proto_prysm_v1alpha1_gloas_proto_rawDesc = []byte{ 0x76, 0x31, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x42, 0x06, 0x92, 0xb5, 0x18, 0x02, 0x31, 0x36, 0x52, 0x1a, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, - 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x15, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a, 0x06, 0x77, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, - 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, + 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x70, 0x74, 0x63, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, + 0xb8, 0x6d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, + 0x54, 0x43, 0x73, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x70, 0x74, 0x63, + 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x22, 0x8b, 0x01, 0x0a, 0x04, 0x50, 0x54, 0x43, 0x73, 0x12, + 0x82, 0x01, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, + 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x42, 0x55, 0x82, 0xb5, 0x18, + 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, - 0x69, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x4f, 0x0a, 0x0a, 0x77, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, - 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x0a, - 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x22, 0x98, 0x02, 0x0a, 0x18, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x72, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, - 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x0c, 0x66, 0x65, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, - 0x69, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, + 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x8a, 0xb5, 0x18, 0x03, 0x35, + 0x31, 0x32, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x65, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x15, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x5c, + 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, + 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, + 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, + 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, + 0x47, 0x77, 0x65, 0x69, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x4f, 0x0a, 0x0a, + 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, + 0x6c, 0x52, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x22, 0x98, 0x02, + 0x0a, 0x18, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x0d, 0x66, 0x65, + 0x65, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x0c, 0x66, 0x65, 0x65, 0x52, 0x65, + 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, + 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, + 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, + 0x18, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, + 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x99, 0x02, 0x0a, 0x16, 0x44, 0x61, 0x74, + 0x61, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x53, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, 0x47, 0x6c, + 0x6f, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x06, 0x63, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x12, 0x8a, 0xb5, 0x18, 0x06, 0x3f, + 0x2c, 0x32, 0x30, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x06, 0x63, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x2f, 0x0a, 0x0a, 0x6b, 0x7a, 0x67, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x10, 0x8a, 0xb5, 0x18, 0x04, 0x3f, + 0x2c, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x09, 0x6b, 0x7a, 0x67, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, - 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18, 0x48, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, - 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, - 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x99, 0x02, 0x0a, 0x16, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x53, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, 0x47, 0x6c, 0x6f, 0x61, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x12, 0x8a, 0xb5, 0x18, 0x06, 0x3f, 0x2c, 0x32, 0x30, - 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x12, 0x2f, 0x0a, 0x0a, 0x6b, 0x7a, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x10, 0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c, 0x34, 0x38, - 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x09, 0x6b, 0x7a, 0x67, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x73, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, + 0x12, 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, + 0x02, 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x6f, 0x6f, 0x74, 0x22, 0xdd, 0x03, 0x0a, 0x18, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x12, 0x43, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, + 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x6e, 0x65, 0x62, 0x52, 0x07, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, + 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x71, 0x0a, 0x0d, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, + 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, + 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, + 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x6f, 0x6f, 0x74, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x32, 0x0a, - 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, - 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, - 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, - 0x74, 0x22, 0xdd, 0x03, 0x0a, 0x18, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x43, - 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x6e, 0x65, 0x62, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x25, 0x0a, + 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x1e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, + 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, + 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xfa, 0x03, 0x0a, 0x1f, 0x42, 0x6c, 0x69, + 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0a, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x61, 0x73, 0x68, 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, @@ -2349,90 +2452,52 @@ var file_proto_prysm_v1alpha1_gloas_proto_rawDesc = []byte{ 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, - 0x74, 0x22, 0x91, 0x01, 0x0a, 0x1e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, - 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xfa, 0x03, 0x0a, 0x1f, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, - 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, - 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, - 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, - 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, - 0xb5, 0x18, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, - 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, - 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, - 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, - 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x58, 0x0a, - 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, - 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, - 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, - 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, - 0x02, 0x33, 0x32, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x32, - 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, - 0x32, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, - 0x73, 0x68, 0x22, 0x9f, 0x01, 0x0a, 0x25, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x6c, 0x69, - 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x50, 0x0a, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, - 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, - 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x22, 0xc1, 0x03, 0x0a, 0x07, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, - 0x12, 0x1e, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x34, 0x38, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, - 0x12, 0x1f, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x42, 0x05, 0x8a, 0xb5, 0x18, 0x01, 0x31, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, - 0x18, 0x02, 0x32, 0x30, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5e, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, - 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, - 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52, 0x07, 0x62, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x6a, 0x0a, 0x0d, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, - 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, - 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, - 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x45, - 0x70, 0x6f, 0x63, 0x68, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x45, 0x70, 0x6f, - 0x63, 0x68, 0x12, 0x74, 0x0a, 0x12, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x42, 0x45, - 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, - 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, - 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, - 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x11, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, - 0x62, 0x6c, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, - 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x3b, 0x65, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x12, 0x32, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, + 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x9f, 0x01, 0x0a, 0x25, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, + 0x50, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x36, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xc1, 0x03, 0x0a, 0x07, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x34, 0x38, 0x52, 0x06, 0x70, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x42, 0x05, 0x8a, 0xb5, 0x18, 0x01, 0x31, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, + 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5e, 0x0a, 0x07, 0x62, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, + 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, + 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x6a, 0x0a, 0x0d, 0x64, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, + 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, + 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x73, 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x74, 0x0a, 0x12, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, + 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, + 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x73, 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x11, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x42, 0x3b, 0x5a, 0x39, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2447,7 +2512,7 @@ func file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP() []byte { return file_proto_prysm_v1alpha1_gloas_proto_rawDescData } -var file_proto_prysm_v1alpha1_gloas_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_proto_prysm_v1alpha1_gloas_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_proto_prysm_v1alpha1_gloas_proto_goTypes = []any{ (*ExecutionPayloadBid)(nil), // 0: ethereum.eth.v1alpha1.ExecutionPayloadBid (*SignedExecutionPayloadBid)(nil), // 1: ethereum.eth.v1alpha1.SignedExecutionPayloadBid @@ -2461,34 +2526,35 @@ var file_proto_prysm_v1alpha1_gloas_proto_goTypes = []any{ (*BeaconBlockBodyGloas)(nil), // 9: ethereum.eth.v1alpha1.BeaconBlockBodyGloas (*SignedBeaconBlockGloas)(nil), // 10: ethereum.eth.v1alpha1.SignedBeaconBlockGloas (*BeaconStateGloas)(nil), // 11: ethereum.eth.v1alpha1.BeaconStateGloas - (*BuilderPendingPayment)(nil), // 12: ethereum.eth.v1alpha1.BuilderPendingPayment - (*BuilderPendingWithdrawal)(nil), // 13: ethereum.eth.v1alpha1.BuilderPendingWithdrawal - (*DataColumnSidecarGloas)(nil), // 14: ethereum.eth.v1alpha1.DataColumnSidecarGloas - (*ExecutionPayloadEnvelope)(nil), // 15: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope - (*SignedExecutionPayloadEnvelope)(nil), // 16: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope - (*BlindedExecutionPayloadEnvelope)(nil), // 17: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope - (*SignedBlindedExecutionPayloadEnvelope)(nil), // 18: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope - (*Builder)(nil), // 19: ethereum.eth.v1alpha1.Builder - (*Eth1Data)(nil), // 20: ethereum.eth.v1alpha1.Eth1Data - (*ProposerSlashing)(nil), // 21: ethereum.eth.v1alpha1.ProposerSlashing - (*AttesterSlashingElectra)(nil), // 22: ethereum.eth.v1alpha1.AttesterSlashingElectra - (*AttestationElectra)(nil), // 23: ethereum.eth.v1alpha1.AttestationElectra - (*Deposit)(nil), // 24: ethereum.eth.v1alpha1.Deposit - (*SignedVoluntaryExit)(nil), // 25: ethereum.eth.v1alpha1.SignedVoluntaryExit - (*SyncAggregate)(nil), // 26: ethereum.eth.v1alpha1.SyncAggregate - (*SignedBLSToExecutionChange)(nil), // 27: ethereum.eth.v1alpha1.SignedBLSToExecutionChange - (*Fork)(nil), // 28: ethereum.eth.v1alpha1.Fork - (*BeaconBlockHeader)(nil), // 29: ethereum.eth.v1alpha1.BeaconBlockHeader - (*Validator)(nil), // 30: ethereum.eth.v1alpha1.Validator - (*Checkpoint)(nil), // 31: ethereum.eth.v1alpha1.Checkpoint - (*SyncCommittee)(nil), // 32: ethereum.eth.v1alpha1.SyncCommittee - (*HistoricalSummary)(nil), // 33: ethereum.eth.v1alpha1.HistoricalSummary - (*PendingDeposit)(nil), // 34: ethereum.eth.v1alpha1.PendingDeposit - (*PendingPartialWithdrawal)(nil), // 35: ethereum.eth.v1alpha1.PendingPartialWithdrawal - (*PendingConsolidation)(nil), // 36: ethereum.eth.v1alpha1.PendingConsolidation - (*v1.Withdrawal)(nil), // 37: ethereum.engine.v1.Withdrawal - (*v1.ExecutionPayloadDeneb)(nil), // 38: ethereum.engine.v1.ExecutionPayloadDeneb - (*v1.ExecutionRequests)(nil), // 39: ethereum.engine.v1.ExecutionRequests + (*PTCs)(nil), // 12: ethereum.eth.v1alpha1.PTCs + (*BuilderPendingPayment)(nil), // 13: ethereum.eth.v1alpha1.BuilderPendingPayment + (*BuilderPendingWithdrawal)(nil), // 14: ethereum.eth.v1alpha1.BuilderPendingWithdrawal + (*DataColumnSidecarGloas)(nil), // 15: ethereum.eth.v1alpha1.DataColumnSidecarGloas + (*ExecutionPayloadEnvelope)(nil), // 16: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope + (*SignedExecutionPayloadEnvelope)(nil), // 17: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope + (*BlindedExecutionPayloadEnvelope)(nil), // 18: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope + (*SignedBlindedExecutionPayloadEnvelope)(nil), // 19: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope + (*Builder)(nil), // 20: ethereum.eth.v1alpha1.Builder + (*Eth1Data)(nil), // 21: ethereum.eth.v1alpha1.Eth1Data + (*ProposerSlashing)(nil), // 22: ethereum.eth.v1alpha1.ProposerSlashing + (*AttesterSlashingElectra)(nil), // 23: ethereum.eth.v1alpha1.AttesterSlashingElectra + (*AttestationElectra)(nil), // 24: ethereum.eth.v1alpha1.AttestationElectra + (*Deposit)(nil), // 25: ethereum.eth.v1alpha1.Deposit + (*SignedVoluntaryExit)(nil), // 26: ethereum.eth.v1alpha1.SignedVoluntaryExit + (*SyncAggregate)(nil), // 27: ethereum.eth.v1alpha1.SyncAggregate + (*SignedBLSToExecutionChange)(nil), // 28: ethereum.eth.v1alpha1.SignedBLSToExecutionChange + (*Fork)(nil), // 29: ethereum.eth.v1alpha1.Fork + (*BeaconBlockHeader)(nil), // 30: ethereum.eth.v1alpha1.BeaconBlockHeader + (*Validator)(nil), // 31: ethereum.eth.v1alpha1.Validator + (*Checkpoint)(nil), // 32: ethereum.eth.v1alpha1.Checkpoint + (*SyncCommittee)(nil), // 33: ethereum.eth.v1alpha1.SyncCommittee + (*HistoricalSummary)(nil), // 34: ethereum.eth.v1alpha1.HistoricalSummary + (*PendingDeposit)(nil), // 35: ethereum.eth.v1alpha1.PendingDeposit + (*PendingPartialWithdrawal)(nil), // 36: ethereum.eth.v1alpha1.PendingPartialWithdrawal + (*PendingConsolidation)(nil), // 37: ethereum.eth.v1alpha1.PendingConsolidation + (*v1.Withdrawal)(nil), // 38: ethereum.engine.v1.Withdrawal + (*v1.ExecutionPayloadDeneb)(nil), // 39: ethereum.engine.v1.ExecutionPayloadDeneb + (*v1.ExecutionRequests)(nil), // 40: ethereum.engine.v1.ExecutionRequests } var file_proto_prysm_v1alpha1_gloas_proto_depIdxs = []int32{ 0, // 0: ethereum.eth.v1alpha1.SignedExecutionPayloadBid.message:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadBid @@ -2497,47 +2563,48 @@ var file_proto_prysm_v1alpha1_gloas_proto_depIdxs = []int32{ 5, // 3: ethereum.eth.v1alpha1.PayloadAttestation.data:type_name -> ethereum.eth.v1alpha1.PayloadAttestationData 5, // 4: ethereum.eth.v1alpha1.PayloadAttestationMessage.data:type_name -> ethereum.eth.v1alpha1.PayloadAttestationData 9, // 5: ethereum.eth.v1alpha1.BeaconBlockGloas.body:type_name -> ethereum.eth.v1alpha1.BeaconBlockBodyGloas - 20, // 6: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data - 21, // 7: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing - 22, // 8: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashingElectra - 23, // 9: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attestations:type_name -> ethereum.eth.v1alpha1.AttestationElectra - 24, // 10: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.deposits:type_name -> ethereum.eth.v1alpha1.Deposit - 25, // 11: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit - 26, // 12: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate - 27, // 13: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange + 21, // 6: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data + 22, // 7: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing + 23, // 8: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashingElectra + 24, // 9: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attestations:type_name -> ethereum.eth.v1alpha1.AttestationElectra + 25, // 10: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.deposits:type_name -> ethereum.eth.v1alpha1.Deposit + 26, // 11: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit + 27, // 12: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate + 28, // 13: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange 1, // 14: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.signed_execution_payload_bid:type_name -> ethereum.eth.v1alpha1.SignedExecutionPayloadBid 6, // 15: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.payload_attestations:type_name -> ethereum.eth.v1alpha1.PayloadAttestation 8, // 16: ethereum.eth.v1alpha1.SignedBeaconBlockGloas.block:type_name -> ethereum.eth.v1alpha1.BeaconBlockGloas - 28, // 17: ethereum.eth.v1alpha1.BeaconStateGloas.fork:type_name -> ethereum.eth.v1alpha1.Fork - 29, // 18: ethereum.eth.v1alpha1.BeaconStateGloas.latest_block_header:type_name -> ethereum.eth.v1alpha1.BeaconBlockHeader - 20, // 19: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data - 20, // 20: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data_votes:type_name -> ethereum.eth.v1alpha1.Eth1Data - 30, // 21: ethereum.eth.v1alpha1.BeaconStateGloas.validators:type_name -> ethereum.eth.v1alpha1.Validator - 31, // 22: ethereum.eth.v1alpha1.BeaconStateGloas.previous_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint - 31, // 23: ethereum.eth.v1alpha1.BeaconStateGloas.current_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint - 31, // 24: ethereum.eth.v1alpha1.BeaconStateGloas.finalized_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint - 32, // 25: ethereum.eth.v1alpha1.BeaconStateGloas.current_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee - 32, // 26: ethereum.eth.v1alpha1.BeaconStateGloas.next_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee + 29, // 17: ethereum.eth.v1alpha1.BeaconStateGloas.fork:type_name -> ethereum.eth.v1alpha1.Fork + 30, // 18: ethereum.eth.v1alpha1.BeaconStateGloas.latest_block_header:type_name -> ethereum.eth.v1alpha1.BeaconBlockHeader + 21, // 19: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data + 21, // 20: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data_votes:type_name -> ethereum.eth.v1alpha1.Eth1Data + 31, // 21: ethereum.eth.v1alpha1.BeaconStateGloas.validators:type_name -> ethereum.eth.v1alpha1.Validator + 32, // 22: ethereum.eth.v1alpha1.BeaconStateGloas.previous_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint + 32, // 23: ethereum.eth.v1alpha1.BeaconStateGloas.current_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint + 32, // 24: ethereum.eth.v1alpha1.BeaconStateGloas.finalized_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint + 33, // 25: ethereum.eth.v1alpha1.BeaconStateGloas.current_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee + 33, // 26: ethereum.eth.v1alpha1.BeaconStateGloas.next_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee 0, // 27: ethereum.eth.v1alpha1.BeaconStateGloas.latest_execution_payload_bid:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadBid - 33, // 28: ethereum.eth.v1alpha1.BeaconStateGloas.historical_summaries:type_name -> ethereum.eth.v1alpha1.HistoricalSummary - 34, // 29: ethereum.eth.v1alpha1.BeaconStateGloas.pending_deposits:type_name -> ethereum.eth.v1alpha1.PendingDeposit - 35, // 30: ethereum.eth.v1alpha1.BeaconStateGloas.pending_partial_withdrawals:type_name -> ethereum.eth.v1alpha1.PendingPartialWithdrawal - 36, // 31: ethereum.eth.v1alpha1.BeaconStateGloas.pending_consolidations:type_name -> ethereum.eth.v1alpha1.PendingConsolidation - 19, // 32: ethereum.eth.v1alpha1.BeaconStateGloas.builders:type_name -> ethereum.eth.v1alpha1.Builder - 12, // 33: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_payments:type_name -> ethereum.eth.v1alpha1.BuilderPendingPayment - 13, // 34: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_withdrawals:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal - 37, // 35: ethereum.eth.v1alpha1.BeaconStateGloas.payload_expected_withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 13, // 36: ethereum.eth.v1alpha1.BuilderPendingPayment.withdrawal:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal - 38, // 37: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.payload:type_name -> ethereum.engine.v1.ExecutionPayloadDeneb - 39, // 38: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests - 15, // 39: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadEnvelope - 39, // 40: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests - 17, // 41: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope - 42, // [42:42] is the sub-list for method output_type - 42, // [42:42] is the sub-list for method input_type - 42, // [42:42] is the sub-list for extension type_name - 42, // [42:42] is the sub-list for extension extendee - 0, // [0:42] is the sub-list for field type_name + 34, // 28: ethereum.eth.v1alpha1.BeaconStateGloas.historical_summaries:type_name -> ethereum.eth.v1alpha1.HistoricalSummary + 35, // 29: ethereum.eth.v1alpha1.BeaconStateGloas.pending_deposits:type_name -> ethereum.eth.v1alpha1.PendingDeposit + 36, // 30: ethereum.eth.v1alpha1.BeaconStateGloas.pending_partial_withdrawals:type_name -> ethereum.eth.v1alpha1.PendingPartialWithdrawal + 37, // 31: ethereum.eth.v1alpha1.BeaconStateGloas.pending_consolidations:type_name -> ethereum.eth.v1alpha1.PendingConsolidation + 20, // 32: ethereum.eth.v1alpha1.BeaconStateGloas.builders:type_name -> ethereum.eth.v1alpha1.Builder + 13, // 33: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_payments:type_name -> ethereum.eth.v1alpha1.BuilderPendingPayment + 14, // 34: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_withdrawals:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal + 38, // 35: ethereum.eth.v1alpha1.BeaconStateGloas.payload_expected_withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 12, // 36: ethereum.eth.v1alpha1.BeaconStateGloas.ptc_window:type_name -> ethereum.eth.v1alpha1.PTCs + 14, // 37: ethereum.eth.v1alpha1.BuilderPendingPayment.withdrawal:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal + 39, // 38: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.payload:type_name -> ethereum.engine.v1.ExecutionPayloadDeneb + 40, // 39: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests + 16, // 40: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadEnvelope + 40, // 41: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests + 18, // 42: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope + 43, // [43:43] is the sub-list for method output_type + 43, // [43:43] is the sub-list for method input_type + 43, // [43:43] is the sub-list for extension type_name + 43, // [43:43] is the sub-list for extension extendee + 0, // [0:43] is the sub-list for field type_name } func init() { file_proto_prysm_v1alpha1_gloas_proto_init() } @@ -2555,7 +2622,7 @@ func file_proto_prysm_v1alpha1_gloas_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_prysm_v1alpha1_gloas_proto_rawDesc, NumEnums: 0, - NumMessages: 20, + NumMessages: 21, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/prysm/v1alpha1/gloas.proto b/proto/prysm/v1alpha1/gloas.proto index bba14d5b14d1..f287d04bc795 100644 --- a/proto/prysm/v1alpha1/gloas.proto +++ b/proto/prysm/v1alpha1/gloas.proto @@ -250,6 +250,8 @@ message SignedBeaconBlockGloas { // latest_block_hash: Hash32 // payload_expected_withdrawals: List[Withdrawal, // MAX_WITHDRAWALS_PER_PAYLOAD] +// ptc_window: +// Vector[PTCs, (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] message BeaconStateGloas { // Versioning [1001-2000] uint64 genesis_time = 1001; @@ -375,6 +377,21 @@ message BeaconStateGloas { bytes latest_block_hash = 14006 [ (ethereum.eth.ext.ssz_size) = "32" ]; repeated ethereum.engine.v1.Withdrawal payload_expected_withdrawals = 14007 [ (ethereum.eth.ext.ssz_max) = "withdrawal.size" ]; + repeated PTCs ptc_window = 14008 + [ (ethereum.eth.ext.ssz_size) = "ptc_window.size" ]; +} + +// PTCs represents the payload timeliness committee for a single slot. +// +// Spec: +// Vector[ValidatorIndex, PTC_SIZE] +message PTCs { + repeated uint64 validator_indices = 1 [ + (ethereum.eth.ext.ssz_size) = "ptc_committee_indices.size", + (ethereum.eth.ext.cast_type) = + "github.com/OffchainLabs/prysm/v7/consensus-types/" + "primitives.ValidatorIndex" + ]; } // BuilderPendingPayment represents a pending payment to a builder. diff --git a/proto/prysm/v1alpha1/gloas.ssz.go b/proto/prysm/v1alpha1/gloas.ssz.go index 3147a1e07221..d6141840c81f 100644 --- a/proto/prysm/v1alpha1/gloas.ssz.go +++ b/proto/prysm/v1alpha1/gloas.ssz.go @@ -1701,7 +1701,7 @@ func (b *BeaconStateGloas) MarshalSSZ() ([]byte, error) { // MarshalSSZTo ssz marshals the BeaconStateGloas object to a target array func (b *BeaconStateGloas) MarshalSSZTo(buf []byte) (dst []byte, err error) { dst = buf - offset := int(2741117) + offset := int(3134333) // Field (0) 'GenesisTime' dst = ssz.MarshalUint(dst, b.GenesisTime) @@ -1962,6 +1962,17 @@ func (b *BeaconStateGloas) MarshalSSZTo(buf []byte) (dst []byte, err error) { dst = ssz.WriteOffset(dst, offset) offset += len(b.PayloadExpectedWithdrawals) * 44 + // Field (45) 'PtcWindow' + if size := len(b.PtcWindow); size != 96 { + err = ssz.ErrVectorLengthFn("--.PtcWindow", size, 96) + return + } + for ii := 0; ii < 96; ii++ { + if dst, err = b.PtcWindow[ii].MarshalSSZTo(dst); err != nil { + return + } + } + // Field (7) 'HistoricalRoots' if size := len(b.HistoricalRoots); size > 16777216 { err = ssz.ErrListTooBigFn("--.HistoricalRoots", size, 16777216) @@ -2118,7 +2129,7 @@ func (b *BeaconStateGloas) MarshalSSZTo(buf []byte) (dst []byte, err error) { func (b *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { var err error size := uint64(len(buf)) - if size < 2741117 { + if size < 3134333 { return ssz.ErrSize } @@ -2176,7 +2187,7 @@ func (b *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return ssz.ErrOffset } - if o7 != 2741117 { + if o7 != 3134333 { return ssz.ErrInvalidVariableOffset } @@ -2378,6 +2389,17 @@ func (b *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { return ssz.ErrOffset } + // Field (45) 'PtcWindow' + b.PtcWindow = make([]*PTCs, 96) + for ii := 0; ii < 96; ii++ { + if b.PtcWindow[ii] == nil { + b.PtcWindow[ii] = new(PTCs) + } + if err = b.PtcWindow[ii].UnmarshalSSZ(buf[2741117:3134333][ii*4096 : (ii+1)*4096]); err != nil { + return err + } + } + // Field (7) 'HistoricalRoots' { buf = tail[o7:o9] @@ -2621,7 +2643,7 @@ func (b *BeaconStateGloas) UnmarshalSSZ(buf []byte) error { // SizeSSZ returns the ssz encoded size in bytes for the BeaconStateGloas object func (b *BeaconStateGloas) SizeSSZ() (size int) { - size = 2741117 + size = 3134333 // Field (7) 'HistoricalRoots' size += len(b.HistoricalRoots) * 32 @@ -3099,6 +3121,87 @@ func (b *BeaconStateGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.MerkleizeWithMixin(subIndx, num, 16) } + // Field (45) 'PtcWindow' + { + subIndx := hh.Index() + for _, elem := range b.PtcWindow { + if err = elem.HashTreeRootWith(hh); err != nil { + return + } + } + hh.Merkleize(subIndx) + } + + hh.Merkleize(indx) + return +} + +// MarshalSSZ ssz marshals the PTCs object +func (p *PTCs) MarshalSSZ() ([]byte, error) { + return ssz.MarshalSSZ(p) +} + +// MarshalSSZTo ssz marshals the PTCs object to a target array +func (p *PTCs) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + + // Field (0) 'ValidatorIndices' + if size := len(p.ValidatorIndices); size != 512 { + err = ssz.ErrVectorLengthFn("--.ValidatorIndices", size, 512) + return + } + for ii := 0; ii < 512; ii++ { + dst = ssz.MarshalUint(dst, p.ValidatorIndices[ii]) + } + + return +} + +// UnmarshalSSZ ssz unmarshals the PTCs object +func (p *PTCs) UnmarshalSSZ(buf []byte) error { + var err error + size := uint64(len(buf)) + if size != 4096 { + return ssz.ErrSize + } + + // Field (0) 'ValidatorIndices' + p.ValidatorIndices = ssz.ExtendUint(p.ValidatorIndices, 512) + for ii := 0; ii < 512; ii++ { + p.ValidatorIndices[ii] = ssz.UnmarshallUint[github_com_OffchainLabs_prysm_v7_consensus_types_primitives.ValidatorIndex](buf[0:4096][ii*8 : (ii+1)*8]) + } + + return err +} + +// SizeSSZ returns the ssz encoded size in bytes for the PTCs object +func (p *PTCs) SizeSSZ() (size int) { + size = 4096 + return +} + +// HashTreeRoot ssz hashes the PTCs object +func (p *PTCs) HashTreeRoot() ([32]byte, error) { + return ssz.HashWithDefaultHasher(p) +} + +// HashTreeRootWith ssz hashes the PTCs object with a hasher +func (p *PTCs) HashTreeRootWith(hh *ssz.Hasher) (err error) { + indx := hh.Index() + + // Field (0) 'ValidatorIndices' + { + if size := len(p.ValidatorIndices); size != 512 { + err = ssz.ErrVectorLengthFn("--.ValidatorIndices", size, 512) + return + } + subIndx := hh.Index() + for _, i := range p.ValidatorIndices { + ssz.AppendUint(hh, i) + } + hh.Merkleize(subIndx) + } + hh.Merkleize(indx) return } diff --git a/proto/ssz_proto_library.bzl b/proto/ssz_proto_library.bzl index f3a424696cd0..2501e8611a6b 100644 --- a/proto/ssz_proto_library.bzl +++ b/proto/ssz_proto_library.bzl @@ -43,6 +43,8 @@ mainnet = { "cells_per_blob.size": "128", "kzg_commitments_inclusion_proof_depth.size": "4", "proposer_lookahead_size": "64", # (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH + "ptc_window.size": "96", # (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH + "ptc_committee_indices.size": "512", # PTC_SIZE "ptc.size": "64", # Gloas: Payload Timeliness Committee aggregation bits (PTC_SIZE = 512) "ptc.type": "github.com/OffchainLabs/go-bitfield.Bitvector512", "payload_attestation.size": "4", # Gloas: MAX_PAYLOAD_ATTESTATIONS defined in block body @@ -88,6 +90,8 @@ minimal = { "cells_per_blob.size": "128", "kzg_commitments_inclusion_proof_depth.size": "4", "proposer_lookahead_size": "16", # (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH + "ptc_window.size": "24", # (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH + "ptc_committee_indices.size": "2", # PTC_SIZE "ptc.size": "1", # Gloas: Payload Timeliness Committee aggregation bits "ptc.type": "github.com/OffchainLabs/go-bitfield.Bitvector2", "payload_attestation.size": "4", # Gloas: MAX_PAYLOAD_ATTESTATIONS defined in block body diff --git a/specrefs/configs.yml b/specrefs/configs.yml index 3f35ef0d3b57..88110c9b84d6 100644 --- a/specrefs/configs.yml +++ b/specrefs/configs.yml @@ -82,16 +82,6 @@ ATTESTATION_SUBNET_EXTRA_BITS = 0 -- name: ATTESTATION_SUBNET_PREFIX_BITS#phase0 - 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#fulu sources: - file: config/params/config.go @@ -352,6 +342,20 @@ GLOAS_FORK_VERSION: Version = '0x07000000' +- name: HEZE_FORK_EPOCH#heze + sources: [] + spec: | + + HEZE_FORK_EPOCH: Epoch = 18446744073709551615 + + +- name: HEZE_FORK_VERSION#heze + sources: [] + spec: | + + HEZE_FORK_VERSION: Version = '0x08000000' + + - name: INACTIVITY_SCORE_BIAS#altair sources: - file: config/params/config.go @@ -372,6 +376,13 @@ INACTIVITY_SCORE_RECOVERY_RATE: uint64 = 16 +- name: INCLUSION_LIST_SUBMISSION_DUE_BPS#heze + sources: [] + spec: | + + INCLUSION_LIST_SUBMISSION_DUE_BPS: uint64 = 6667 + + - name: MAXIMUM_GOSSIP_CLOCK_DISPARITY#phase0 sources: - file: config/params/config.go @@ -402,6 +413,13 @@ MAX_BLOBS_PER_BLOCK_ELECTRA: uint64 = 9 +- name: MAX_BYTES_PER_INCLUSION_LIST#heze + sources: [] + spec: | + + MAX_BYTES_PER_INCLUSION_LIST = 8192 + + - name: MAX_PAYLOAD_SIZE#phase0 sources: - file: config/params/config.go @@ -432,26 +450,6 @@ MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: Gwei = 256000000000 -- name: MAX_REQUEST_BLOB_SIDECARS#deneb - sources: - - file: config/params/config.go - search: MaxRequestBlobSidecars\s+uint64 - regex: true - spec: | - - MAX_REQUEST_BLOB_SIDECARS = 768 - - -- name: MAX_REQUEST_BLOB_SIDECARS_ELECTRA#electra - sources: - - file: config/params/config.go - search: MaxRequestBlobSidecarsElectra\s+uint64 - regex: true - spec: | - - MAX_REQUEST_BLOB_SIDECARS_ELECTRA = 1152 - - - name: MAX_REQUEST_BLOCKS#phase0 sources: - file: config/params/config.go @@ -472,14 +470,11 @@ MAX_REQUEST_BLOCKS_DENEB = 128 -- name: MAX_REQUEST_DATA_COLUMN_SIDECARS#fulu - sources: - - file: config/params/config.go - search: MaxRequestDataColumnSidecars\s+uint64 - regex: true +- name: MAX_REQUEST_INCLUSION_LIST#heze + sources: [] spec: | - - MAX_REQUEST_DATA_COLUMN_SIDECARS = 16384 + + MAX_REQUEST_INCLUSION_LIST = 16 - name: MAX_REQUEST_PAYLOADS#gloas @@ -531,16 +526,6 @@ MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS = 4096 -- name: MIN_EPOCHS_FOR_BLOCK_REQUESTS#phase0 - 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#fulu sources: - file: config/params/config.go @@ -621,6 +606,13 @@ PAYLOAD_ATTESTATION_DUE_BPS: uint64 = 7500 +- name: PROPOSER_INCLUSION_LIST_CUTOFF_BPS#heze + sources: [] + spec: | + + PROPOSER_INCLUSION_LIST_CUTOFF_BPS: uint64 = 9167 + + - name: PROPOSER_REORG_CUTOFF_BPS#phase0 sources: - file: config/params/config.go @@ -691,16 +683,6 @@ SECONDS_PER_ETH1_BLOCK: uint64 = 14 -- name: SECONDS_PER_SLOT#phase0 - sources: - - file: config/params/config.go - search: SecondsPerSlot\s+uint64 - regex: true - spec: | - - SECONDS_PER_SLOT: uint64 = 12 - - - name: SHARD_COMMITTEE_PERIOD#phase0 sources: - file: config/params/config.go @@ -787,3 +769,10 @@ VALIDATOR_CUSTODY_REQUIREMENT = 8 + +- name: VIEW_FREEZE_CUTOFF_BPS#heze + sources: [] + spec: | + + VIEW_FREEZE_CUTOFF_BPS: uint64 = 7500 + diff --git a/specrefs/constants.yml b/specrefs/constants.yml index 8dc0b78ea011..45373098ecc6 100644 --- a/specrefs/constants.yml +++ b/specrefs/constants.yml @@ -212,6 +212,13 @@ DOMAIN_DEPOSIT: DomainType = '0x03000000' +- name: DOMAIN_INCLUSION_LIST_COMMITTEE#heze + sources: [] + spec: | + + DOMAIN_INCLUSION_LIST_COMMITTEE: DomainType = '0x0E000000' + + - name: DOMAIN_PROPOSER_PREFERENCES#gloas sources: - file: config/params/config.go @@ -445,22 +452,22 @@ - name: PAYLOAD_STATUS_EMPTY#gloas sources: [] spec: | - - PAYLOAD_STATUS_EMPTY: PayloadStatus = 1 + + PAYLOAD_STATUS_EMPTY: PayloadStatus = 0 - name: PAYLOAD_STATUS_FULL#gloas sources: [] spec: | - - PAYLOAD_STATUS_FULL: PayloadStatus = 2 + + PAYLOAD_STATUS_FULL: PayloadStatus = 1 - name: PAYLOAD_STATUS_PENDING#gloas sources: [] spec: | - - PAYLOAD_STATUS_PENDING: PayloadStatus = 0 + + PAYLOAD_STATUS_PENDING: PayloadStatus = 2 - name: PRIMITIVE_ROOT_OF_UNITY#deneb diff --git a/specrefs/containers.yml b/specrefs/containers.yml index 29d8da7a3244..c9c69d8d55a2 100644 --- a/specrefs/containers.yml +++ b/specrefs/containers.yml @@ -568,7 +568,7 @@ - name: BeaconState#gloas sources: [] spec: | - + class BeaconState(Container): genesis_time: uint64 genesis_validators_root: Root @@ -625,6 +625,62 @@ latest_block_hash: Hash32 # [New in Gloas:EIP7732] payload_expected_withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] + # [New in Gloas:EIP7732] + ptc_window: Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] + + +- name: BeaconState#heze + sources: [] + 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 Heze:EIP7805] + latest_execution_payload_bid: ExecutionPayloadBid + 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] + proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH] + builders: List[Builder, BUILDER_REGISTRY_LIMIT] + next_withdrawal_builder_index: BuilderIndex + execution_payload_availability: Bitvector[SLOTS_PER_HISTORICAL_ROOT] + builder_pending_payments: Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH] + builder_pending_withdrawals: List[BuilderPendingWithdrawal, BUILDER_PENDING_WITHDRAWALS_LIMIT] + latest_block_hash: Hash32 + payload_expected_withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] + ptc_window: Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] - name: BlobIdentifier#deneb @@ -932,6 +988,26 @@ blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] +- name: ExecutionPayloadBid#heze + sources: [] + spec: | + + class ExecutionPayloadBid(Container): + parent_block_hash: Hash32 + parent_block_root: Root + block_hash: Hash32 + prev_randao: Bytes32 + fee_recipient: ExecutionAddress + gas_limit: uint64 + builder_index: BuilderIndex + slot: Slot + value: Gwei + execution_payment: Gwei + blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + # [New in Heze:EIP7805] + inclusion_list_bits: Bitvector[INCLUSION_LIST_COMMITTEE_SIZE] + + - name: ExecutionPayloadEnvelope#gloas sources: [] spec: | @@ -1090,6 +1166,17 @@ state_summary_root: Root +- name: InclusionList#heze + sources: [] + spec: | + + class InclusionList(Container): + slot: Slot + validator_index: ValidatorIndex + inclusion_list_committee_root: Root + transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + + - name: IndexedAttestation#phase0 sources: - file: proto/prysm/v1alpha1/beacon_block.proto @@ -1280,6 +1367,53 @@ row_index: RowIndex +- name: PartialDataColumnHeader#fulu + sources: [] + spec: | + + class PartialDataColumnHeader(Container): + kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + signed_block_header: SignedBeaconBlockHeader + kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH] + + +- name: PartialDataColumnHeader#gloas + sources: [] + spec: | + + class PartialDataColumnHeader(Container): + kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + # [Modified in Gloas:EIP7732] + # Removed `signed_block_header` + # [Modified in Gloas:EIP7732] + # Removed `kzg_commitments_inclusion_proof` + # [New in Gloas:EIP7732] + slot: Slot + # [New in Gloas:EIP7732] + beacon_block_root: Root + + +- name: PartialDataColumnPartsMetadata#fulu + sources: [] + spec: | + + class PartialDataColumnPartsMetadata(Container): + available: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] + requests: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] + + +- name: PartialDataColumnSidecar#fulu + sources: [] + spec: | + + class PartialDataColumnSidecar(Container): + cells_present_bitmap: Bitlist[MAX_BLOB_COMMITMENTS_PER_BLOCK] + partial_column: List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK] + kzg_proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] + # Optional header, only sent on eager pushes + header: List[PartialDataColumnHeader, 1] + + - name: PayloadAttestation#gloas sources: [] spec: | @@ -1471,6 +1605,16 @@ signature: BLSSignature +- name: SignedExecutionPayloadBid#heze + sources: [] + spec: | + + class SignedExecutionPayloadBid(Container): + # [Modified in Heze:EIP7805] + message: ExecutionPayloadBid + signature: BLSSignature + + - name: SignedExecutionPayloadEnvelope#gloas sources: [] spec: | @@ -1480,6 +1624,15 @@ signature: BLSSignature +- name: SignedInclusionList#heze + sources: [] + spec: | + + class SignedInclusionList(Container): + message: InclusionList + signature: BLSSignature + + - name: SignedProposerPreferences#gloas sources: [] spec: | diff --git a/specrefs/dataclasses.yml b/specrefs/dataclasses.yml index 7d02bfc4ddcd..3ba15f0c765b 100644 --- a/specrefs/dataclasses.yml +++ b/specrefs/dataclasses.yml @@ -68,6 +68,14 @@ processed_sweep_withdrawals_count: uint64 +- name: GetInclusionListResponse#heze + sources: [] + spec: | + + class GetInclusionListResponse(object): + inclusion_list_transactions: Sequence[Transaction] + + - name: GetPayloadResponse#bellatrix sources: - file: consensus-types/blocks/get_payload.go @@ -140,6 +148,19 @@ execution_requests: Sequence[bytes] +- name: InclusionListStore#heze + sources: [] + spec: | + + class InclusionListStore(object): + inclusion_lists: DefaultDict[Tuple[Slot, Root], Set[InclusionList]] = field( + default_factory=lambda: defaultdict(set) + ) + equivocators: DefaultDict[Tuple[Slot, Root], Set[ValidatorIndex]] = field( + default_factory=lambda: defaultdict(set) + ) + + - name: LatestMessage#phase0 sources: [] spec: | @@ -288,6 +309,34 @@ parent_beacon_block_root: Root +- name: PayloadAttributes#heze + sources: [] + spec: | + + class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] + parent_beacon_block_root: Root + # [New in Heze:EIP7805] + inclusion_list_transactions: Sequence[Transaction] + + +- name: Seen#phase0 + sources: [] + spec: | + + class Seen(object): + proposer_slots: Set[Tuple[ValidatorIndex, Slot]] + aggregator_epochs: Set[Tuple[ValidatorIndex, Epoch]] + aggregate_data_roots: Dict[Root, Set[Tuple[boolean, ...]]] + voluntary_exit_indices: Set[ValidatorIndex] + proposer_slashing_indices: Set[ValidatorIndex] + attester_slashing_indices: Set[ValidatorIndex] + attestation_validator_epochs: Set[Tuple[ValidatorIndex, Epoch]] + + - name: Store#phase0 sources: [] spec: | @@ -312,7 +361,7 @@ - name: Store#gloas sources: [] spec: | - + class Store(object): time: uint64 genesis_time: uint64 @@ -331,7 +380,41 @@ latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict) unrealized_justifications: Dict[Root, Checkpoint] = field(default_factory=dict) # [New in Gloas:EIP7732] - execution_payload_states: Dict[Root, BeaconState] = field(default_factory=dict) + payload_states: Dict[Root, BeaconState] = field(default_factory=dict) + # [New in Gloas:EIP7732] + payload_timeliness_vote: Dict[Root, Vector[boolean, PTC_SIZE]] = field(default_factory=dict) # [New in Gloas:EIP7732] - ptc_vote: Dict[Root, Vector[boolean, PTC_SIZE]] = field(default_factory=dict) + payload_data_availability_vote: Dict[Root, Vector[boolean, PTC_SIZE]] = field( + default_factory=dict + ) + + +- name: Store#heze + 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, Vector[boolean, NUM_BLOCK_TIMELINESS_DEADLINES]] = 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) + payload_states: Dict[Root, BeaconState] = field(default_factory=dict) + payload_timeliness_vote: Dict[Root, Vector[boolean, PTC_SIZE]] = field(default_factory=dict) + payload_data_availability_vote: Dict[Root, Vector[boolean, PTC_SIZE]] = field( + default_factory=dict + ) + # [New in Heze:EIP7805] + payload_inclusion_list_satisfaction: Dict[Root, boolean] = field(default_factory=dict) diff --git a/specrefs/functions.yml b/specrefs/functions.yml index 94a3fa3c33f8..378b8d65dfbd 100644 --- a/specrefs/functions.yml +++ b/specrefs/functions.yml @@ -440,6 +440,17 @@ return Epoch(epoch + 1 + MAX_SEED_LOOKAHEAD) +- name: compute_attestation_subnet_prefix_bits#phase0 + sources: [] + spec: | + + def compute_attestation_subnet_prefix_bits() -> uint64: + """ + Return the number of NodeId bits to use when mapping to a subscribed subnet. + """ + return uint64(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS) + + - name: compute_balance_weighted_acceptance#gloas sources: [] spec: | @@ -871,6 +882,33 @@ return GENESIS_FORK_VERSION +- name: compute_fork_version#heze + sources: [] + spec: | + + def compute_fork_version(epoch: Epoch) -> Version: + """ + Return the fork version at the given ``epoch``. + """ + if epoch >= HEZE_FORK_EPOCH: + return HEZE_FORK_VERSION + if epoch >= GLOAS_FORK_EPOCH: + return GLOAS_FORK_VERSION + 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#fulu sources: [] spec: | @@ -897,6 +935,40 @@ return matrix +- name: compute_max_request_blob_sidecars#deneb + sources: [] + spec: | + + def compute_max_request_blob_sidecars() -> uint64: + """ + Return the maximum number of blob sidecars in a single request. + """ + return uint64(MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK) + + +- name: compute_max_request_blob_sidecars#electra + sources: [] + spec: | + + def compute_max_request_blob_sidecars() -> uint64: + """ + Return the maximum number of blob sidecars in a single request. + """ + # [Modified in Electra:EIP7691] + return uint64(MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA) + + +- name: compute_max_request_data_column_sidecars#fulu + sources: [] + spec: | + + def compute_max_request_data_column_sidecars() -> uint64: + """ + Return the maximum number of data column sidecars in a single request. + """ + return uint64(MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS) + + - name: compute_merkle_proof#altair sources: [] spec: | @@ -904,6 +976,17 @@ def compute_merkle_proof(object: SSZObject, index: GeneralizedIndex) -> Sequence[Bytes32]: ... +- name: compute_min_epochs_for_block_requests#phase0 + sources: [] + spec: | + + def compute_min_epochs_for_block_requests() -> uint64: + """ + Return the minimum epoch range over which a node must serve blocks. + """ + return uint64(MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2) + + - name: compute_new_state_root#phase0 sources: - file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go @@ -1050,6 +1133,27 @@ return (committee_weight * PROPOSER_SCORE_BOOST) // 100 +- name: compute_ptc#gloas + sources: [] + spec: | + + def compute_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: + """ + Get the payload timeliness committee for the given ``slot``. + """ + epoch = compute_epoch_at_slot(slot) + seed = hash(get_seed(state, epoch, DOMAIN_PTC_ATTESTER) + uint_to_bytes(slot)) + indices: List[ValidatorIndex] = [] + # Concatenate all committees for this slot in order + committees_per_slot = get_committee_count_per_slot(state, epoch) + for i in range(committees_per_slot): + committee = get_beacon_committee(state, slot, CommitteeIndex(i)) + indices.extend(committee) + return compute_balance_weighted_selection( + state, indices, seed, size=PTC_SIZE, shuffle_indices=False + ) + + - name: compute_pulled_up_tip#phase0 sources: [] spec: | @@ -1243,16 +1347,17 @@ - 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) + prefix_bits = int(compute_attestation_subnet_prefix_bits()) + node_id_prefix = node_id >> (NODE_ID_BITS - prefix_bits) node_offset = node_id % EPOCHS_PER_SUBNET_SUBSCRIPTION 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, + 1 << prefix_bits, permutation_seed, ) return SubnetID((permutated_prefix + index) % ATTESTATION_SUBNET_COUNT) @@ -1291,10 +1396,22 @@ - 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) + return uint64(state.genesis_time + slots_since_genesis * SLOT_DURATION_MS // 1000) + + +- name: compute_time_at_slot_ms#phase0 + sources: [] + spec: | + + def compute_time_at_slot_ms(state: BeaconState, slot: Slot) -> uint64: + """ + Return the time in milliseconds at the start of the given slot. + """ + slots_since_genesis = slot - GENESIS_SLOT + return uint64(state.genesis_time * 1000 + slots_since_genesis * SLOT_DURATION_MS) - name: compute_weak_subjectivity_period#phase0 @@ -3220,7 +3337,7 @@ - name: get_forkchoice_store#phase0 sources: [] spec: | - + def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: assert anchor_block.state_root == hash_tree_root(anchor_state) anchor_root = hash_tree_root(anchor_block) @@ -3229,7 +3346,7 @@ 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), + time=uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), genesis_time=anchor_state.genesis_time, justified_checkpoint=justified_checkpoint, finalized_checkpoint=finalized_checkpoint, @@ -3247,7 +3364,7 @@ - name: get_forkchoice_store#gloas sources: [] spec: | - + def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: assert anchor_block.state_root == hash_tree_root(anchor_state) anchor_root = hash_tree_root(anchor_block) @@ -3256,7 +3373,7 @@ 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), + time=uint64(anchor_state.genesis_time + SLOT_DURATION_MS * anchor_state.slot // 1000), genesis_time=anchor_state.genesis_time, justified_checkpoint=justified_checkpoint, finalized_checkpoint=finalized_checkpoint, @@ -3266,12 +3383,57 @@ equivocating_indices=set(), blocks={anchor_root: copy(anchor_block)}, block_states={anchor_root: copy(anchor_state)}, + # [New in Gloas:EIP7732] + block_timeliness={anchor_root: [True, True]}, checkpoint_states={justified_checkpoint: copy(anchor_state)}, unrealized_justifications={anchor_root: justified_checkpoint}, # [New in Gloas:EIP7732] - execution_payload_states={anchor_root: copy(anchor_state)}, - ptc_vote={anchor_root: Vector[boolean, PTC_SIZE]()}, + payload_states={anchor_root: copy(anchor_state)}, + # [New in Gloas:EIP7732] + payload_timeliness_vote={ + anchor_root: Vector[boolean, PTC_SIZE](True for _ in range(PTC_SIZE)) + }, + # [New in Gloas:EIP7732] + payload_data_availability_vote={ + anchor_root: Vector[boolean, PTC_SIZE](True for _ in range(PTC_SIZE)) + }, + ) + + +- name: get_forkchoice_store#heze + sources: [] + spec: | + + def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: + assert anchor_block.state_root == hash_tree_root(anchor_state) + anchor_root = hash_tree_root(anchor_block) + 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 + SLOT_DURATION_MS * anchor_state.slot // 1000), + 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)}, block_timeliness={anchor_root: [True, True]}, + checkpoint_states={justified_checkpoint: copy(anchor_state)}, + unrealized_justifications={anchor_root: justified_checkpoint}, + payload_states={anchor_root: copy(anchor_state)}, + payload_timeliness_vote={ + anchor_root: Vector[boolean, PTC_SIZE](True for _ in range(PTC_SIZE)) + }, + payload_data_availability_vote={ + anchor_root: Vector[boolean, PTC_SIZE](True for _ in range(PTC_SIZE)) + }, + # [New in Heze:EIP7805] + payload_inclusion_list_satisfaction={anchor_root: True}, ) @@ -3455,6 +3617,133 @@ return rewards, penalties +- name: get_inclusion_list_bits#heze + sources: [] + spec: | + + def get_inclusion_list_bits( + store: InclusionListStore, state: BeaconState, slot: Slot + ) -> Bitvector[INCLUSION_LIST_COMMITTEE_SIZE]: + """ + Return a ``Bitvector`` over inclusion list committee indices with bits set + for valid, non-equivocating inclusion list submissions for the given ``slot``. + """ + inclusion_list_committee = get_inclusion_list_committee(state, slot) + inclusion_list_committee_root = hash_tree_root(inclusion_list_committee) + key = (slot, inclusion_list_committee_root) + + validator_indices = [ + inclusion_list.validator_index + for inclusion_list in store.inclusion_lists[key] + if inclusion_list.validator_index not in store.equivocators[key] + ] + + return Bitvector[INCLUSION_LIST_COMMITTEE_SIZE]( + validator_index in validator_indices for validator_index in inclusion_list_committee + ) + + +- name: get_inclusion_list_committee#heze + sources: [] + spec: | + + def get_inclusion_list_committee( + state: BeaconState, slot: Slot + ) -> Vector[ValidatorIndex, INCLUSION_LIST_COMMITTEE_SIZE]: + """ + Get the inclusion list committee for the given ``slot``. + """ + epoch = compute_epoch_at_slot(slot) + indices: List[ValidatorIndex] = [] + # Concatenate all committees for this slot in order + committees_per_slot = get_committee_count_per_slot(state, epoch) + for i in range(committees_per_slot): + committee = get_beacon_committee(state, slot, CommitteeIndex(i)) + indices.extend(committee) + return Vector[ValidatorIndex, INCLUSION_LIST_COMMITTEE_SIZE]( + [indices[i % len(indices)] for i in range(INCLUSION_LIST_COMMITTEE_SIZE)] + ) + + +- name: get_inclusion_list_committee_assignment#heze + sources: [] + spec: | + + def get_inclusion_list_committee_assignment( + state: BeaconState, epoch: Epoch, validator_index: ValidatorIndex + ) -> Optional[Slot]: + """ + Returns the slot during the requested epoch in which the validator with + index ``validator_index`` is a member of the inclusion list committee. + Returns None if no assignment is found. + """ + next_epoch = Epoch(get_current_epoch(state) + 1) + assert epoch <= next_epoch + + start_slot = compute_start_slot_at_epoch(epoch) + for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH): + if validator_index in get_inclusion_list_committee(state, Slot(slot)): + return Slot(slot) + return None + + +- name: get_inclusion_list_signature#heze + sources: [] + spec: | + + def get_inclusion_list_signature( + state: BeaconState, inclusion_list: InclusionList, privkey: int + ) -> BLSSignature: + domain = get_domain( + state, DOMAIN_INCLUSION_LIST_COMMITTEE, compute_epoch_at_slot(inclusion_list.slot) + ) + signing_root = compute_signing_root(inclusion_list, domain) + return bls.Sign(privkey, signing_root) + + +- name: get_inclusion_list_store#heze + sources: [] + spec: | + + def get_inclusion_list_store() -> InclusionListStore: + # `cached_or_new_inclusion_list_store` is implementation and context dependent. + # It returns the cached `InclusionListStore`; if none exists, + # it initializes a new instance, caches it and returns it. + inclusion_list_store = cached_or_new_inclusion_list_store() + + return inclusion_list_store + + +- name: get_inclusion_list_submission_due_ms#heze + sources: [] + spec: | + + def get_inclusion_list_submission_due_ms(epoch: Epoch) -> uint64: + return get_slot_component_duration_ms(INCLUSION_LIST_SUBMISSION_DUE_BPS) + + +- name: get_inclusion_list_transactions#heze + sources: [] + spec: | + + def get_inclusion_list_transactions( + store: InclusionListStore, state: BeaconState, slot: Slot + ) -> Sequence[Transaction]: + inclusion_list_committee = get_inclusion_list_committee(state, slot) + inclusion_list_committee_root = hash_tree_root(inclusion_list_committee) + key = (slot, inclusion_list_committee_root) + + inclusion_list_transactions = [ + transaction + for inclusion_list in store.inclusion_lists[key] + if inclusion_list.validator_index not in store.equivocators[key] + for transaction in inclusion_list.transactions + ] + + # Deduplicate inclusion list transactions. Order does not need to be preserved. + return list(set(inclusion_list_transactions)) + + - name: get_index_for_new_builder#gloas sources: [] spec: | @@ -3783,13 +4072,13 @@ - name: get_node_children#gloas sources: [] spec: | - + def get_node_children( store: Store, blocks: Dict[Root, BeaconBlock], node: ForkChoiceNode ) -> Sequence[ForkChoiceNode]: if node.payload_status == PAYLOAD_STATUS_PENDING: children = [ForkChoiceNode(root=node.root, payload_status=PAYLOAD_STATUS_EMPTY)] - if node.root in store.execution_payload_states: + if node.root in store.payload_states: children.append(ForkChoiceNode(root=node.root, payload_status=PAYLOAD_STATUS_FULL)) return children else: @@ -4028,6 +4317,14 @@ return head_root +- name: get_proposer_inclusion_list_cutoff_ms#heze + sources: [] + spec: | + + def get_proposer_inclusion_list_cutoff_ms(epoch: Epoch) -> uint64: + return get_slot_component_duration_ms(PROPOSER_INCLUSION_LIST_CUTOFF_BPS) + + - name: get_proposer_preferences_signature#gloas sources: [] spec: | @@ -4072,28 +4369,25 @@ - name: get_ptc#gloas sources: [] spec: | - + def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: """ Get the payload timeliness committee for the given ``slot``. """ epoch = compute_epoch_at_slot(slot) - seed = hash(get_seed(state, epoch, DOMAIN_PTC_ATTESTER) + uint_to_bytes(slot)) - indices: List[ValidatorIndex] = [] - # Concatenate all committees for this slot in order - committees_per_slot = get_committee_count_per_slot(state, epoch) - for i in range(committees_per_slot): - committee = get_beacon_committee(state, slot, CommitteeIndex(i)) - indices.extend(committee) - return compute_balance_weighted_selection( - state, indices, seed, size=PTC_SIZE, shuffle_indices=False - ) + state_epoch = get_current_epoch(state) + if epoch < state_epoch: + assert epoch + 1 == state_epoch + return state.ptc_window[slot % SLOTS_PER_EPOCH] + assert epoch <= state_epoch + MIN_SEED_LOOKAHEAD + offset = (epoch - state_epoch + 1) * SLOTS_PER_EPOCH + return state.ptc_window[offset + slot % SLOTS_PER_EPOCH] - name: get_ptc_assignment#gloas sources: [] spec: | - + def get_ptc_assignment( state: BeaconState, epoch: Epoch, validator_index: ValidatorIndex ) -> Optional[Slot]: @@ -4102,8 +4396,8 @@ index ``validator_index`` is a member of the PTC. Returns None if no assignment is found. """ - next_epoch = Epoch(get_current_epoch(state) + 1) - assert epoch <= next_epoch + max_epoch = Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD) + assert epoch <= max_epoch start_slot = compute_start_slot_at_epoch(epoch) for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH): @@ -4181,9 +4475,9 @@ - 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 + return (store.time - store.genesis_time) * 1000 // SLOT_DURATION_MS - name: get_source_deltas#phase0 @@ -4397,18 +4691,23 @@ - name: get_upcoming_proposal_slots#gloas sources: [] spec: | - + def get_upcoming_proposal_slots( state: BeaconState, validator_index: ValidatorIndex ) -> Sequence[Slot]: """ - Get the slots in the next epoch for which ``validator_index`` is proposing. + Get the future slots in the current epoch and the slots in the next + epoch for which ``validator_index`` is proposing. """ - return [ - Slot(compute_start_slot_at_epoch(get_current_epoch(state) + Epoch(1)) + offset) - for offset, proposer_index in enumerate(state.proposer_lookahead[SLOTS_PER_EPOCH:]) - if validator_index == proposer_index - ] + current_epoch_start_slot = compute_start_slot_at_epoch(get_current_epoch(state)) + upcoming_proposal_slots = [] + for offset, proposer_index in enumerate(state.proposer_lookahead): + slot = Slot(current_epoch_start_slot + offset) + if slot <= state.slot: + continue + if validator_index == proposer_index: + upcoming_proposal_slots.append(slot) + return upcoming_proposal_slots - name: get_validator_activation_churn_limit#deneb @@ -4615,6 +4914,14 @@ return withdrawals, withdrawal_index, processed_count +- name: get_view_freeze_cutoff_ms#heze + sources: [] + spec: | + + def get_view_freeze_cutoff_ms(epoch: Epoch) -> uint64: + return get_slot_component_duration_ms(VIEW_FREEZE_CUTOFF_BPS) + + - name: get_voting_source#phase0 sources: [] spec: | @@ -4859,6 +5166,32 @@ return lookahead +- name: initialize_ptc_window#gloas + sources: [] + spec: | + + def initialize_ptc_window( + state: BeaconState, + ) -> Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH]: + """ + Return the cached PTC window starting from the current epoch. + Used to initialize the ``ptc_window`` field in the beacon state at genesis and after forks. + """ + empty_previous_epoch = [ + Vector[ValidatorIndex, PTC_SIZE]([ValidatorIndex(0) for _ in range(PTC_SIZE)]) + for _ in range(SLOTS_PER_EPOCH) + ] + + ptcs = [] + current_epoch = get_current_epoch(state) + for e in range(1 + MIN_SEED_LOOKAHEAD): + epoch = Epoch(current_epoch + e) + start_slot = compute_start_slot_at_epoch(epoch) + ptcs += [compute_ptc(state, Slot(start_slot + i)) for i in range(SLOTS_PER_EPOCH)] + + return empty_previous_epoch + ptcs + + - name: initiate_builder_exit#gloas sources: - file: beacon-chain/core/gloas/builder_exit.go @@ -5383,6 +5716,30 @@ return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY +- name: is_inclusion_list_bits_inclusive#heze + sources: [] + spec: | + + def is_inclusion_list_bits_inclusive( + store: InclusionListStore, + state: BeaconState, + slot: Slot, + inclusion_list_bits: Bitvector[INCLUSION_LIST_COMMITTEE_SIZE], + ) -> bool: + """ + Return ``True`` if and only if ``inclusion_list_bits`` is a superset of + the locally observed inclusion list bits for the given ``slot``. + """ + local_inclusion_list_bits = get_inclusion_list_bits(store, state, slot) + + return all( + inclusion_bit or not local_inclusion_bit + for inclusion_bit, local_inclusion_bit in zip( + inclusion_list_bits, local_inclusion_list_bits + ) + ) + + - name: is_merge_transition_block#bellatrix sources: [] spec: | @@ -5409,6 +5766,23 @@ return store.next_sync_committee != SyncCommittee() +- name: is_not_from_future_slot#phase0 + sources: [] + spec: | + + def is_not_from_future_slot( + state: BeaconState, + slot: Slot, + current_time_ms: uint64, + ) -> bool: + """ + Check if the given slot is not from the future + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). + """ + slot_time_ms = compute_time_at_slot_ms(state, slot) + return current_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY >= slot_time_ms + + - name: is_optimistic#bellatrix sources: - file: beacon-chain/blockchain/chain_info.go @@ -5523,48 +5897,109 @@ ) -- name: is_payload_timely#gloas +- name: is_payload_data_available#gloas sources: [] spec: | - - def is_payload_timely(store: Store, root: Root) -> bool: + + def is_payload_data_available(store: Store, root: Root) -> bool: """ - Return whether the execution payload for the beacon block with root ``root`` + Return whether the blob data for the beacon block with root ``root`` was voted as present by the PTC, and was locally determined to be available. """ # The beacon block root must be known - assert root in store.ptc_vote + assert root in store.payload_data_availability_vote - # If the payload is not locally available, the payload + # If the payload is not locally available, the blob data # is not considered available regardless of the PTC vote - if root not in store.execution_payload_states: + if root not in store.payload_states: return False - return sum(store.ptc_vote[root]) > PAYLOAD_TIMELY_THRESHOLD + return sum(store.payload_data_availability_vote[root]) > DATA_AVAILABILITY_TIMELY_THRESHOLD -- name: is_proposer#phase0 +- name: is_payload_inclusion_list_satisfied#heze sources: [] spec: | - - def is_proposer(state: BeaconState, validator_index: ValidatorIndex) -> bool: - return get_beacon_proposer_index(state) == validator_index + + def is_payload_inclusion_list_satisfied(store: Store, root: Root) -> bool: + """ + Return whether the execution payload for the beacon block with root ``root`` + satisfied the inclusion list constraints, and was locally determined to be available. + """ + # The beacon block root must be known + assert root in store.payload_inclusion_list_satisfaction + + # If the payload is not locally available, the payload + # is not considered to satisfy the inclusion list constraints + if root not in store.payload_states: + return False + + return store.payload_inclusion_list_satisfaction[root] -- name: is_proposer_equivocation#phase0 +- name: is_payload_timely#gloas sources: [] spec: | - - def is_proposer_equivocation(store: Store, root: Root) -> bool: - block = store.blocks[root] - proposer_index = block.proposer_index - slot = block.slot - # roots from the same slot and proposer - matching_roots = [ - root - for root, block in store.blocks.items() - if (block.proposer_index == proposer_index and block.slot == slot) - ] + + def is_payload_timely(store: Store, root: Root) -> bool: + """ + Return whether the execution payload for the beacon block with root ``root`` + was voted as present by the PTC, and was locally determined to be available. + """ + # The beacon block root must be known + assert root in store.payload_timeliness_vote + + # If the payload is not locally available, the payload + # is not considered available regardless of the PTC vote + if root not in store.payload_states: + return False + + return sum(store.payload_timeliness_vote[root]) > PAYLOAD_TIMELY_THRESHOLD + + +- name: is_pending_validator#gloas + sources: [] + spec: | + + def is_pending_validator(state: BeaconState, pubkey: BLSPubkey) -> bool: + """ + Check if a pending deposit with a valid signature is in the queue for the given pubkey. + """ + for pending_deposit in state.pending_deposits: + if pending_deposit.pubkey != pubkey: + continue + if is_valid_deposit_signature( + pending_deposit.pubkey, + pending_deposit.withdrawal_credentials, + pending_deposit.amount, + pending_deposit.signature, + ): + return True + return False + + +- name: is_proposer#phase0 + sources: [] + spec: | + + def is_proposer(state: BeaconState, validator_index: ValidatorIndex) -> bool: + return get_beacon_proposer_index(state) == validator_index + + +- name: is_proposer_equivocation#phase0 + sources: [] + spec: | + + def is_proposer_equivocation(store: Store, root: Root) -> bool: + block = store.blocks[root] + proposer_index = block.proposer_index + slot = block.slot + # roots from the same slot and proposer + matching_roots = [ + root + for root, block in store.blocks.items() + if (block.proposer_index == proposer_index and block.slot == slot) + ] return len(matching_roots) > 1 @@ -5625,11 +6060,11 @@ - name: is_supporting_vote#gloas sources: [] spec: | - + def is_supporting_vote(store: Store, node: ForkChoiceNode, message: LatestMessage) -> bool: """ - Returns whether a vote for ``message.root`` supports the chain containing the beacon block ``node.root`` with the - payload contents indicated by ``node.payload_status`` as head during slot ``node.slot``. + Returns whether the vote ``message`` supports the chain containing the + forkchoice node ``node``. """ block = store.blocks[node.root] if node.root == message.root: @@ -5711,6 +6146,24 @@ return True +- name: is_valid_inclusion_list_signature#heze + sources: [] + spec: | + + def is_valid_inclusion_list_signature( + state: BeaconState, signed_inclusion_list: SignedInclusionList + ) -> bool: + """ + Check if ``signed_inclusion_list`` has a valid signature. + """ + message = signed_inclusion_list.message + index = message.validator_index + pubkey = state.validators[index].pubkey + domain = get_domain(state, DOMAIN_INCLUSION_LIST_COMMITTEE, compute_epoch_at_slot(message.slot)) + signing_root = compute_signing_root(message, domain) + return bls.Verify(pubkey, signing_root, signed_inclusion_list.signature) + + - name: is_valid_indexed_attestation#phase0 sources: - file: beacon-chain/core/blocks/attestation.go @@ -5854,12 +6307,21 @@ - name: is_valid_proposal_slot#gloas sources: [] spec: | - + def is_valid_proposal_slot(state: BeaconState, preferences: ProposerPreferences) -> bool: """ - Check if the validator is the proposer for the given slot in the next epoch. + Check if the validator is the proposer for the given slot in the current or + next epoch. """ - index = SLOTS_PER_EPOCH + preferences.proposal_slot % SLOTS_PER_EPOCH + current_epoch = get_current_epoch(state) + proposal_epoch = compute_epoch_at_slot(preferences.proposal_slot) + if proposal_epoch < current_epoch: + return False + if proposal_epoch > current_epoch + Epoch(1): + return False + + index = (proposal_epoch - current_epoch) * SLOTS_PER_EPOCH + index += preferences.proposal_slot % SLOTS_PER_EPOCH return state.proposer_lookahead[index] == preferences.validator_index @@ -5916,6 +6378,29 @@ return is_total_difficulty_reached and is_parent_total_difficulty_valid +- name: is_within_slot_range#phase0 + sources: [] + spec: | + + def is_within_slot_range( + state: BeaconState, + slot: Slot, + slot_range: uint64, + current_time_ms: uint64, + ) -> bool: + """ + Check if the current time is within the inclusive slot range ``[slot, slot + slot_range]`` + (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance on both ends). + """ + start_time_ms = compute_time_at_slot_ms(state, slot) + if current_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY < start_time_ms: + return False + end_time_ms = compute_time_at_slot_ms(state, Slot(slot + slot_range + 1)) + if end_time_ms + MAXIMUM_GOSSIP_CLOCK_DISPARITY < current_time_ms: + return False + return True + + - name: is_within_weak_subjectivity_period#phase0 sources: - file: beacon-chain/core/helpers/weak_subjectivity.go @@ -6367,7 +6852,7 @@ - name: on_block#gloas sources: [] spec: | - + def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: """ Run ``on_block`` upon receiving a new block. @@ -6382,8 +6867,8 @@ parent_bid = parent_block.body.signed_execution_payload_bid.message # Make a copy of the state to avoid mutability issues if is_parent_node_full(store, block): - assert block.parent_root in store.execution_payload_states - state = copy(store.execution_payload_states[block.parent_root]) + assert block.parent_root in store.payload_states + state = copy(store.payload_states[block.parent_root]) else: assert bid.parent_block_hash == parent_bid.parent_block_hash state = copy(store.block_states[block.parent_root]) @@ -6412,7 +6897,8 @@ # Add new state for this block to the store store.block_states[block_root] = state # Add a new PTC voting for this block to the store - store.ptc_vote[block_root] = [False] * PTC_SIZE + store.payload_timeliness_vote[block_root] = [False] * PTC_SIZE + store.payload_data_availability_vote[block_root] = [False] * PTC_SIZE # Notify the store about the payload_attestations in the block notify_ptc_messages(store, state, block.body.payload_attestations) @@ -6430,7 +6916,33 @@ - name: on_execution_payload#gloas sources: [] spec: | - + + def on_execution_payload(store: Store, signed_envelope: SignedExecutionPayloadEnvelope) -> None: + """ + Run ``on_execution_payload`` upon receiving a new execution payload. + """ + envelope = signed_envelope.message + # The corresponding beacon block root needs to be known + assert envelope.beacon_block_root in store.block_states + + # Check if blob data is available + # If not, this payload MAY be queued and subsequently considered when blob data becomes available + assert is_data_available(envelope.beacon_block_root) + + # Make a copy of the state to avoid mutability issues + state = copy(store.block_states[envelope.beacon_block_root]) + + # Process the execution payload + process_execution_payload(state, signed_envelope, EXECUTION_ENGINE) + + # Add new state for this payload to the store + store.payload_states[envelope.beacon_block_root] = state + + +- name: on_execution_payload#heze + sources: [] + spec: | + def on_execution_payload(store: Store, signed_envelope: SignedExecutionPayloadEnvelope) -> None: """ Run ``on_execution_payload`` upon receiving a new execution payload. @@ -6449,14 +6961,40 @@ # Process the execution payload process_execution_payload(state, signed_envelope, EXECUTION_ENGINE) + # [New in Heze:EIP7805] + # Check if this payload satisfies the inclusion list constraints + # If not, add this payload to the store as inclusion list constraints unsatisfied + record_payload_inclusion_list_satisfaction( + store, state, envelope.beacon_block_root, envelope.payload, EXECUTION_ENGINE + ) + # Add new state for this payload to the store - store.execution_payload_states[envelope.beacon_block_root] = state + store.payload_states[envelope.beacon_block_root] = state + + +- name: on_inclusion_list#heze + sources: [] + spec: | + + def on_inclusion_list(store: Store, signed_inclusion_list: SignedInclusionList) -> None: + """ + Run ``on_inclusion_list`` upon receiving a new inclusion list. + """ + inclusion_list = signed_inclusion_list.message + + seconds_since_genesis = store.time - store.genesis_time + time_into_slot_ms = seconds_to_milliseconds(seconds_since_genesis) % SLOT_DURATION_MS + epoch = get_current_store_epoch(store) + view_freeze_cutoff_ms = get_view_freeze_cutoff_ms(epoch) + is_before_view_freeze_cutoff = time_into_slot_ms < view_freeze_cutoff_ms + + process_inclusion_list(get_inclusion_list_store(), inclusion_list, is_before_view_freeze_cutoff) - name: on_payload_attestation_message#gloas sources: [] spec: | - + def on_payload_attestation_message( store: Store, ptc_message: PayloadAttestationMessage, is_from_block: bool = False ) -> None: @@ -6467,6 +7005,7 @@ # The beacon block root must be known data = ptc_message.data # PTC attestation must be for a known block. If block is unknown, delay consideration until the block is found + assert data.beacon_block_root in store.block_states state = store.block_states[data.beacon_block_root] ptc = get_ptc(state, data.slot) # PTC votes can only change the vote for their assigned beacon block, return early otherwise @@ -6488,22 +7027,26 @@ signature=ptc_message.signature, ), ) - # Update the ptc vote for the block + # Update the votes for the block ptc_index = ptc.index(ptc_message.validator_index) - ptc_vote = store.ptc_vote[data.beacon_block_root] - ptc_vote[ptc_index] = data.payload_present + payload_timeliness_vote = store.payload_timeliness_vote[data.beacon_block_root] + payload_timeliness_vote[ptc_index] = data.payload_present + payload_data_availability_vote = store.payload_data_availability_vote[data.beacon_block_root] + payload_data_availability_vote[ptc_index] = data.blob_data_available - name: on_tick#phase0 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 + tick_slot = (time - store.genesis_time) * 1000 // SLOT_DURATION_MS while get_current_slot(store) < tick_slot: - previous_time = store.genesis_time + (get_current_slot(store) + 1) * SECONDS_PER_SLOT + previous_time = ( + store.genesis_time + (get_current_slot(store) + 1) * SLOT_DURATION_MS // 1000 + ) on_tick_per_slot(store, previous_time) on_tick_per_slot(store, time) @@ -6672,6 +7215,37 @@ ) +- name: prepare_execution_payload#heze + 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]: + # 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).withdrawals, + parent_beacon_block_root=hash_tree_root(state.latest_block_header), + # [New in Heze:EIP7805] + inclusion_list_transactions=get_inclusion_list_transactions( + get_inclusion_list_store(), state, Slot(state.slot - 1) + ), + ) + return execution_engine.notify_forkchoice_updated( + head_block_hash=state.latest_block_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 @@ -7319,7 +7893,7 @@ - name: process_deposit_request#gloas sources: [] spec: | - + def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None: # [New in Gloas:EIP7732] builder_pubkeys = [b.pubkey for b in state.builders] @@ -7330,8 +7904,11 @@ # already exists with this pubkey, apply the deposit to their balance is_builder = deposit_request.pubkey in builder_pubkeys is_validator = deposit_request.pubkey in validator_pubkeys - is_builder_prefix = is_builder_withdrawal_credential(deposit_request.withdrawal_credentials) - if is_builder or (is_builder_prefix and not is_validator): + if is_builder or ( + is_builder_withdrawal_credential(deposit_request.withdrawal_credentials) + and not is_validator + and not is_pending_validator(state, deposit_request.pubkey) + ): # Apply builder deposits immediately apply_deposit_for_builder( state, @@ -7532,7 +8109,7 @@ - name: process_epoch#gloas sources: [] spec: | - + def process_epoch(state: BeaconState) -> None: process_justification_and_finalization(state) process_inactivity_updates(state) @@ -7551,6 +8128,8 @@ process_participation_flag_updates(state) process_sync_committee_updates(state) process_proposer_lookahead(state) + # [New in Gloas:EIP7732] + process_ptc_window(state) - name: process_eth1_data#phase0 @@ -8047,6 +8626,35 @@ ) +- name: process_inclusion_list#heze + sources: [] + spec: | + + def process_inclusion_list( + store: InclusionListStore, inclusion_list: InclusionList, is_before_view_freeze_cutoff: bool + ) -> None: + key = (inclusion_list.slot, inclusion_list.inclusion_list_committee_root) + + # Ignore `inclusion_list` from equivocators. + if inclusion_list.validator_index in store.equivocators[key]: + return + + for stored_inclusion_list in store.inclusion_lists[key]: + if stored_inclusion_list.validator_index != inclusion_list.validator_index: + continue + + if stored_inclusion_list != inclusion_list: + store.equivocators[key].add(inclusion_list.validator_index) + store.inclusion_lists[key].remove(stored_inclusion_list) + + # Whether it was an equivocation or not, we have processed this `inclusion_list`. + return + + # Only store `inclusion_list` if it arrived before the view freeze cutoff. + if is_before_view_freeze_cutoff: + store.inclusion_lists[key].add(inclusion_list) + + - name: process_justification_and_finalization#phase0 sources: - file: beacon-chain/core/epoch/precompute/justification_finalization.go @@ -8572,6 +9180,24 @@ slash_validator(state, header_1.proposer_index) +- name: process_ptc_window#gloas + sources: [] + spec: | + + def process_ptc_window(state: BeaconState) -> None: + """ + Update the cached PTC window. + """ + # Shift all epochs forward by one + state.ptc_window[: len(state.ptc_window) - SLOTS_PER_EPOCH] = state.ptc_window[SLOTS_PER_EPOCH:] + # Fill in the last epoch + next_epoch = Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD + 1) + start_slot = compute_start_slot_at_epoch(next_epoch) + state.ptc_window[len(state.ptc_window) - SLOTS_PER_EPOCH :] = [ + compute_ptc(state, Slot(slot)) for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH) + ] + + - name: process_randao#phase0 sources: - file: beacon-chain/core/blocks/randao.go @@ -9350,6 +9976,26 @@ ] +- name: record_payload_inclusion_list_satisfaction#heze + sources: [] + spec: | + + def record_payload_inclusion_list_satisfaction( + store: Store, + state: BeaconState, + root: Root, + payload: ExecutionPayload, + execution_engine: ExecutionEngine, + ) -> None: + inclusion_list_transactions = get_inclusion_list_transactions( + get_inclusion_list_store(), state, Slot(state.slot - 1) + ) + is_inclusion_list_satisfied = execution_engine.is_inclusion_list_satisfied( + payload, inclusion_list_transactions + ) + store.payload_inclusion_list_satisfaction[root] = is_inclusion_list_satisfied + + - name: recover_matrix#fulu sources: [] spec: | @@ -9458,11 +10104,29 @@ - name: should_extend_payload#gloas sources: [] spec: | - + def should_extend_payload(store: Store, root: Root) -> bool: proposer_root = store.proposer_boost_root return ( - is_payload_timely(store, root) + (is_payload_timely(store, root) and is_payload_data_available(store, root)) + or proposer_root == Root() + or store.blocks[proposer_root].parent_root != root + or is_parent_node_full(store, store.blocks[proposer_root]) + ) + + +- name: should_extend_payload#heze + sources: [] + spec: | + + def should_extend_payload(store: Store, root: Root) -> bool: + # [New in Heze:EIP7805] + if not is_payload_inclusion_list_satisfied(store, root): + return False + + proposer_root = store.proposer_boost_root + return ( + (is_payload_timely(store, root) and is_payload_data_available(store, root)) or proposer_root == Root() or store.blocks[proposer_root].parent_root != root or is_parent_node_full(store, store.blocks[proposer_root]) @@ -9807,7 +10471,7 @@ - name: update_latest_messages#gloas sources: [] spec: | - + def update_latest_messages( store: Store, attesting_indices: Sequence[ValidatorIndex], attestation: Attestation ) -> None: @@ -9819,8 +10483,11 @@ ] for i in non_equivocating_attesting_indices: if i not in store.latest_messages or slot > store.latest_messages[i].slot: + # [Modified in Gloas:EIP7732] store.latest_messages[i] = LatestMessage( - slot=slot, root=beacon_block_root, payload_present=payload_present + slot=slot, + root=beacon_block_root, + payload_present=payload_present, ) @@ -10654,7 +11321,7 @@ - name: upgrade_to_gloas#gloas sources: [] spec: | - + def upgrade_to_gloas(pre: fulu.BeaconState) -> BeaconState: epoch = fulu.get_current_epoch(pre) @@ -10721,6 +11388,8 @@ latest_block_hash=pre.latest_execution_payload_header.block_hash, # [New in Gloas:EIP7732] payload_expected_withdrawals=[], + # [New in Gloas:EIP7732] + ptc_window=initialize_ptc_window(pre), ) # [New in Gloas:EIP7732] @@ -10729,6 +11398,431 @@ return post +- name: upgrade_to_heze#heze + sources: [] + spec: | + + def upgrade_to_heze(pre: gloas.BeaconState) -> BeaconState: + epoch = gloas.get_current_epoch(pre) + latest_execution_payload_bid = ExecutionPayloadBid( + parent_block_hash=pre.latest_execution_payload_bid.parent_block_hash, + parent_block_root=pre.latest_execution_payload_bid.parent_block_root, + block_hash=pre.latest_execution_payload_bid.block_hash, + prev_randao=pre.latest_execution_payload_bid.prev_randao, + fee_recipient=pre.latest_execution_payload_bid.fee_recipient, + gas_limit=pre.latest_execution_payload_bid.gas_limit, + builder_index=pre.latest_execution_payload_bid.builder_index, + slot=pre.latest_execution_payload_bid.slot, + value=pre.latest_execution_payload_bid.value, + execution_payment=pre.latest_execution_payload_bid.execution_payment, + blob_kzg_commitments=pre.latest_execution_payload_bid.blob_kzg_commitments, + # [New in Heze:EIP7805] + inclusion_list_bits=Bitvector[INCLUSION_LIST_COMMITTEE_SIZE](), + ) + + 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 Heze:EIP7805] + current_version=HEZE_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 Heze:EIP7805] + latest_execution_payload_bid=latest_execution_payload_bid, + 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, + proposer_lookahead=pre.proposer_lookahead, + builders=pre.builders, + next_withdrawal_builder_index=pre.next_withdrawal_builder_index, + execution_payload_availability=pre.execution_payload_availability, + builder_pending_payments=pre.builder_pending_payments, + builder_pending_withdrawals=pre.builder_pending_withdrawals, + latest_block_hash=pre.latest_block_hash, + payload_expected_withdrawals=pre.payload_expected_withdrawals, + ptc_window=pre.ptc_window, + ) + + return post + + +- name: validate_attester_slashing_gossip#phase0 + sources: [] + spec: | + + def validate_attester_slashing_gossip( + seen: Seen, + state: BeaconState, + attester_slashing: AttesterSlashing, + ) -> None: + """ + Validate an AttesterSlashing for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + attestation_1 = attester_slashing.attestation_1 + attestation_2 = attester_slashing.attestation_2 + + attesting_indices_1 = set(attestation_1.attesting_indices) + attesting_indices_2 = set(attestation_2.attesting_indices) + slashable_indices = attesting_indices_1.intersection(attesting_indices_2) + + # [IGNORE] At least one index in the intersection has not yet been seen + new_indices = slashable_indices.difference(seen.attester_slashing_indices) + if len(new_indices) == 0: + raise GossipIgnore("all attester slashing indices already seen") + + # [REJECT] The attestation data is slashable (double vote or surround vote) + if not is_slashable_attestation_data(attestation_1.data, attestation_2.data): + raise GossipReject("attestation data is not slashable") + + # [REJECT] All validator indices in the first indexed attestation are valid + if any(index >= len(state.validators) for index in attestation_1.attesting_indices): + raise GossipReject("validator index out of range in indexed attestation 1") + + # [REJECT] The first indexed attestation has valid properties + if not is_valid_indexed_attestation(state, attestation_1): + raise GossipReject("invalid indexed attestation 1") + + # [REJECT] All validator indices in the second indexed attestation are valid + if any(index >= len(state.validators) for index in attestation_2.attesting_indices): + raise GossipReject("validator index out of range in indexed attestation 2") + + # [REJECT] The second indexed attestation has valid properties + if not is_valid_indexed_attestation(state, attestation_2): + raise GossipReject("invalid indexed attestation 2") + + # [REJECT] At least one validator in the intersection is slashable + slashable_any = False + current_epoch = get_current_epoch(state) + for index in slashable_indices: + if is_slashable_validator(state.validators[index], current_epoch): + slashable_any = True + break + if not slashable_any: + raise GossipReject("no slashable validators in intersection") + + # Mark these indices as seen + seen.attester_slashing_indices.update(slashable_indices) + + +- name: validate_beacon_aggregate_and_proof_gossip#phase0 + sources: [] + spec: | + + def validate_beacon_aggregate_and_proof_gossip( + seen: Seen, + store: Store, + state: BeaconState, + signed_aggregate_and_proof: SignedAggregateAndProof, + current_time_ms: uint64, + ) -> None: + """ + Validate a SignedAggregateAndProof for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + aggregate_and_proof = signed_aggregate_and_proof.message + aggregate = aggregate_and_proof.aggregate + index = aggregate.data.index + aggregation_bits = aggregate.aggregation_bits + + # [REJECT] The committee index is within the expected range + committee_count = get_committee_count_per_slot(state, aggregate.data.target.epoch) + if index >= committee_count: + raise GossipReject("committee index out of range") + + # [IGNORE] The aggregate attestation's slot is within the propagation range + # (MAY be queued for processing at the appropriate slot) + if not is_within_slot_range( + state, aggregate.data.slot, ATTESTATION_PROPAGATION_SLOT_RANGE, current_time_ms + ): + raise GossipIgnore("attestation slot not within propagation range") + + # [REJECT] The aggregate attestation's epoch matches its target + if aggregate.data.target.epoch != compute_epoch_at_slot(aggregate.data.slot): + raise GossipReject("attestation epoch does not match target epoch") + + # [REJECT] The number of aggregation bits matches the committee size + committee = get_beacon_committee(state, aggregate.data.slot, index) + if len(aggregation_bits) != len(committee): + raise GossipReject("aggregation bits length does not match committee size") + + # [REJECT] The aggregate attestation has participants + attesting_indices = get_attesting_indices(state, aggregate) + if len(attesting_indices) < 1: + raise GossipReject("aggregate has no participants") + + # [IGNORE] A valid aggregate with a superset of aggregation bits has not already been seen + aggregate_data_root = hash_tree_root(aggregate.data) + aggregate_bits = tuple(bool(bit) for bit in aggregation_bits) + seen_aggregation_bits = seen.aggregate_data_roots.get(aggregate_data_root, set()) + for prior_aggregation_bits in seen_aggregation_bits: + is_non_strict_superset = True + for prior_bit, aggregate_bit in zip(prior_aggregation_bits, aggregate_bits): + if aggregate_bit and not prior_bit: + is_non_strict_superset = False + break + if is_non_strict_superset: + raise GossipIgnore("already seen aggregate for this data") + + # [IGNORE] This is the first valid aggregate for this aggregator in this epoch + aggregator_index = aggregate_and_proof.aggregator_index + target_epoch = aggregate.data.target.epoch + if (aggregator_index, target_epoch) in seen.aggregator_epochs: + raise GossipIgnore("already seen aggregate from this aggregator for this epoch") + + # [REJECT] The selection proof selects the validator as an aggregator + if not is_aggregator(state, aggregate.data.slot, index, aggregate_and_proof.selection_proof): + raise GossipReject("validator is not selected as aggregator") + + # [REJECT] The aggregator's validator index is within the committee + if aggregator_index not in committee: + raise GossipReject("aggregator index not in committee") + + # [REJECT] The selection proof signature is valid + aggregator = state.validators[aggregator_index] + domain = get_domain(state, DOMAIN_SELECTION_PROOF, target_epoch) + signing_root = compute_signing_root(aggregate.data.slot, domain) + if not bls.Verify(aggregator.pubkey, signing_root, aggregate_and_proof.selection_proof): + raise GossipReject("invalid selection proof signature") + + # [REJECT] The aggregator signature is valid + domain = get_domain(state, DOMAIN_AGGREGATE_AND_PROOF, target_epoch) + signing_root = compute_signing_root(aggregate_and_proof, domain) + if not bls.Verify(aggregator.pubkey, signing_root, signed_aggregate_and_proof.signature): + raise GossipReject("invalid aggregator signature") + + # [REJECT] The aggregate signature is valid + if not is_valid_indexed_attestation(state, get_indexed_attestation(state, aggregate)): + raise GossipReject("invalid aggregate signature") + + # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + if aggregate.data.beacon_block_root not in store.blocks: + raise GossipIgnore("block being voted for has not been seen") + + # [REJECT] The block being voted for passes validation + if aggregate.data.beacon_block_root not in store.block_states: + raise GossipReject("block being voted for failed validation") + + # [REJECT] The target block is an ancestor of the LMD vote block + checkpoint_block = get_checkpoint_block( + store, aggregate.data.beacon_block_root, aggregate.data.target.epoch + ) + if checkpoint_block != aggregate.data.target.root: + raise GossipReject("target block is not an ancestor of LMD vote block") + + # [IGNORE] The finalized checkpoint is an ancestor of the block + finalized_checkpoint_block = get_checkpoint_block( + store, aggregate.data.beacon_block_root, store.finalized_checkpoint.epoch + ) + if finalized_checkpoint_block != store.finalized_checkpoint.root: + raise GossipIgnore("finalized checkpoint is not an ancestor of block") + + # Mark this aggregate as seen + seen.aggregator_epochs.add((aggregator_index, target_epoch)) + if aggregate_data_root not in seen.aggregate_data_roots: + seen.aggregate_data_roots[aggregate_data_root] = set() + seen.aggregate_data_roots[aggregate_data_root].add(aggregate_bits) + + +- name: validate_beacon_attestation_gossip#phase0 + sources: [] + spec: | + + def validate_beacon_attestation_gossip( + seen: Seen, + store: Store, + state: BeaconState, + attestation: Attestation, + subnet_id: uint64, + current_time_ms: uint64, + ) -> None: + """ + Validate an Attestation for gossip propagation on a subnet. + Raises GossipIgnore or GossipReject on validation failure. + """ + data = attestation.data + committee_index = data.index + target_epoch = data.target.epoch + aggregation_bits = attestation.aggregation_bits + + # [REJECT] The committee index is within the expected range + committees_per_slot = get_committee_count_per_slot(state, target_epoch) + if committee_index >= committees_per_slot: + raise GossipReject("committee index out of range") + + # [REJECT] The attestation is for the correct subnet + expected_subnet = compute_subnet_for_attestation( + committees_per_slot, data.slot, committee_index + ) + if expected_subnet != subnet_id: + raise GossipReject("attestation is for wrong subnet") + + # [IGNORE] The attestation slot is within the propagation range + # (MAY be queued for processing at the appropriate slot) + if not is_within_slot_range( + state, data.slot, ATTESTATION_PROPAGATION_SLOT_RANGE, current_time_ms + ): + raise GossipIgnore("attestation slot not within propagation range") + + # [REJECT] The attestation's epoch matches its target + if target_epoch != compute_epoch_at_slot(data.slot): + raise GossipReject("attestation epoch does not match target epoch") + + # [REJECT] The attestation is unaggregated (exactly one bit set) + num_bits_set = sum(1 for bit in aggregation_bits if bit) + if num_bits_set != 1: + raise GossipReject("attestation is not unaggregated") + + # [REJECT] The number of aggregation bits matches the committee size + committee = get_beacon_committee(state, data.slot, committee_index) + if len(aggregation_bits) != len(committee): + raise GossipReject("aggregation bits length does not match committee size") + + # [IGNORE] No other valid attestation seen for this validator and target epoch + participant_index = committee[aggregation_bits.index(True)] + if (participant_index, target_epoch) in seen.attestation_validator_epochs: + raise GossipIgnore("already seen attestation from this validator for this epoch") + + # [REJECT] The attestation signature is valid + indexed_attestation = get_indexed_attestation(state, attestation) + if not is_valid_indexed_attestation(state, indexed_attestation): + raise GossipReject("invalid attestation signature") + + # [IGNORE] The block being voted for has been seen (via gossip or non-gossip sources) + # (MAY be queued until block is retrieved) + beacon_block_root = data.beacon_block_root + if beacon_block_root not in store.blocks: + raise GossipIgnore("block being voted for has not been seen") + + # [REJECT] The block being voted for passes validation + if beacon_block_root not in store.block_states: + raise GossipReject("block being voted for failed validation") + + # [REJECT] The attestation's target block is an ancestor of the LMD vote block + target_checkpoint_block = get_checkpoint_block(store, beacon_block_root, target_epoch) + if target_checkpoint_block != data.target.root: + raise GossipReject("target block is not an ancestor of LMD vote block") + + # [IGNORE] The current finalized_checkpoint is an ancestor of the block + finalized_checkpoint_block = get_checkpoint_block( + store, beacon_block_root, store.finalized_checkpoint.epoch + ) + if finalized_checkpoint_block != store.finalized_checkpoint.root: + raise GossipIgnore("finalized checkpoint is not an ancestor of block") + + # Mark this attestation as seen + seen.attestation_validator_epochs.add((participant_index, target_epoch)) + + +- name: validate_beacon_block_gossip#phase0 + sources: [] + spec: | + + def validate_beacon_block_gossip( + seen: Seen, + store: Store, + state: BeaconState, + signed_beacon_block: SignedBeaconBlock, + current_time_ms: uint64, + ) -> None: + """ + Validate a SignedBeaconBlock for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + block = signed_beacon_block.message + + # [IGNORE] The block is not from a future slot + # (MAY be queued for processing at the appropriate slot) + if not is_not_from_future_slot(state, block.slot, current_time_ms): + raise GossipIgnore("block is from a future slot") + + # [IGNORE] The block is from a slot greater than the latest finalized slot + # (MAY choose to validate and store such blocks for additional purposes + # -- e.g. slashing detection, archive nodes, etc). + finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + if block.slot <= finalized_slot: + raise GossipIgnore("block is not from a slot greater than the latest finalized slot") + + # [IGNORE] The block is the first block with valid signature received for the proposer for the slot + if (block.proposer_index, block.slot) in seen.proposer_slots: + raise GossipIgnore("block is not the first valid block for this proposer and slot") + + # [REJECT] The proposer index is a valid validator index + if block.proposer_index >= len(state.validators): + raise GossipReject("proposer index out of range") + + # [REJECT] The proposer signature is valid + proposer = state.validators[block.proposer_index] + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block.slot)) + signing_root = compute_signing_root(block, domain) + if not bls.Verify(proposer.pubkey, signing_root, signed_beacon_block.signature): + raise GossipReject("invalid proposer signature") + + # [IGNORE] The block's parent has been seen (via gossip or non-gossip sources) + # (MAY be queued until parent is retrieved) + if block.parent_root not in store.blocks: + raise GossipIgnore("block's parent has not been seen") + + # [REJECT] The block's parent passes validation + if block.parent_root not in store.block_states: + raise GossipReject("block's parent failed validation") + + # [REJECT] The block is from a higher slot than its parent + if block.slot <= store.blocks[block.parent_root].slot: + raise GossipReject("block is not from a higher slot than its parent") + + # [REJECT] The current finalized checkpoint is an ancestor of the block + checkpoint_block = get_checkpoint_block( + store, block.parent_root, store.finalized_checkpoint.epoch + ) + if checkpoint_block != store.finalized_checkpoint.root: + raise GossipReject("finalized checkpoint is not an ancestor of block") + + # [REJECT] The block is proposed by the expected proposer for the slot + # (if shuffling is not available, IGNORE instead and MAY be queued for later) + parent_state = store.block_states[block.parent_root].copy() + process_slots(parent_state, block.slot) + expected_proposer = get_beacon_proposer_index(parent_state) + if block.proposer_index != expected_proposer: + raise GossipReject("block proposer_index does not match expected proposer") + + # Mark this block as seen for this proposer/slot combination + seen.proposer_slots.add((block.proposer_index, block.slot)) + + - name: validate_light_client_update#altair sources: [] spec: | @@ -10881,7 +11975,7 @@ - name: validate_on_attestation#gloas sources: [] spec: | - + def validate_on_attestation(store: Store, attestation: Attestation, is_from_block: bool) -> None: target = attestation.data.target @@ -10909,6 +12003,10 @@ assert attestation.data.index in [0, 1] if block_slot == attestation.data.slot: assert attestation.data.index == 0 + # [New in Gloas:EIP7732] + # If attesting for a full node, the payload must be known + if attestation.data.index == 1: + assert attestation.data.beacon_block_root in store.payload_states # LMD vote must be consistent with FFG vote target assert target.root == get_checkpoint_block( @@ -10920,6 +12018,61 @@ assert get_current_slot(store) >= attestation.data.slot + 1 +- name: validate_proposer_slashing_gossip#phase0 + sources: [] + spec: | + + def validate_proposer_slashing_gossip( + seen: Seen, + state: BeaconState, + proposer_slashing: ProposerSlashing, + ) -> None: + """ + Validate a ProposerSlashing for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + header_1 = proposer_slashing.signed_header_1.message + header_2 = proposer_slashing.signed_header_2.message + proposer_index = header_1.proposer_index + + # [IGNORE] The proposer slashing is the first valid proposer slashing received for this proposer + if proposer_index in seen.proposer_slashing_indices: + raise GossipIgnore("already seen proposer slashing for this proposer") + + # [REJECT] The header slots match + if header_1.slot != header_2.slot: + raise GossipReject("header slots do not match") + + # [REJECT] The header proposer indices match + if header_1.proposer_index != header_2.proposer_index: + raise GossipReject("header proposer indices do not match") + + # [REJECT] The headers are different + if header_1 == header_2: + raise GossipReject("headers are not different") + + # [REJECT] The proposer index is valid + if proposer_index >= len(state.validators): + raise GossipReject("proposer index out of range") + + # [REJECT] The proposer is slashable + proposer = state.validators[proposer_index] + if not is_slashable_validator(proposer, get_current_epoch(state)): + raise GossipReject("proposer is not slashable") + + # [REJECT] The signatures are valid + 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) + if not bls.Verify(proposer.pubkey, signing_root, signed_header.signature): + raise GossipReject("invalid proposer slashing signature") + + # Mark this proposer slashing as seen + seen.proposer_slashing_indices.add(proposer_index) + + - name: validate_target_epoch_against_current_time#phase0 sources: [] spec: | @@ -10935,6 +12088,59 @@ assert target.epoch in [current_epoch, previous_epoch] +- name: validate_voluntary_exit_gossip#phase0 + sources: [] + spec: | + + def validate_voluntary_exit_gossip( + seen: Seen, + state: BeaconState, + signed_voluntary_exit: SignedVoluntaryExit, + ) -> None: + """ + Validate a SignedVoluntaryExit for gossip propagation. + Raises GossipIgnore or GossipReject on validation failure. + """ + voluntary_exit = signed_voluntary_exit.message + validator_index = voluntary_exit.validator_index + + # [IGNORE] The voluntary exit is the first valid voluntary exit received for the validator + if validator_index in seen.voluntary_exit_indices: + raise GossipIgnore("already seen voluntary exit for this validator") + + # [REJECT] The validator index is valid + if validator_index >= len(state.validators): + raise GossipReject("validator index out of range") + + validator = state.validators[validator_index] + current_epoch = get_current_epoch(state) + + # [REJECT] The validator is active + if not is_active_validator(validator, current_epoch): + raise GossipReject("validator is not active") + + # [REJECT] The validator has not already initiated exit + if validator.exit_epoch != FAR_FUTURE_EPOCH: + raise GossipReject("validator has already initiated exit") + + # [REJECT] The voluntary exit epoch is not in the future + if current_epoch < voluntary_exit.epoch: + raise GossipReject("voluntary exit epoch is in the future") + + # [REJECT] The validator has been active long enough + if current_epoch < validator.activation_epoch + SHARD_COMMITTEE_PERIOD: + raise GossipReject("validator has not been active long enough") + + # [REJECT] The signature is valid + domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) + signing_root = compute_signing_root(voluntary_exit, domain) + if not bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature): + raise GossipReject("invalid voluntary exit signature") + + # Mark this voluntary exit as seen + seen.voluntary_exit_indices.add(validator_index) + + - name: verify_blob_sidecar_inclusion_proof#deneb sources: - file: consensus-types/blocks/kzg.go @@ -11106,6 +12312,50 @@ return bls.Verify(pubkey, signing_root, signed_envelope.signature) +- name: verify_partial_data_column_header_inclusion_proof#fulu + sources: [] + spec: | + + def verify_partial_data_column_header_inclusion_proof(header: PartialDataColumnHeader) -> bool: + """ + Verify if the given KZG commitments are included in the given beacon block. + """ + return is_valid_merkle_branch( + leaf=hash_tree_root(header.kzg_commitments), + branch=header.kzg_commitments_inclusion_proof, + depth=KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH, + index=get_subtree_index(get_generalized_index(BeaconBlockBody, "blob_kzg_commitments")), + root=header.signed_block_header.message.body_root, + ) + + +- name: verify_partial_data_column_sidecar_kzg_proofs#fulu + sources: [] + spec: | + + def verify_partial_data_column_sidecar_kzg_proofs( + sidecar: PartialDataColumnSidecar, + all_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK], + column_index: ColumnIndex, + ) -> bool: + """ + Verify the KZG proofs. + """ + # Get the blob indices from the bitmap + blob_indices = [i for i, b in enumerate(sidecar.cells_present_bitmap) if b] + + # The cell index is the column index for all cells in this column + cell_indices = [CellIndex(column_index)] * len(blob_indices) + + # Batch verify that the cells match the corresponding commitments and proofs + return verify_cell_kzg_proof_batch( + commitments_bytes=[all_commitments[i] for i in blob_indices], + cell_indices=cell_indices, + cells=sidecar.partial_column, + proofs_bytes=sidecar.kzg_proofs, + ) + + - name: voting_period_start_time#phase0 sources: - file: time/slots/slottime.go diff --git a/specrefs/presets.yml b/specrefs/presets.yml index 9e7938edfd5b..896f79deee6b 100644 --- a/specrefs/presets.yml +++ b/specrefs/presets.yml @@ -192,6 +192,13 @@ INACTIVITY_PENALTY_QUOTIENT_BELLATRIX: uint64 = 16777216 +- name: INCLUSION_LIST_COMMITTEE_SIZE#heze + sources: [] + spec: | + + INCLUSION_LIST_COMMITTEE_SIZE: uint64 = 16 + + - name: KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH#fulu sources: - file: proto/ssz_proto_library.bzl diff --git a/testing/spectest/shared/fulu/ssz_static/ssz_static.go b/testing/spectest/shared/fulu/ssz_static/ssz_static.go index 1175b6174e73..8d3529ce2380 100644 --- a/testing/spectest/shared/fulu/ssz_static/ssz_static.go +++ b/testing/spectest/shared/fulu/ssz_static/ssz_static.go @@ -155,6 +155,8 @@ func UnmarshalledSSZ(t *testing.T, serializedBytes []byte, folderName string) (a obj = ðpb.DataColumnsByRootIdentifier{} case "MatrixEntry": t.Skip("Unused type") + case "PartialDataColumnHeader", "PartialDataColumnPartsMetadata", "PartialDataColumnSidecar": + t.Skip("Not yet implemented") default: return nil, errors.New("type not found") } diff --git a/testing/spectest/shared/gloas/ssz_static/ssz_static.go b/testing/spectest/shared/gloas/ssz_static/ssz_static.go index 35fbbe7725fb..5fe3b0ea581d 100644 --- a/testing/spectest/shared/gloas/ssz_static/ssz_static.go +++ b/testing/spectest/shared/gloas/ssz_static/ssz_static.go @@ -187,6 +187,8 @@ func unmarshalledSSZ(t *testing.T, serializedBytes []byte, folderName string) (a obj = ðpb.DataColumnsByRootIdentifier{} case "MatrixEntry": t.Skip("Unused type") + case "PartialDataColumnHeader", "PartialDataColumnPartsMetadata", "PartialDataColumnSidecar": + t.Skip("Not yet implemented") default: return nil, errors.New("type not found") } diff --git a/testing/util/BUILD.bazel b/testing/util/BUILD.bazel index 01f7756ba267..2d9af46877ca 100644 --- a/testing/util/BUILD.bazel +++ b/testing/util/BUILD.bazel @@ -23,6 +23,7 @@ go_library( "fulu.go", "fulu_block.go", "fulu_state.go", + "gloas_state.go", "helpers.go", "lightclient.go", "logging.go", @@ -39,6 +40,7 @@ go_library( "//beacon-chain/blockchain/kzg:go_default_library", "//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/blocks:go_default_library", + "//beacon-chain/core/gloas:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/peerdas:go_default_library", "//beacon-chain/core/signing:go_default_library", diff --git a/testing/util/gloas_state.go b/testing/util/gloas_state.go new file mode 100644 index 000000000000..c431235ba3ff --- /dev/null +++ b/testing/util/gloas_state.go @@ -0,0 +1,24 @@ +package util + +import ( + "testing" + + "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" + "github.com/OffchainLabs/prysm/v7/beacon-chain/state" + "github.com/OffchainLabs/prysm/v7/crypto/bls" + "github.com/pkg/errors" +) + +// DeterministicGenesisStateGloas returns a genesis state in Gloas format made +// using the deterministic deposits. +func DeterministicGenesisStateGloas(t testing.TB, numValidators uint64) (state.BeaconState, []bls.SecretKey) { + t.Helper() + + fuluState, privKeys := DeterministicGenesisStateFulu(t, numValidators) + beaconState, err := gloas.UpgradeToGloas(fuluState) + if err != nil { + t.Fatal(errors.Wrapf(err, "failed to upgrade genesis beacon state of %d validators to gloas", numValidators)) + } + resetCache() + return beaconState, privKeys +} diff --git a/testing/util/state.go b/testing/util/state.go index 69daf54e5124..6f4a58c64d2b 100644 --- a/testing/util/state.go +++ b/testing/util/state.go @@ -12,6 +12,7 @@ import ( state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native" fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams" "github.com/OffchainLabs/prysm/v7/config/params" + "github.com/OffchainLabs/prysm/v7/consensus-types/primitives" "github.com/OffchainLabs/prysm/v7/crypto/bls" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" @@ -526,6 +527,13 @@ func NewBeaconStateGloas(options ...func(state *ethpb.BeaconStateGloas) error) ( } } + ptcWindow := make([]*ethpb.PTCs, 3*params.BeaconConfig().SlotsPerEpoch) + for i := range ptcWindow { + ptcWindow[i] = ðpb.PTCs{ + ValidatorIndices: make([]primitives.ValidatorIndex, fieldparams.PTCSize), + } + } + seed := ðpb.BeaconStateGloas{ BlockRoots: filledByteSlice2D(uint64(params.BeaconConfig().SlotsPerHistoricalRoot), 32), StateRoots: filledByteSlice2D(uint64(params.BeaconConfig().SlotsPerHistoricalRoot), 32), @@ -572,6 +580,7 @@ func NewBeaconStateGloas(options ...func(state *ethpb.BeaconStateGloas) error) ( BuilderPendingWithdrawals: make([]*ethpb.BuilderPendingWithdrawal, 0), LatestBlockHash: make([]byte, 32), PayloadExpectedWithdrawals: make([]*enginev1.Withdrawal, 0), + PtcWindow: ptcWindow, } for _, opt := range options {