Skip to content

Avoid refetching empty live RPC ranges#220

Merged
fracek merged 3 commits into
apibara:mainfrom
moodysalem:fix/live-empty-range-refetch
May 11, 2026
Merged

Avoid refetching empty live RPC ranges#220
fracek merged 3 commits into
apibara:mainfrom
moodysalem:fix/live-empty-range-refetch

Conversation

@moodysalem

Copy link
Copy Markdown
Contributor

Summary

Fix repeated live RPC range scans after emitting empty accepted blocks.

When live filtering reaches the current head with no matching data, the stream emits an empty accepted block but
intentionally does not advance state.cursor. Subsequent live scans were still starting from cursor + 1, so sparse
filters could repeatedly refetch previously scanned empty blocks as the head advanced.

This changes live range fetching to resume from max(cursor, lastEmptyBlockNumber) + 1, treats lastEmptyBlockNumber === head as being at head, and clears the empty-block marker on reorg invalidation.

Testing

  • Added a protocol test covering empty accepted live blocks as the head advances.
  • Not run locally: dependencies are not installed in this checkout, so vitest is unavailable.

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Rate limit exceeded

@fracek has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 43 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e8a5bbee-a41e-4ce9-b297-af8f3a0147bf

📥 Commits

Reviewing files that changed from the base of the PR and between 758d25b and 3d285f9.

📒 Files selected for processing (3)
  • change/@apibara-protocol-cefba257-a3ad-451e-b3d6-13613ecf7903.json
  • packages/protocol/src/rpc/data-stream.ts
  • packages/protocol/tests/rpc-data-stream.test.ts
📝 Walkthrough

Walkthrough

RpcDataStream now centralizes invalidation decisions via new helpers, tracks the last emitted empty block (lastEmptyBlockNumber) for head detection and range-start calculations, resets that state on invalidation, and adds a test ensuring empty live blocks are not refetched as the head advances.

Changes

Live Block Empty-Block Handling

Layer / File(s) Summary
Helper Predicates
packages/protocol/src/rpc/data-stream.ts
shouldInvalidateProcessedLiveData(state, cursor) centralizes reorg invalidation checks using state.cursor.orderKey and state.lastEmptyBlockNumber. lastProcessedLiveBlock(state) returns the greater of lastEmptyBlockNumber or cursor.orderKey.
Head Detection with Empty Block Awareness
packages/protocol/src/rpc/data-stream.ts
isAtHead now returns true when either state.cursor.orderKey or state.lastEmptyBlockNumber equals the current head order key.
Reorg Invalidation in Live and Waiting States
packages/protocol/src/rpc/data-stream.ts
produceLiveBlocks and waitForHeadChange now call shouldInvalidateProcessedLiveData; when it returns true they set state.cursor to the reorg cursor and clear state.lastEmptyBlockNumber before yielding invalidate.
Test Suite and Utilities
packages/protocol/tests/rpc-data-stream.test.ts
Adds EmptyLiveHeadConfig test double and a Vitest case that verifies empty accepted blocks are not refetched as the live head advances; includes helpers for deterministic blocks, cursors, and timing.
Change Descriptor
change/@apibara-protocol-cefba257-a3ad-451e-b3d6-13613ecf7903.json
Adds a patch descriptor for @apibara/protocol noting the change and author.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
Empty blocks I gently note,
No refetch, I hop and float,
Reorgs checked with tidy care,
Head advances — nothing to spare,
I nibble logs and skip the air.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main fix: avoiding refetching empty live RPC ranges, which is the core problem addressed throughout all modified files.
Description check ✅ Passed The description is directly related to the changeset, explaining the problem being fixed, the solution implemented, and testing approach.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/protocol/tests/rpc-data-stream.test.ts (1)

98-149: ⚡ Quick win

Add a regression test for reorgs after an empty live block.

