Skip to content

explorer: fix stale per-element state and ignored adj in /blocks - #2079

Open
Maxnflaxl wants to merge 1 commit into
masterfrom
issue/2077-2078
Open

explorer: fix stale per-element state and ignored adj in /blocks#2079
Maxnflaxl wants to merge 1 commit into
masterfrom
issue/2077-2078

Conversation

@Maxnflaxl

@Maxnflaxl Maxnflaxl commented Aug 18, 2026

Copy link
Copy Markdown
Member

Summary

Two bugs in the explorer's /blocks (plural) endpoint, reported by @dbadol as #2077 and #2078. Both live in Adapter::get_blocks, so they're fixed together.

#2077 — every element carries the first block's header

Regression from ba181a9, which replaced the old per-row get_block_impl() walk with a StateID/m_Number loop. The loop advances the row but never reloads the state for it, so every element after the first is rendered against the first block's Block::SystemState::Full:

sid.m_Number.v++;
sid.m_Row = _nodeBackend.FindActiveAtStrict(sid.m_Number);   // `s` left stale

Because the body is read from sid.m_Row (correct) while the header and context come from s (stale), the damage is wider than the report: on top of h and info, the totals table (Chainwork, Current Emission, Current Circulation, Size Compressed, Size Archive) and outputs[].Maturity are all wrong. Verified against mainnet — for block 27730 in a height=27729&n=4 series, emission reads 2,218,320 instead of 2,218,400 and the coinbase maturity 27969 instead of 27970. inputs and kernels were the only correct sections.

Fixed by reloading the state after each step.

#2078adj is ignored

adj simply never reached the backend: on_request_blocks parsed only height and n, and get_blocks had no adj parameter. What looked like "defaults to adj=1" was FindBlockByHeightFindAtivePastHeight snapping to the next active height unconditionally, which also meant /blocks had no not-found path at all.

Fixed per the three points in the issue:

  1. adj is parsed and passed through, and applies to the first block of the series only; the rest always follow upwards.
  2. A vacant height with no adj returns {"found":false,"height":N}, matching /block.
  3. Once the walk passes the tip, the remaining elements are filled with the same not-found objects, so the array always has n entries.

To keep /block and /blocks from drifting apart again, the first-block resolution is now shared: get_block's logic is factored into ResolveBlock(sid, s, h, height, adj) and both endpoints call it.

Changes

  • explorer/server.cppon_request_blocks parses adj and passes it on.
  • explorer/adapter.hget_blocks(Height, uint64_t, int adj).
  • explorer/adapter.cpp — new ResolveBlock helper shared with get_block; get_blocks refreshes the state per element, honors adj for the first block, and emits not-found placeholders.

Behavior

Request (dappnet2, PoS with gaps) Before After
blocks?height=2743&n=4 4 blocks, all with 2743's header 4 blocks, own headers
blocks?height=2742&n=4 (vacant) series from 2743 [{"found":false,"height":2742}]
blocks?height=2742&n=4&adj=1 series from 2743 series from 2743
blocks?height=2744&n=4&adj=-1 series from 2795 ❌ series from 2743 ✅
series running past the tip short array, empty blocks n entries, tail is found:false

Two judgement calls worth a look, since the spec is ambiguous for PoS chains:

  • Point 2 returns a one-element array rather than a bare object, to keep /blocks type-stable for clients. Easy to change if the bare object is preferred.
  • The placeholder heights past the tip are consecutive (tip+1, tip+2, …), which only carries meaning on PoW. On a PoS chain with gaps they should be read as "no block here", not as a height prediction.

Closes #2077
Closes #2078

@Maxnflaxl
Maxnflaxl requested a review from valdok August 18, 2026 09:58
@Maxnflaxl Maxnflaxl changed the title explorer: fix stale per-element state and ignored adj in /blocks explorer: fix /blocks per-element state and adj; consensus: pbft cfg checksum Aug 18, 2026
@Maxnflaxl
Maxnflaxl marked this pull request as draft August 25, 2026 21:16
@Maxnflaxl Maxnflaxl changed the title explorer: fix /blocks per-element state and adj; consensus: pbft cfg checksum explorer: fix stale per-element state and ignored adj in /blocks Aug 27, 2026
@Maxnflaxl
Maxnflaxl marked this pull request as ready for review August 27, 2026 21:12
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.

Explorer node: Parameter adj is ignored in queries of type blocks Explorer node: Wrong info in queries with type 'blocks'

1 participant