Repository navigation
feat(rpc): serve GET /eth/v2/validator/duties/proposer/{epoch} - #660
MegaRedHand wants to merge 6 commits into
Conversation
…eposit_contract and POST /eth/v1/validator/duties/sync/{epoch} from ethlambda beacon, three of the four Beacon API endpoints validator clients call that were missing. fork returns the state's own Fork through the same state_id resolution as the other state endpoints, so a state root is the same 404. deposit_contract returns the Config's deposit chain id and contract address. duties/sync reads the head state's current_sync_committee for an epoch in the head's own sync committee period and next_sync_committee for the next one, matches each requested validator by pubkey and returns every seat it holds (the committee is drawn with replacement), leaves out validators with no seat, and answers 400 for an unknown index or any other period and 503 while syncing. An earlier period is refused rather than answered from a historical state, recorded in docs/spec_deviations.md. compute_sync_committee_period is added to the altair helpers as validator.md defines it.
beacon-APIs #563 deprecates the v1 endpoint in favour of v2, which differs only in `dependent_root`: the block before the previous epoch rather than the block before the epoch. That is the block fulu's proposer lookahead actually depends on, since an epoch's proposers are written by the epoch transition into the epoch before it. v1's later root changes on reorgs that leave the duties untouched, so a validator client watching it refetches for nothing. Both versions share one handler body, parameterised by the dependent slot. Attester duties already used v2's formula and now share its helper.
🤖 Kimi Code ReviewI'll review this PR which adds v2 proposer duties endpoint support to ethlambda's Beacon API. Overall AssessmentThis is a well-structured, focused PR that correctly implements the Beacon API v2 proposer duties specification. The refactoring to share logic between v1 and v2 is clean. I found one minor correctness issue in test code and several code quality suggestions. Issues Found1. Test Bug: Potential Underflow in
|
| Priority | Item | Location |
|---|---|---|
| Fix | Test underflow: epoch - 1 → epoch.saturating_sub(1) |
validator.rs:681 |
| Fix | Grammar in doc comment | validator.rs:338 |
| Suggest | Add v2 epoch 0 test case | validator.rs tests |
| — | All other code is correct and well-structured | — |
Automated review by Kimi (Moonshot AI) · kimi-k2.6 · custom prompt
🤖 Claude Code ReviewReview:
|
🤖 Codex Code ReviewLooks good overall. The change is narrowly scoped, aligns with the Beacon API v2 proposer-duties semantics, and reuses the existing duty computation cleanly.
One small test nit:
No blockchain-security or memory-safety concerns jump out in this diff. Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
a7f7f83 to
b252fbc
Compare
…poser-duties-v2 #642 was squashed onto the current beacon-chain-integration, so this merge ran against the old base and both sides re-added #642's work. Git kept the `duties/sync` test module twice; the second copy is dropped. In docs/rpc.md the duties paragraph keeps this branch's `dependent_root` wording.
…3-636-638-gloas-live # Conflicts: # docs/rpc.md
…36-638-gloas-live Brings gloas validator duties (produceBlockV4, envelope publication, PTC duties and payload attestations, gloas attestation data and aggregates, VC gloas support) onto the deployment branch, keeping every behavior of #626, #633, #636, #638, #646, #647-#652, #656, #658-#660 and the sync-committee and liveness endpoints. Conflict resolutions keep both sides: the attestation pool stays in Store (tmp) while the payload attestation pool is threaded through P2P and the RPC handles (feature); the aggregate endpoints keep tmp's liveness recording and attesting indices and add the feature's fork-header check and gloas pooling; the VC tests and fake execution client serve both fulu blobs and gloas V6. Semantic fixes: a. POST /eth/v2/beacon/blocks (gloas) calls publish_beacon_block(block, Vec::new()): gloas columns travel with the envelope. RecordingNetwork implements publish_beacon_block(block, sidecars) and both new methods. b. produceBlockV4 appends client versions to the graffiti exactly like produceBlockV3 (graffiti::execution_client_version run alongside the payload build, with_client_versions, Extension<OwnVersion>) and logs it. c. Attestation data, aggregate_attestation keep require_execution_client and require_validated for gloas slots; payload_attestation_data now applies the same two rules (503 without an execution client, or when the voted block's payload is unvalidated). d. Proposer duties v1 and v2 serve gloas epochs from a fulu or gloas state's proposer_lookahead; nothing refuses gloas any more; v2 keeps its dependent root. e. The VC's per-validator ProposerSettings apply to gloas proposals (graffiti in the BlockRequest, fee recipient compared with the bid's); a test pins the graffiti. VC tests updated to the ProposerSettings constructors. f. gloas production reads the attestation pool from Store and calls the stf with the ActiveBalanceCache the perf work added; fulu production and pack_operations are untouched (gloas blocks carry no pooled operations). g. Chain events are emitted by the chain actor only, so nothing on the RPC publish paths needed to move; gloas imports reach it unchanged. h. Cargo.lock unchanged; cargo check --locked passes.
|
Already included in #653 |
…63-64-633-636-638-gloas-live" This reverts merge 1fef238, keeping its first parent's side. #653 serves v2 proposer duties too, through its own handler, so tmp takes that one instead of carrying both. #662 had since taught proposer_duties to read a gloas head's lookahead; that stays, only the dependent-slot parameter, the v2 route and its test go.
…653 line #663 landed on tmp while #660 was being reverted here, and was written against #660's v2 helpers. The merge keeps #663's wall-clock bound, head advance and blocking thread, with #653's DependentRoot in place of #660's last_slot_before helpers and #653's 503-while-syncing v2 handler. The lookahead paragraph moves from the v1 handler's doc to proposer_duties, as #663 has it. The tests' get helper now layers a default SyncStatusController, as the production router always does: #663's v2 assertions went through routes() without it, which #653's v2 handler answers with a 500.
Stacked on #642.
Motivation
beacon-APIs #563 added
GET /eth/v2/validator/duties/proposer/{epoch}and deprecated v1. The two return the same duties. They differ only independent_root:compute_start_slot_at_epoch(E) - 1compute_start_slot_at_epoch(E - 1) - 1, genesis on underflowv2's slot is the one fulu's
proposer_lookaheaddepends on.process_proposer_lookaheadwrites epoch E's proposers during the transition into E-1. v1's later root also changes on reorgs inside E-1, which leave the duties as they were, so a validator client watching it refetches for nothing.Changes
/eth/v2/validator/duties/proposer/{epoch}. v1 and v2 share oneproposer_dutiesbody, which takes the dependent slot as a function argument.last_slot_before/last_slot_before_previoushelpers. Attester duties already used v2's formula and now call the shared helper.docs/rpc.md: a table row for v2, v1 marked as deprecated by the spec, and thedependent_rootnote rewritten for each endpoint.Not in this PR
ethlambda validatorstill fetches v1.head_v2events'current_epoch_dependent_root/next_epoch_dependent_root. The events endpoint (feat(beacon): serve the Beacon API eventstream, GET /eth/v1/events #626) doesn't emit those yet.Testing
v2_dependent_root_is_the_block_before_the_previous_epoch: for both lookahead epochs, v2'sdataequals v1's, and itsdependent_rootmatches the spec slot and differs from v1's. The head's epoch is 1, so this test also covers the underflow-to-genesis case.an_epoch_outside_the_lookahead_is_a_400now covers both versions.cargo test -p ethlambda-rpc --lib -- beacon::validator: 25 passed.cargo clippy -p ethlambda-rpc --all-targets -D warningsis clean.