fix(discovery-service): reject zero-size history pages, and correct the cursor docs - #991
Open
Yoni-Starkware wants to merge 3 commits into
Open
fix(discovery-service): reject zero-size history pages, and correct the cursor docs#991Yoni-Starkware wants to merge 3 commits into
Yoni-Starkware wants to merge 3 commits into
Conversation
validate_bound only rejects values above the maximum, so a zero page size reached the scan. It breaks out of the loop before any work and can never satisfy the history_complete condition (result.len() < max_transactions is false at 0), so every page returns an empty 200 with an unchanged cursor and a client paginating until history_complete loops forever. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…number begin_block_number is an Option<u64> and the SDK sends it as undefined, but the spec told clients to set it to 0 on the first request. A client following that literally pins the scan upper bound at block 0: every note is skipped as above the bound and the page comes back empty and marked complete, with the cursor burned so a retry cannot recover. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three history tests each recomputed the same budget expression inline. Bind it once as ONE_BLOCK_BUDGET so the arithmetic lives in one place and the cost constants can change without touching each test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Extracted from #866 so that changes unrelated to that PR's gap-scan bug fix can land on their own. #866 is now stacked on top of this branch.
Each commit is independent of the follow-up fix and of the other two.
1.
fix(discovery-service): reject max_transactions == 0 with 400validate_boundonly rejects values above the maximum, so a zero page size reached the scan. There it breaks out of the loop before any work, and can never satisfy the completion condition (result.len() < max_transactionsis false at0), so every page returns an empty200with an unchanged cursor. A client paginating untilhistory_complete— which the spec instructs, and which both e2e loops do — never terminates.Verified empirically rather than by reading: a probe calling
fetch_transactionswithmax_transactions = 0and a deliberately huge budget returnsOk(empty)withhistory_complete: falseand an untouched cursor on every attempt.No caller can regress: the field is required (no serde default), the SDK defaults to 50, and the demo/e2e use 1, 5 and 10. A client sending
0today is already stuck in that loop.2.
docs(discovery-service): the first history request omits begin_block_numberbegin_block_numberis anOption<u64>and the SDK sends it asundefined, but the spec told clients to set it to0on the first request. Following that literally pins the scan's upper bound at block 0: every note is skipped as above the bound, the page comes back empty and marked complete, and the cursor is burned so a retry cannot recover.Also corrects "resolves from chain head" — the code resolves from the pinned snapshot block (
block_ref, or the current head when omitted), which forTag(PreConfirmed)iscached_head + 1.3.
test(discovery-core): name the one-block budget shared by history testsThree history tests each recomputed the same budget expression inline. Bound once as
ONE_BLOCK_BUDGETso the arithmetic lives in one place and the cost constants can change without touching each test. Test-only; no production code.Testing
cargo fmt --checkclean ·cargo clippy -p discovery-core -p discovery-service --all-targets0 warnings ·cargo test156 (discovery-core) + 58 (discovery-service) + all integration suites pass.The new validator test was proven to fail when its guard is disabled (
if max_transactions == 0→if false⇒test_history_cursor_zero_max_transactions_rejectedfails on its ownunwrap_err), per the repo's "prove a new test can fail" rule. A boundary test pins thatmax_transactions == 1is still accepted.🤖 Generated with Claude Code
This change is