fix(light-client): bound leaf proof construction to prevent OOM#4716
Conversation
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
|
Claude finished @bfish713's task in 2m 58s —— View job Code ReviewI reviewed the full diff against 1. The core fallback path (
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Successfully created backport PR for |
…n to prevent OOM (#4718) fix(light-client): bound leaf proof construction to prevent OOM (#4716) * limit range of leaf requests * send smallest proof possible * comments * test(light-client): distant hint falls through to bounded proof --------- (cherry picked from commit 8682dc5) Co-authored-by: Brendon Fish <bfish713@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Abdul Basit <45506001+imabdulbasit@users.noreply.github.com>
Problem
Restarting a wiped archival query node on the new-protocol devnet OOM'd every other query node. The wiped node's backfill requests leaf proofs with a
finalizedhint far from the requested leaf (its only cached anchor is near the tip), and for leaves with version >= 0.6LeafProof::pushcan never terminate a chain — both of its chain-detection branches require pre-0.6 versions. Each serving node therefore materialized the entire leaf chain from the requested height to the hint (~600k leaves on the devnet) in memory per request, and the light client's 300ms no-cancel fallback fanned the same request out to every peer.Fix
Server (
crates/espresso/node/src/api/light_client.rs):get_leaf_proofrouting function shared by the tide-disco endpoint and the axum/v1 API: a nearbyfinalizedhint keeps the cheap assumption path; a distant hint falls through to a bounded cert2/QC-chain proof instead of walking an unbounded range, so old clients that send far hints keep working.leaf_proof_chain_limit(default 500, matchingsmall_object_range_limit): the QC-chain walk fails with 404 rather than walking to the tip, the cert2 path refuses a cert2 further than the limit, and the assumption path rejects hints beyond the limit with 400.complete_proof_with_cert2: when a QC-chain walk crosses into v0.6 leaves, it completes the proof with the nearest cert2 instead of walking forever.get_leaf_proof_with_cert2now delegates to it.Client (
light-client/src/state.rs):fetch_leafonly sends the cached upper bound as thefinalizedhint when it is within 500 blocks of the requested leaf. This also protects peers still running old server code: without the distant hint, an unpatched server takes the cert2 path, which is naturally short.Docs (
light-client.toml): document the proof-size bound, the distant-hint fallback, and the previously-undocumentedNewProtocolproof variant.Testing
api::light_client: cert2 walk bounded and refused when cert2 is too far, QC-chain walk bounded, distant hint rejected at function level, and a chain crossing the v0.6 cutover with non-consecutive views terminating via cert2 (the shape that OOM'd the devnet).test_fetch_leaf_distant_upper_boundverifies a distant cached anchor is not sent as the hint, against aTestClientthat rejects distant hints like a patched server.api::light_clienttests and 84 light-client tests pass. The 5client::testTestNetwork tests are flaky when run concurrently, but fail identically onmainand pass individually with these changes.Reviewer focus
complete_proof_with_cert2— the interplay withLeafProof::pushat the protocol cutover boundary (push may legitimately complete a HotStuff2 chain, in which case the cert2 is not attached), and theremainingbudget threading inget_leaf_proof_with_qc_chain.Follow-up (not in this PR)
FallbackClient's 300ms no-cancel fan-out still lands one slow request on every peer; a longer delay or cancellation would reduce redundant load during mass backfill.🤖 Generated with Claude Code