This PR also changes invalidation to consider lastEmptyBlockNumber and clear it on reorg, but the new test only covers straight head growth. A case where block N is emitted as empty and then a reorg invalidates N would lock in the new invalidation path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/protocol/tests/rpc-data-stream.test.ts` around lines 98 - 149, Add a
regression test that simulates an empty live block followed by a reorg to ensure
the new invalidation path clears lastEmptyBlockNumber and triggers proper
refetch: create an EmptyLiveHeadConfig and RpcClient, open streamData({
finality: "accepted", filter: ["logs"], startingCursor: { orderKey: 1n }}),
advance the head to emit an empty block (verifying fetchBlockRangeCalls and that
config.lastEmptyBlockNumber is set), then simulate a reorg by setting
config.headBlock to a lower value (invalidating that empty block) and assert
that config.lastEmptyBlockNumber is cleared and that subsequent iterator.next()
causes fetchBlockRange to be called again for the correct start/max block;
reference EmptyLiveHeadConfig, RpcClient, streamData, fetchBlockRangeCalls, and
lastEmptyBlockNumber to locate where to add assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/protocol/src/rpc/data-stream.ts`:
- Around line 483-491: The termination check currently uses state.cursor to
decide whether to stop, but lastProcessedLiveBlock(state) can advance beyond
state.cursor when an empty accepted block updates state.lastEmptyBlockNumber;
update the termination logic in shouldContinue() (or wherever
options.endingCursor is compared) to compare options.endingCursor against
lastProcessedLiveBlock(state) instead of state.cursor so the stream stops when
the processed-live position reaches the requested endingCursor; ensure you
reference lastProcessedLiveBlock(state), state.lastEmptyBlockNumber,
state.cursor.orderKey and options.endingCursor when making the change.

---

Nitpick comments:
In `@packages/protocol/tests/rpc-data-stream.test.ts`:
- Around line 98-149: Add a regression test that simulates an empty live block
followed by a reorg to ensure the new invalidation path clears
lastEmptyBlockNumber and triggers proper refetch: create an EmptyLiveHeadConfig
and RpcClient, open streamData({ finality: "accepted", filter: ["logs"],
startingCursor: { orderKey: 1n }}), advance the head to emit an empty block
(verifying fetchBlockRangeCalls and that config.lastEmptyBlockNumber is set),
then simulate a reorg by setting config.headBlock to a lower value (invalidating
that empty block) and assert that config.lastEmptyBlockNumber is cleared and
that subsequent iterator.next() causes fetchBlockRange to be called again for
the correct start/max block; reference EmptyLiveHeadConfig, RpcClient,
streamData, fetchBlockRangeCalls, and lastEmptyBlockNumber to locate where to
add assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b73dac99-1265-4168-a9b7-940cb58ad9b6

📥 Commits

Reviewing files that changed from the base of the PR and between aa40eac and 3f172f4.

📒 Files selected for processing (2)
  • packages/protocol/src/rpc/data-stream.ts
  • packages/protocol/tests/rpc-data-stream.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/protocol/src/rpc/data-stream.ts`:
- Around line 482-490: The resume start for fetching the next live range should
use lastProcessedLiveBlock(state) instead of directly using
state.cursor.orderKey; update the logic that currently computes the next start
as state.cursor.orderKey + 1n to compute lastProcessedLiveBlock(state) + 1n so
that after an accepted empty head block (when state.lastEmptyBlockNumber >
state.cursor.orderKey) the fetch resumes from max(cursor,
lastEmptyBlockNumber)+1; change the reference at the place that builds the
head-range fetch start (currently using state.cursor.orderKey + 1n) to call
lastProcessedLiveBlock(state) and add 1n.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0fec8b04-b7f8-4a8e-985f-88822cc47600

📥 Commits

Reviewing files that changed from the base of the PR and between 3f172f4 and 758d25b.

📒 Files selected for processing (2)
  • change/@apibara-protocol-cefba257-a3ad-451e-b3d6-13613ecf7903.json
  • packages/protocol/src/rpc/data-stream.ts
✅ Files skipped from review due to trivial changes (1)
  • change/@apibara-protocol-cefba257-a3ad-451e-b3d6-13613ecf7903.json

Comment thread packages/protocol/src/rpc/data-stream.ts
@fracek fracek force-pushed the fix/live-empty-range-refetch branch from 758d25b to fc0b1c6 Compare May 11, 2026 19:08
@fracek fracek force-pushed the fix/live-empty-range-refetch branch from fc0b1c6 to 3d285f9 Compare May 11, 2026 19:12
@fracek fracek merged commit e833963 into apibara:main May 11, 2026
2 checks passed
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.

2 participants