Skip to content

Conversation

@georgehao
Copy link
Member

@georgehao georgehao commented Nov 25, 2025

Purpose or design rationale of this PR

Describe your change. Make sure to answer these three questions: What does this PR do? Why does it do it? How does it do it?

Imagine there are 10 records in db, the size of one page is 5, the user queries it like this:

api/l2/unclaimed/withdrawals?address=0xfbaf549fE0d1eA2727E5F5B3662F54dBfA1eCbA1&page=1&page_size=5
api/l2/unclaimed/withdrawals?address=0xfbaf549fE0d1eA2727E5F5B3662F54dBfA1eCbA1&page=2&page_size=5
api/l2/unclaimed/withdrawals?address=0xfbaf549fE0d1eA2727E5F5B3662F54dBfA1eCbA1&page=3&page_size=5

The page=3&page_size=5 query is more than the number of records in db, so we should return early when start > total.

The page=3&page_size=5 query result cannot be found in cache, so we try to select from db, however the db returns no records, so we cannot cache the result. So every time the user queries page=3&page_size=5, this query will hit the db.

PR title

Your PR title must follow conventional commits (as we are doing squash merge for each PR), so it must start with one of the following types:

  • build: Changes that affect the build system or external dependencies (example scopes: yarn, eslint, typescript)
  • ci: Changes to our CI configuration files and scripts (example scopes: vercel, github, cypress)
  • docs: Documentation-only changes
  • feat: A new feature
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that doesn't fix a bug, or add a feature, or improves performance
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • test: Adding missing tests or correcting existing tests

Deployment tag versioning

Has tag in common/version.go been updated or have you added bump-version label to this PR?

  • No, this PR doesn't involve a new deployment, git tag, docker image tag
  • Yes

Breaking change label

Does this PR have the breaking-change label?

  • No, this PR is not a breaking change
  • Yes

Summary by CodeRabbit

  • Bug Fixes

    • Improved transaction history pagination: requests that start beyond available items now return empty results instead of causing errors, improving stability and API reliability.
  • Chores

    • Project version bumped to v4.7.5.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

Walkthrough

Added a boundary check in getCachedTxsInfo to return no results when the requested start index is >= total items; bumped internal version from v4.7.4 to v4.7.5. Minor formatting change in processAndCacheTxHistoryInfo only.

Changes

Cohort / File(s) Change Summary
Version Update
common/version/version.go
Bumped internal version tag from "v4.7.4" to "v4.7.5"
Pagination Boundary Check
bridge-history-api/internal/logic/history_logic.go
Added guard in getCachedTxsInfo to return empty results when requested start index ≥ total items; preserved existing total==0 behavior; minor non-functional formatting tweak in processAndCacheTxHistoryInfo

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant HistoryLogic as History Logic (getCachedTxsInfo)
    participant Cache

    Client->>HistoryLogic: requestTxs(start, limit)
    opt start < total
        HistoryLogic->>Cache: fetchSlice(start, limit)
        Cache-->>HistoryLogic: txItems, total
        HistoryLogic-->>Client: items, total, hasMore
    end
    opt start >= total
        HistoryLogic-->>Client: nil, 0, false
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Review focus: correctness of the boundary condition and that total==0 path remains unchanged.
  • Files to check: bridge-history-api/internal/logic/history_logic.go, common/version/version.go.

Suggested reviewers

  • Thegaram
  • yiweichi

Poem

🐰 A hop, a fix, a careful bound,
No more paging lost or found.
Version nudged one step anew,
Small clean change, yet keen and true.
I munch on code and bounce with glee. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title does not follow Conventional Commits format. It should start with a type like 'fix:', but only provides 'Return when total < request page'. The description confirms this is a fix but the title format is incorrect. Update the PR title to follow Conventional Commits format: 'fix: return early when request page exceeds total records' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The pull request description follows the template structure with clear purpose explanation, proper Conventional Commits type selection (fix), and deployment/breaking change checklist answers.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/remove_unnecessary_check

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link

codecov-commenter commented Nov 25, 2025

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 36.53%. Comparing base (de72e2d) to head (daa0e26).

Files with missing lines Patch % Lines
bridge-history-api/internal/logic/history_logic.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1766      +/-   ##
===========================================
- Coverage    36.54%   36.53%   -0.01%     
===========================================
  Files          247      247              
  Lines        21186    21188       +2     
===========================================
  Hits          7742     7742              
- Misses       12614    12616       +2     
  Partials       830      830              
Flag Coverage Δ
bridge-history-api 8.07% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bridge-history-api/internal/logic/history_logic.go (1)

365-377: Off‑by‑one and cache‑hit semantics for out‑of‑range pages

With 0‑based indices, valid positions are [0, total-1], so start == total is already out of range. Using start > total means the PR’s own example (10 records, pageSize=5, page=3 → start=10, total=10) will not be caught here and will still flow to ZRevRange and then down the “cache miss” path.

Also, returning isHit=false for an out‑of‑range page forces a DB query and can trigger the "cache miss after write, expect hit" log in processAndCacheTxHistoryInfo, even though the cache already contains the full dataset and we know this page is simply empty.

