From 962616436380120d78e419fedc752d722133e1e1 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 25 Jun 2026 00:27:39 -0600 Subject: [PATCH] feat(state): stitch tree_aux root serving across the vct upgrade height Record a one-time `vct_upgrade_height` marker `U` (the lowest height this binary commits, and the lowest height in the `commitment_roots_by_height` serving index) in a new `vct_upgrade_metadata` column family. Written once on the first committed block and never moved. Root serving (`ReadRequest::BlockRoots`) now stitches the per-height trees below `U` with the serving index at and above `U`, so a node that upgraded mid-chain serves a range crossing `U` as one gap-free batch instead of the short index-only prefix that stalled the fetch client's minimum-progress check. A pre-index archive node (no `U`) still derives the whole range from the trees. Historical note-commitment tree availability is now the band `[U, H)` (H = checkpoint handoff) via a new `vct_tree_absent` helper: trees are present below `U` (pre-upgrade) and at/above `H` (semantic sync), absent only in between. For a genesis fast-sync (`U = 0`) this reduces exactly to the prior `height < H` behaviour. --- zebra-state/src/service.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 4894c05f1ca..48965d418b5 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -1554,10 +1554,12 @@ impl Service for ReadStateService { start_height, count, } => { - // Serve stitched committed verified roots first, then provisional - // header-ahead roots for heights that have headers but no committed - // body yet. Committed roots win for overlapping heights because - // they have already been verified during block commit. + // Serve stitched committed verified roots first, then provisional header-ahead + // roots for heights that have headers but no committed body yet. Committed roots + // come from the compact `commitment_roots_by_height` index, with + // `serve_block_roots` filling pre-upgrade gaps from per-height trees when needed. + // They win for overlapping heights because they have already been verified during + // block commit. let roots = if count == 0 { Vec::new() } else if let Some((tip, _hash)) = state.db.best_header_tip() {