feat(api): restore /lean/v0/blocks/finalized for checkpoint-sync anchor block#974
Open
MegaRedHand wants to merge 2 commits into
Open
feat(api): restore /lean/v0/blocks/finalized for checkpoint-sync anchor block#974MegaRedHand wants to merge 2 commits into
MegaRedHand wants to merge 2 commits into
Conversation
…or block PR leanEthereum#713 added this endpoint so a checkpoint-syncing peer can fetch the (state, signed block) anchor pair. PR leanEthereum#751 removed it as dead code because it has no callers inside this repository. The callers are external: the hive lean simulator gates every checkpoint-sync scenario on this endpoint, and client implementations serve it for interop. Since the removal shipped, all hive checkpoint-sync-based reqresp tests fail for every client with a permanent 404 from the helper node. Restores the endpoint and the injectable signed-block source on the API server, since the fork-choice store only retains unsigned blocks. The handler and field docstrings now name the external consumers so the next dead-code sweep has the missing context.
The anchor builder previously rebuilt the anchor block from the header embedded in the state with an empty body. The anchor root is the hash of the full block, so whenever the finalized block carried attestations the rebuilt root diverged from the finalized root the rest of the network agrees on. This is the gap issue leanEthereum#712 originally described. Fetch the real signed block from the finalized block endpoint and anchor the store on it. The block is fetched before the state: it is small, so a source that cannot serve it fails fast before the multi-megabyte state download starts. A block that does not pair with the fetched state raises, since that means the source advanced finalization between the two requests and a retry is the fix. This also gives the restored endpoint an in-repo production caller.
b1b6491 to
5a8e346
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Restores the
/lean/v0/blocks/finalizedendpoint that #713 introduced and #751 removed as dead code, and makes the node's checkpoint-sync client consume it.The endpoint's consumers were external, which is why the dead-code sweep missed them:
signed_block_getterparameter onApiServer(lean_spec_client_runner.py) and its readiness probe polls/lean/v0/blocks/finalized(helper.rs). Since refactor: dead-code sweep in sync / api / storage subspecs #751 shipped, the probe 404s forever and all checkpoint-sync-based reqresp tests fail for every client on hive.leanroadmap.org: 17 of 21 tests per client in the latest reqresp run. These failures are easy to miss in the UI, since they happen during setup, before the client-under-test starts, so they disappear from per-client filtered views.Commit 1: restore the endpoint (server side)
node/api/endpoints/blocks.py: the finalized signed-block handler, re-added in the currentnode/apistructure (it previously lived undersubspecs/api).node/api/routes.py: route entry.node/api/server.py: optionalsigned_block_getterfield onApiServer, exposed to handlers. The fork-choice store retains only unsigned blocks, so the embedding node injects the signed-block source; the endpoint returns 503 when unset. This matches the original feat(api,sync): add /lean/v0/blocks/finalized for checkpoint-sync anchor block #713 design and hive's feature detection.Commit 2: consume it during checkpoint sync (client side)
Anchor.from_checkpointpreviously rebuilt the anchor block fromstate.latest_block_headerwith an empty body.create_storekeys the head, the checkpoints, and the block map byhash_tree_root(anchor_block), so whenever the finalized block carried attestations the rebuilt anchor root diverged from the finalized root the rest of the network agrees on. This is the gap #712 originally described.The new flow, replacing the header reconstruction entirely:
/lean/v0/blocks/finalized. The block is fetched first because it is small: a source that cannot serve it (503/404) aborts checkpoint sync before the multi-megabyte state download starts./lean/v0/states/finalizedand run the existing structural and genesis-time checks.block.state_root == hash_tree_root(state). A mismatch raises, since it means the source advanced finalization between the two requests and a retry is the fix.create_store(state, block), now keyed by the network's true finalized root.Tests
tests/api/endpoints/test_blocks.py: contract tests (200, content type, SSZ round-trip, block state-root matches the finalized state's hash tree root).tests/node/api/test_server.py: 503 without store, 503 without signed-block source, 404 when the source has no block, 200 + anchor-root match.tests/node/sync/test_checkpoint_sync.py: transport/HTTP/corrupt-SSZ error wrapping for the block fetch, plus a live-server round-trip and the 503 path.tests/node/test_anchor.py: anchor keyed by the fetched block's root, abort on block-fetch failure, abort on state-fetch failure, raise on state/block pairing mismatch.tests/api/conftest.py: the conformance server now wires a signed-block source that wraps the store's anchor block with an empty proof.just check,just deadcode, and the node/cli/integration/api test trees are green.