Skip to content

fix: select_transactions_records edge case#2285

Merged
sergerad merged 6 commits into
nextfrom
sergerad-selext-tx-records-page
Jun 29, 2026
Merged

fix: select_transactions_records edge case#2285
sergerad merged 6 commits into
nextfrom
sergerad-selext-tx-records-page

Conversation

@sergerad

Copy link
Copy Markdown
Collaborator

Summary

select_transactions_records paginates by payload size, but it inferred truncation from total_size >= cap, which missed the common case where a transaction fails to fit while the running total is still below the cap — making a partial page look complete.

The fix tracks an explicit "transaction didn't fit" signal so a truncated page reports the last complete block as the cursor, and errors when a single block exceeds the payload cap.

Changelog

changelog = "none"
reason    = "Internal change only."

@sergerad sergerad changed the title Report last complete block as cursor fix: select_transactions_records edge case Jun 25, 2026
@sergerad sergerad mentioned this pull request Jun 25, 2026
Comment thread crates/store/src/errors.rs Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding this function quite confusing. The fix works - I think - but given the function layout I'm a bit worried there's something I'm overlooking.

However I think what I want to suggest isn't possible because the table is without rowid.

Maybe @kkovaacs can offer some insight.

What I want to do is roughly:

// Find the first applicable row.
let mut row_start = db.select(
    "SELECT rowid FROM transactions WHERE <account+block start filter>"
);

// The last completed full block page index ito tx records.
let mut iblock = 0usize;
let mut records = Vec::new();
let mut last_block = BlockNumber::MAX;

loop {
    let chunk = db.select(
        "SELECT tx, rowid, block FROM transactions WHERE <filter> AND rowid >= row_start LIMIT 1000 ORDER BY rowid"
    );

    for row in chunk {
        if records.size() + row > capacity {
            break;
        }

        row_start = row.rowid;
        if row.block != last_block {
            last_block = row.block;
            iblock = records.len();
        }
        records.push(row.tx);
    }
}

// Truncate to the last full block.
records = records[..iblock];
Ok(records);

Comment on lines +228 to +231
// Set to the block number of the first transaction that did not fit within the payload cap.
// This is the explicit "we truncated" signal; the accumulated byte total cannot be used as a
// proxy, since a transaction can fail to fit while `total_size` is still below the cap.
let mut truncated_at_block: Option<i64> = None;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest an alternate approach, like I outlined in https://github.com/0xMiden/node/pull/2285/changes#r3474272591.

Comment on lines +294 to +297
let complete_transactions: Vec<_> = all_transactions
.into_iter()
.take_while(|row| row.block_num < truncation_block)
.collect();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you track the last index in addition to the last completed block, then you can instead all_transactions.truncate(ilast_completed).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with partition_point and truncate instead of managing the index. Its safer and cleaner, particularly because the vec is mut. The partition point is O(log n), not that it matters with the lengths we are likely to see here.

Comment thread crates/store/src/errors.rs
@sergerad sergerad requested a review from kkovaacs June 29, 2026 04:10
Comment thread crates/rpc/src/server/api.rs Outdated
@sergerad sergerad enabled auto-merge (squash) June 29, 2026 20:55
@sergerad sergerad merged commit c339134 into next Jun 29, 2026
36 of 37 checks passed
@sergerad sergerad deleted the sergerad-selext-tx-records-page branch June 29, 2026 21:30
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.

4 participants