You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Multiple bail! invocations use brace-style interpolation ({context}, {transactions_len}, {expected_total}) without supplying matching format arguments, leading to compilation failures. Use positional {} placeholders with corresponding arguments or named parameters accepted by format!.
fnvalidate_progress(page:&ImporterPageInfo,expected_total:&mutOption<usize>,context:&str) -> anyhow::Result<Option<String>>{if page.returned == 0 && page.next_cursor.is_some(){bail!("paginated {context} returned no items but provided a next cursor");}match expected_total {Some(expected_total)if*expected_total != page.total => {bail!("paginated {context} changed total from {expected_total} to {}", page.total);}Some(_) => {}None => *expected_total = Some(page.total),}Ok(page.next_cursor.clone())}structBlockAndReceiptsPages{block_number:BlockNumber,block:Option<ExternalBlock>,receipts:Vec<ExternalReceipt>,expected_total:Option<usize>,}implBlockAndReceiptsPages{fnnew(block_number:BlockNumber) -> Self{Self{
block_number,block:None,receipts:Vec::new(),expected_total:None,}}fnpush_block(&mutself,page_block:ExternalBlock) -> anyhow::Result<()>{if page_block.number() != self.block_number{bail!("paginated block with receipts returned unexpected block number {} instead of {}",
page_block.number(),self.block_number
);}match&mutself.block{Some(block) => block.extend_full_transactions_from(page_block),None => {self.block = Some(page_block);Ok(())}}}}implPageReducer<BlockAndReceiptsPageResponse>forBlockAndReceiptsPages{typeOutput = ExternalBlockWithReceipts;typePaginator = ImporterCursorPaginator;fnreduce(&mutself,page:BlockAndReceiptsPageResponse) -> anyhow::Result<Option<String>>{let cursor = validate_progress(&page.pagination,&mutself.expected_total,"block with receipts")?;let page_block = ExternalBlock::try_from(page.block)?;self.push_block(page_block)?;self.receipts.extend(page.receipts);Ok(cursor)}fnfinish_after_not_found(self) -> anyhow::Result<Option<Self::Output>>{ifself.block.is_none(){Ok(None)}else{bail!("block disappeared while fetching paginated block with receipts");}}fn finish(self) -> anyhow::Result<Option<Self::Output>>{letSome(block) = self.blockelse{returnOk(None);};let expected_total = self.expected_total.unwrap_or_default();let transactions_len = block.full_transactions_len()?;if transactions_len != expected_total {bail!("paginated block with receipts assembled {transactions_len} transactions but expected {expected_total}");}
Replace the named placeholders in the bail! macros with positional {} placeholders and pass the corresponding variables as arguments. This ensures the format strings compile correctly and include the intended context and values.
fn validate_progress(page: &ImporterPageInfo, expected_total: &mut Option<usize>, context: &str) -> anyhow::Result<Option<String>> {
if page.returned == 0 && page.next_cursor.is_some() {
- bail!("paginated {context} returned no items but provided a next cursor");+ bail!(+ "paginated {} returned no items but provided a next cursor",+ context+ );
}
match expected_total {
- Some(expected_total) if *expected_total != page.total => {- bail!("paginated {context} changed total from {expected_total} to {}", page.total);+ Some(total) if *total != page.total => {+ bail!(+ "paginated {} changed total from {} to {}",+ context,+ total,+ page.total+ );
}
Some(_) => {}
None => *expected_total = Some(page.total),
}
Ok(page.next_cursor.clone())
}
Suggestion importance[1-10]: 9
__
Why: This fixes compile errors in validate_progress by replacing unsupported named placeholders with positional {} formatting, enabling the bail! macros to work correctly.
High
Use positional placeholders in bail!
Correct the format string in the bail!macro by using {} placeholders for both values and passing page_block_number and self.block_number as positional arguments to avoid compile errors.
impl BlockWithChangesPages {
fn push_block(&mut self, page_block: BlockRocksdb) -> anyhow::Result<()> {
let page_block_number = BlockNumber::from(page_block.header.number);
if page_block_number != self.block_number {
bail!(
- "paginated block with changes returned unexpected block number {page_block_number} instead of {}",+ "paginated block with changes returned unexpected block number {} instead of {}",+ page_block_number,
self.block_number
);
}
// ...
}
}
Suggestion importance[1-10]: 8
__
Why: Changing the bail! macro to use {} placeholders and positional arguments corrects the format string error in push_block, ensuring it compiles and displays the values properly.
Medium
Correct bail! placeholders in finish
Replace the named placeholders in the bail! call with positional {} and supply total and expected_total as arguments so the error message formats correctly.
impl PageReducer<BlockWithChangesPageResponse> for BlockWithChangesPages {
fn finish(self) -> anyhow::Result<Option<Self::Output>> {
let Some(block) = self.block else {
return Ok(None);
};
let expected_total = self.expected_total.unwrap_or_default();
let total = block.transactions.len() + self.changes.account_changes.len() + self.changes.slot_changes.len();
if total != expected_total {
- bail!("paginated block with changes assembled {total} items but expected {expected_total}");+ bail!(+ "paginated block with changes assembled {} items but expected {}",+ total,+ expected_total+ );
}
Ok(Some((block, self.changes)))
}
}
Suggestion importance[1-10]: 8
__
Why: Updating the bail! call in finish to use positional formatting fixes a compilation issue and ensures the error message includes the correct total and expected_total values.
Medium
gventino-cw
changed the title
feat: generic pagination engine with cursor paginatio policy + importer pagination
Issue 2518 - Implement response pagination for requests larger than the max response size
Aug 19, 2026
gventino-cw
changed the title
Issue 2518 - Implement response pagination for requests larger than the max response size
2518 - Generic Pagination Engine with Cursor Pagination Engine + Importer Cursor Pagination
Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Type
Enhancement
Description
Introduce generic cursor-based pagination engine
Delegate block fetches to ImporterPaginationClient
Add server-side pagination in RPC handlers
Extend ExternalBlock for merging paginated transactions
Diagram Walkthrough
File Walkthrough
1 files
Wrap FakeLeader arm in braces for consistency6 files
Delegate fetching to ImporterPaginationClientAdd ImporterPaginationClient pagination logicImplement pagination in RPC handlersDefine ImporterPagination request/response typesIntroduce generic pagination engine and policiesAdd methods for transaction merging and count2 files
Expose importer_pagination in moduleRe-export pagination types in types module