2518 - Importer Cursor Pagination - #2626
Conversation
PR Reviewer Guide 🔍(Review updated until commit bae6dfb)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to bae6dfb
Previous suggestionsSuggestions up to commit 681c886
|
There was a problem hiding this comment.
Summary
Great change set. The pagination design is cohesive across server slicing (ImporterPagination), client reassembly (PaginatedPageFetcher + reducers), and domain validation (ExternalBlock transaction merge helpers). I reviewed for correctness/safety around partial data assembly, cursor integrity, and mismatch detection; the implementation has strong defensive checks (stable total, block identity/hash checks, duplicate state-change guards, and not-found-after-partial failure behavior).
Test coverage is substantial and targeted at failure modes that matter for importer safety (cursor parsing, bounds handling, multi-section slicing, mismatch/error paths, and reducer finalization). I did not find any concrete blocking issues in the provided diff/context.
There was a problem hiding this comment.
Summary
Solid implementation of cursor pagination across server and importer sides, with strong defensive checks for consistency (stable totals, block identity/hash continuity, duplicate change detection, and partial-not-found failure). The generic paginator/fetcher abstractions are coherent, and test coverage is meaningful across happy paths and important failure modes.
I did not find any concrete blocking issues in the provided diff/context.
ok, will do it |
|
Also would be good to understand the behavior if say, a follower is deployed with this new feature, but leader does not have it yet. Is that follower prepared to deal with that? |
There was a problem hiding this comment.
Summary
Nice progress on introducing generic cursor pagination and importer-side reassembly; the reducer validation and tests are generally strong. I found one blocking deployment-safety issue related to mixed-version leader/follower compatibility.
Blocking
- The importer client now always calls
stratus_getBlockAndReceipts/stratus_getBlockWithChangeswith a second pagination param and expects paginated response shapes. If follower is upgraded before leader (raised in PR discussion), older leaders that only support legacy signatures/tuple responses can fail decode or reject params, causing importer sync interruption during rollout.
Please add backward compatibility in the client fetch path (e.g., fallback to legacy one-param call and legacy response decode when paginated call fails with method/params/shape mismatch), or gate pagination usage behind a config/feature flag for staged deploys.
Other than that, coverage and invariants look good.
currently old follower -> new leader works fine. But old leader <- new follower it will not work, because the follower at this version always send the request expecting a paginated response. |
There was a problem hiding this comment.
Summary
Solid implementation overall: pagination reducers, cursor decoding, reassembly invariants, and test coverage are strong. However, there is one blocking deploy-safety issue still present in the importer client path.
Blocking
The follower importer now always sends the paginated 2-param RPC form and expects paginated/object-compatible responses, but there is no request-level fallback when talking to an older leader that only supports legacy signatures/response shapes. In a mixed-version rollout (new follower -> old leader), this can fail RPC decode/params validation and interrupt syncing.
fixed it |
|
Benchmark: Git Info:
Leader Stats: Follower Stats: Plots: |
There was a problem hiding this comment.
Summary
Great work — this PR introduces a cohesive pagination model across server and importer client with strong compatibility handling and meaningful guardrails.
What I verified in the provided diff/context:
- Server now supports optional cursor pagination for both
stratus_getBlockAndReceiptsandstratus_getBlockWithChanges, while preserving legacy one-shot shapes when pagination is not needed. - Importer client fetch path now supports both paginated and legacy response forms (
BlockWithChangesPageResponsecustom deserializer + optionalpagination), addressing mixed-version rollout risk. - Reducers include solid consistency checks (stable total, cursor monotonicity, block identity/hash continuity, duplicate change detection, tx/receipt count matching, partial-not-found fail-fast).
- Test coverage is substantial and includes e2e round-trips plus targeted unit tests for cursor decoding, clamping, section slicing, byte-budget behavior, backward compatibility, and reducer invariants.
I did not find any concrete blocking issues in the shown changes.
|
Benchmark: Git Info:
Leader Stats: Follower Stats: Plots: |
|
Benchmark: Git Info:
Leader Stats: Follower Stats: Plots: |
There was a problem hiding this comment.
Summary
Strong change set overall: pagination is implemented end-to-end (RPC handlers + importer client), with explicit backward-compat handling for legacy one-shot shapes, cursor validation, and consistency checks during reassembly. I also verified meaningful coverage was added across unit and e2e paths (legacy behavior, multi-page assembly, byte-budget constraints, and leader/follower round-trips).
I did not find concrete blocking issues in the provided diff/context.
|
Persistent review updated to latest commit bae6dfb |
There was a problem hiding this comment.
Rescue Review — Re-approval
Retry on the same head (bae6dfb, no new commits since my earlier platform-deep approval). Re-verified the diff and open threads: nothing new to flag. The explicit limit override is already gated behind #[cfg(any(test, feature = "dev"))], addressing the remaining member feedback. Sticking with APPROVE. 🦉
|
|
||
| let opted_in = matches!(request.as_ref().and_then(|r| r.pagination), Some(true)); | ||
| let has_cursor = request.as_ref().is_some_and(|r| r.cursor.is_some()); | ||
| let policy = match (pagination_enabled, opted_in || has_cursor) { |
There was a problem hiding this comment.
extract to should paginate tuple (bool)
| return Ok((json!((BlockRocksdb { header, transactions }, changes)), false)); | ||
| }; | ||
|
|
||
| let ranges = slice_ranges(§ion_lens, self.start, end); |
There was a problem hiding this comment.
maybe change this from a naive json response and implement a string stream
gventino-cw
left a comment
There was a problem hiding this comment.
the PR code it's well structured and feature rich. But we don't need all of that, a simple text stream should get the job done. I'll put this and draft and try to do it in the simpler way possible.
PR Type
Enhancement
Description
Add cursor-based pagination to importer RPC methods
Implement client fetcher and page reducers
Preserve backward compatibility for legacy clients
Expose config flag and error for oversized items
Diagram Walkthrough
File Walkthrough
6 files
Add pagination engine for importer RPC methodsImplement client-side paginated page fetcherAdd merge and length methods for ExternalBlockIntroduce generic pagination traits and fetcherIntegrate pagination into RPC handlersUse PaginationClient in fetch methods1 files
Add pagination_enabled configuration flag2 files
Export new pagination types and pagination requestInclude importer_pagination module1 files
Fix enum arm formatting for FakeLeader case1 files
Add error for oversized pagination item6 files