Skip to content

chain-serve pagination: EncodeBlocksUpTo + design (working-set fix — PE approach-review before the async loop) - #466

Open
nerolabs wants to merge 1 commit into
mainfrom
fix/paginate-chain-sync
Open

chain-serve pagination: EncodeBlocksUpTo + design (working-set fix — PE approach-review before the async loop)#466
nerolabs wants to merge 1 commit into
mainfrom
fix/paginate-chain-sync

Conversation

@nerolabs

Copy link
Copy Markdown
Owner

The chain-serve OOM driver (heap-profiled): a node serving MsgGetChain{Height:0} marshals its whole bond-reg-laden chain into ONE buffer (chain.EncodeBlocks = 144 MB LIVE). This bounds it.

What's here (safe, tested, groundwork)

  • chain.EncodeBlocksUpTo(blocks, maxBytes) — encodes the longest prefix fitting a byte cap (always ≥1; sizes blocks one at a time so it never marshals more than the returned window). Bounds the serve buffer instead of the whole chain.
  • Tests: TestEncodeBlocksUpToBoundsTheWindow (bounded prefix / oversize / legacy) + TestWindowedReassemblyEqualsFullChain (successive windows rebuild the exact chain — the requester-loop logic pinned deterministically, without the async wiring).

Deliberately NOT here — flagged for PE approach-review first

The async requester loop (fetchFull windowed fetch) + the handler wiring is the delicate sync-correctness change. Safety hinge (verified): Reconcile validates full block linkage (ErrWrongParent), so a windowed reassembly that splices inconsistent windows fails closed — pagination cannot corrupt the chain. But the atomic server+requester rollout (mixed-fleet) is a design question.

3 questions for PE (in the design doc — docs/thinking/2026-08-18-paginate-chain-sync-design.md):

  1. maxChainReplyBytes = 8 MiB — endorse or derive from network-durability?
  2. Atomic server+requester rollout vs. a capability-negotiation fallback for old peers?
  3. Is bounding the SERVE spike (not the requester's reassembled chain — that's retention/Bond proof reply is ~1.5 MB — loss-sensitivity (#289 leg-b) + N² bandwidth cost; succinct-proof is the structural close #299) the right PR scope? (I believe yes — it's the observed 144 MB driver.)

This is the interim memory fix; #299 succinct proofs is the structural win that makes it (and pruning) minor. Scope + safety + failure-modes + test plan in the design doc.

🤖 Generated with Claude Code

…in sync (working-set fix)

The chain-serve OOM driver: a node serving MsgGetChain{Height:0} marshals its WHOLE
bond-reg-laden chain into ONE buffer (chain.EncodeBlocks = 144MB LIVE, heap-profiled).
EncodeBlocksUpTo encodes the longest PREFIX that fits a byte cap (always >=1; sizing
blocks one at a time so it never marshals more than the returned window) — bounding the
serve buffer instead of the whole chain. A syncing peer requests successive windows and
reassembles; Reconcile validates the reassembled linkage (ErrWrongParent), so a windowed
fetch CANNOT corrupt the chain (verified — this is why it's tractable).

Tests: TestEncodeBlocksUpToBoundsTheWindow (bounded prefix, >=1 on oversize, legacy
whole-chain at maxBytes<=0) + TestWindowedReassemblyEqualsFullChain (successive windows
rebuild the exact chain across multiple round-trips — the requester-loop logic pinned
deterministically, without the async wiring).

The DELICATE half — wiring the MsgGetChain handler + the async fetchFull window-loop — is
flagged for PE sign-off on the approach FIRST (sync-correctness path; the atomic
server+requester rollout / mixed-fleet question). Design + safety argument + PE questions:
docs/thinking/2026-08-18-paginate-chain-sync-design.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqsAc2sNZY7Pg3VgCUKm2P
@netlify

netlify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Deploy Preview for kaleidoscopic-pegasus-e9fec4 ready!

Name Link
🔨 Latest commit d8e9c01
🔍 Latest deploy log https://app.netlify.com/projects/kaleidoscopic-pegasus-e9fec4/deploys/6a84325f6b9efe0008b56d81
😎 Deploy Preview https://deploy-preview-466--kaleidoscopic-pegasus-e9fec4.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@nerolabs

Copy link
Copy Markdown
Owner Author

Triage 2026-08-19 (post D-M1-PIVOT): kept open — NOT superseded by #470. Checked against main: the serve handler still encodes the whole requested suffix in one buffer (chain.EncodeBlocks at core/node/chainrole.go:411). #470's suffix-sync + rolling retention bound the request pattern (a behind peer asks from its floor height, and the horizon bounds worst-case chain length), which shrinks the typical serve — but the serve-side byte-cap this PR adds (EncodeBlocksUpTo) is still the only bound on a single reply's transient buffer for a deeply-behind peer inside the horizon.

Status unchanged: awaiting PE approach-review before the requester loop lands (per the design doc's own guardrail). Roadmap placement: Phase 3-adjacent (cheap heights shrink the same per-height cost from the other side). Will need a mechanical rebase when picked up (main is at dd19203; the PR's chain.go addition is additive, so conflicts should be minimal).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant