Update state transition for spec v1.7.0-alpha.14 - #841
Conversation
There was a problem hiding this comment.
This PR ports the two functional state-transition changes from consensus-specs alpha.13 to alpha.14: upgrade_to_gloas now seeds the full latest_execution_payload_bid (parent_block_hash/parent_block_root/prev_randao/slot and BUILDER_INDEX_SELF_BUILD), and process_attestation gates builder payment weight on had_no_participation. I verified both functions field-by-field against the alpha.14 spec text, confirmed every newly-set bid field exists on the go-eth2-client types and reaches the state HTR via the all.ExecutionPayloadBid wrapper, and traced the fork-upgrade timing and the downstream consumer. The changes match the spec exactly with no regressions found.
Reviewed 3 changed file(s) @ 157c3d4f — no blocking issues found.
"Weeks of coding can save you hours of planning."
SummaryBumps the Gloas state transition to consensus-specs v1.7.0-alpha.14: upgrade_to_gloas now seeds the full latest_execution_payload_bid (verified field-by-field against the alpha.14 fork.md, including BUILDER_INDEX_SELF_BUILD), process_attestation gains the had_no_participation gate exactly as the spec has it, and db/slots.go drops a dead assignment. The two functional changes the description claims are both correct — but the description is incomplete: alpha.14 also changed upgrade_to_gloas to seed builder_pending_payments empty, which this PR leaves at alpha.13's 2*SLOTS_PER_EPOCH entries. Issues
Reviewed @ |
This finding is incorrect — no change needed. BuilderPendingPayments is a fixed-length SSZ Vector, not a list. From alpha.14 gloas/beacon-chain.md: class BuilderPendingPayments(Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH]): BuilderPendingPayments() is therefore the Vector's default value: 2 * SLOTS_PER_EPOCH default-constructed elements — not an empty list. Verified empirically against remerkleable (the library pyspec uses): alpha.13 form: len 64, root 87eb0ddba57e35f6 Three independent cross-checks agree:
The same pattern appears elsewhere in the alpha.14 diff and is likewise non-functional: heze/fork.md swaps BitVectorINCLUSION_LIST_COMMITTEE_SIZE for InclusionListBits(). By contrast electra/fork.md's pending_deposits=PendingDeposits() is an empty list — because that alias wraps a List, not a Vector. The distinction is the alias's base type, which is why the two-functional-changes count in the PR description holds. |
Upgrades the state transition in
indexer/beacon/statetransition/from consensus-specsv1.7.0-alpha.13tov1.7.0-alpha.14.Spec delta
The raw
alpha.13 → alpha.14diff is ~5,900 lines, but nearly all of it is cosmetic: the spec now declares named SSZ type aliases (Balances,Withdrawals,PTC,PTCWindow,ProposerIndices, …) and containers reference those instead of inlineProgressiveList[…]/Vector[…]. Diffing the spec's Python blocks function-by-function across every fork shows phase0 through fulu have zero functional changes.Only two changes affect the state transition, both Gloas.
1.
upgrade_to_gloaspopulates the fulllatest_execution_payload_bidPreviously only
block_hash,gas_limitandexecution_requests_rootwere seeded. alpha.14 also setsparent_block_hash(from the pre-state payload header),parent_block_rootandslot(frompre.latest_block_header),prev_randao, andbuilder_index = BUILDER_INDEX_SELF_BUILD.This changes the post-fork state root, so it is required for correct replay across the Gloas fork boundary. Adds a
BuilderIndexSelfBuildconstant (UINT64_MAX).2. Gloas
process_attestationgains thehad_no_participationgateBuilder payment weight now also requires that the validator held no participation flags for that epoch before the attestation was applied. alpha.13's
will_set_new_flagcheck alone was insufficient: when two aggregates for the same slot each set a different new flag, the validator's effective balance was added to the payment weight twice.Not covered here (non-STF)
GAS_LIMIT_SCHEDULEconfig andget_scheduled_gas_limit— block-building only, no state effect.MAX_BYTES_PER_INCLUSION_LIST→MAX_TRANSACTIONS_BYTES_PER_INCLUSION_LIST— not referenced by dora.InclusionList.inclusion_list_committee_root→dependent_root— needs ago-eth2-clientrename first, thenhandlers/slot.goandhandlers/api/slot_inclusion_lists_v1.gofollow. SSZ shape is unchanged (Root→Root), so nothing breaks in the meantime.Verification
all.ExecutionPayloadBidwrapper — each field independently changes the root, and nil vs. emptyblob_kzg_commitmentshash identically.process_payload_attestationmutates no state,can_builder_cover_bid, the two signature verifiers), which is consistent with replaying canonical blocks.process_execution_payload_bidagainst alpha.14 — state effects match (dora readss.Slot/block.ProposerIndexwhere the spec readsbid.slot/get_beacon_proposer_index, equivalent under the spec's own asserts).go build,go vet,gofmtandgo test ./indexer/beacon/...all clean.glamsterdam-devnet-8(alpha.14, slots 45601–45617): every state root matched.Known gap
The new
upgrade_to_gloasbid has not been validated against a real post-fork state root yet.devnet-7is still on alpha.13;glamsterdam-devnet-8is on alpha.14 but itsGLOAS_FORK_EPOCHis 1536 and head was around epoch 1425 at the time of writing. The definitive check is to replay devnet-8 across slot 49152 withcmd/statetransition-testonce it forks.