Consider tightening the guard and treating this as a cache hit with an empty page:

 func (h *HistoryLogic) getCachedTxsInfo(ctx context.Context, cacheKey string, pageNum, pageSize uint64) ([]*types.TxHistoryInfo, uint64, bool, error) {
   start := int64((pageNum - 1) * pageSize)
   end := start + int64(pageSize) - 1

   total, err := h.redis.ZCard(ctx, cacheKey).Result()
   if err != nil {
     log.Error("failed to get zcard result", "error", err)
     return nil, 0, false, err
   }

-  if start > total {
-    return nil, 0, false, nil
-  }
-
-  if total == 0 {
-    return nil, 0, false, nil
-  }
+  // No cache populated yet.
+  if total == 0 {
+    return nil, 0, false, nil
+  }
+
+  // Cache exists, but requested page is beyond available items.
+  // Treat this as an empty but valid page and avoid hitting DB again.
+  if start >= total {
+    return nil, 0, true, nil
+  }

This aligns the behavior with the PR description (e.g., page 3 when there are only 10 items) and avoids unnecessary DB work and noisy error logs in processAndCacheTxHistoryInfo.

🧹 Nitpick comments (2)
bridge-history-api/internal/logic/history_logic.go (1)

447-458: processAndCacheTxHistoryInfo behavior remains correct; log depends on getCachedTxsInfo semantics

The logic here is fine and the only change is formatting. Note that if getCachedTxsInfo continues to return isHit=false for out‑of‑range pages after caching, this "cache miss after write, expect hit" branch will still fire (with err == nil). If you adopt the adjusted getCachedTxsInfo semantics above (treating out‑of‑range as isHit=true), this path will only indicate real inconsistencies.

common/version/version.go (1)

8-8: Version tag bump to v4.7.5 looks consistent

The tag update cleanly advances the reported protocol version and is consistent with the rest of the file; no behavioral issues here. As a minor process note, ensure the PR title follows Conventional Commits (e.g., fix: return when total < request page) so it passes squash‑merge policies.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de72e2d and d036fe8.

📒 Files selected for processing (2)
  • bridge-history-api/internal/logic/history_logic.go (2 hunks)
  • common/version/version.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: tests
  • GitHub Check: test
  • GitHub Check: check

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bridge-history-api/internal/logic/history_logic.go (1)

361-376: Boundary check is logically correct; add tests and consider isHit/total semantics for out-of-range pages

The new if start >= total { return nil, 0, false, nil } guard is correct for 0-based pagination and avoids an unnecessary Redis range call when the requested page is beyond the last item.

Two follow-ups worth addressing:

  1. Tests / coverage
    Codecov reports these new lines as uncovered. Please add tests that exercise:

    • A non-empty sorted set where (pageNum-1)*pageSize is equal to total (out-of-range page).
    • Verifying that getCachedTxsInfo returns an empty slice and no error for that case.
      This will bring patch coverage up and lock in the desired behavior.
  2. isHit and total behavior
    For “page beyond last item” you currently return isHit=false and total=0, same as before. That means upstream methods will still treat this as a cache miss and go back to the DB even though the full dataset is already cached, and clients lose the real total count.
    Consider instead treating this as a cache hit with an empty page, e.g.:

    if start >= total {
  • return nil, 0, false, nil
  • return nil, uint64(total), true, nil
    }

This would (a) prevent unnecessary DB work on out-of-range pages and (b) keep `total` consistent with pages that do have results. If you go this route, you should also ensure call sites and metrics treat this as an expected “empty last page” rather than a miss.

</blockquote></details>

</blockquote></details>
🧹 Nitpick comments (1)
bridge-history-api/internal/logic/history_logic.go (1)

446-457: Clarify !isHit handling after cache write; current log uses a nil err

In processAndCacheTxHistoryInfo, when getCachedTxsInfo returns !isHit but err == nil, the code logs:

log.Error("cache miss after write, expect hit", ..., "error", err)
return nil, 0, err

Given the current getCachedTxsInfo logic, reaching this block implies no error occurred, so err is always nil. That results in an error log with a nil error field and returns a nil error to the caller, which is confusing both for logs and for callers.

Two options to improve this:

  • If a cache miss here is truly exceptional, construct and return a real error instead of reusing err:

  • if !isHit {

  • log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", page, "page size", pageSize, "error", err)

  • return nil, 0, err

  • }

  • if !isHit {
  • cacheErr := errors.New("cache miss after write, expect hit")
  • log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", page, "page size", pageSize, "error", cacheErr)
  • return nil, 0, cacheErr
  • }
    
    
  • If you adopt the suggested change where out-of-range pages are treated as cache hits with empty results, then !isHit here should only indicate genuine anomalies; you could keep the structure above but this path would be much rarer.

Either way, cleaning this up will make logs and error propagation more accurate.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d036fe8 and daa0e26.

📒 Files selected for processing (1)
  • bridge-history-api/internal/logic/history_logic.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests

@georgehao georgehao merged commit 2ecc42e into develop Nov 25, 2025
6 checks passed
@georgehao georgehao deleted the fix/remove_unnecessary_check branch November 25, 2025 15:36
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