feat(address): on-demand backfill for Calls-tab block-range gaps - #86
Merged
Conversation
The Calls tab showed recent calls and older cached calls with no indication of the unfetched block range between them — the Dune `starknet.calls` fetch caps at 500 and the pf event window at 200, so an active address revisited after a few days has a hidden hole. Mirror the Transactions tab's nonce-gap feature, keyed on block ranges: - Detect block-span holes wider than CALL_GAP_SPAN_BLOCKS between cached calls and render an interactive gap row. Enter backfills that window newest-first (lazy chunking) via Dune `query_contract_calls_windowed` (contracts) or the pf event window `FillGap` (accounts), merging the result so the gap shrinks from its newer edge. - Persist fully-scanned ranges (new `address_call_scanned_ranges` table) so a genuinely-sparse hole stays closed across re-navigation and restarts; ranges load before first paint. Gaps filled with real calls self-close via the existing call cache. Adds gap-aware Calls-list navigation that reuses the existing static gap-index helpers and the calls fetch/merge/persist plumbing, plus a shared block-interval coalescing helper (utils::merge_block_interval). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds on-demand “gap rows” to the Address Calls tab to surface large block-range holes between cached calls and lazily backfill them (mirroring the Transactions nonce-gap UX). It also persists “scanned but sparse” call ranges in SQLite so gaps that prove empty don’t reappear across re-navigation/restarts.
Changes:
- Detect block-range call gaps (threshold-based), render interactive gap rows, and make Calls list navigation gap-aware.
- Implement a network task to fill a selected call gap and merge results into the existing calls/cache pipeline.
- Persist fully-scanned call ranges (
address_call_scanned_ranges) and coalesce intervals (shared in-memory + SQLite).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils.rs | Adds merge_block_interval interval coalescing helper used by scanned-range tracking. |
| src/ui/views/address_info.rs | Renders Calls-tab gap rows and switches Calls list rendering to a gap-aware ListState. |
| src/network/mod.rs | Wires the new FillAddressCallGap action into the network task runner/cancellation set. |
| src/network/event_window.rs | Documents FillGap policy usage for Calls-gap filling. |
| src/network/address.rs | Implements run_call_gap_fill and loads persisted scanned ranges before first paint. |
| src/data/mod.rs | Extends DataSource with load/add APIs for persisted scanned call ranges. |
| src/data/cache.rs | Adds address_call_scanned_ranges table + read/write/coalesce logic + a persistence test. |
| src/app/views/address_info.rs | Adds call-gap state, detection, selection, and gap-aware navigation helpers + tests. |
| src/app/mod.rs | Dispatches call-gap fills on Enter and refreshes call-gap detection after merges/scans. |
| src/app/input.rs | On Enter in Calls tab, dispatches a call-gap fill when a gap row is selected. |
| src/app/actions.rs | Adds actions for filling call gaps and for scanned-range load/record events. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ck-loading Addresses three issues in the on-demand Calls-tab gap fill flagged in review: - FillGap pf path ignored the upper bound: `fetch_address_activity` hardcoded `to_block = None`, so a `[lo, hi]` gap fill scanned `[lo, head]` newest-first and never converged on its range. Thread `to_block` through into `get_events_for_address`/`get_contract_events` (which already accept it). - Contract-without-Dune used the keyed `transaction_executed` (`Account`) filter, which targets an address as a tx sender — wrong for a contract. Pick the EventQueryKind from `is_contract`. - A failed/no-op fill left the gap row stuck on "loading": `r` (full refresh) preserves `fill_dispatched` for an unchanged range, so Enter could never re-dispatch. A drop guard now emits `AddressCallGapFillFinished` on every exit path of `run_call_gap_fill`; the reducer clears `fill_dispatched` so the row becomes re-dispatchable. Drop the misleading "press r to retry" text. Co-Authored-By: Claude Opus 4.8 (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.
Problem
The address Calls tab shows old cached calls immediately on re-entry (good), but the fresh fetch only fills the recent window — Dune
starknet.callscaps at 500, the pf event window at 200. An active address revisited after a few days ends up with recent calls on top and stale cached calls at the bottom, separated by an unfetched block range the UI never surfaced and the user couldn't fill. The Transactions tab already solves the equivalent problem for nonce gaps; this brings the same UX to Calls, keyed on block ranges.What this does
CALL_GAP_SPAN_BLOCKS(10k) apart, and render an interactive row:query_contract_calls_windowed; accounts use the pf event window'sFillGappolicy. Results flow through the existingAddressCallsMerged/ cache-persist path.j/k,Ctrl+D/U,g/Gclamp on gap rows), reusing the existing static gap-index helpers.Caching gaps as "closed" (so they don't re-appear)
address_callsand bridge the hole on the next visit.address_call_scanned_rangestable and loaded before first paint, so detection skips them across re-navigation and restarts. Interval coalescing is shared between the in-memory tracker and the SQLite layer (utils::merge_block_interval).Verification
cargo build+cargo build --releaseclean.cargo test— full suite green (263 lib + integration tests, 0 failed). New coverage: call-gap detection/threshold/nav, scanned-range suppression, and acache.dbround-trip/coalesce test.cargo fmtapplied; no new clippy warnings.BETWEEN from AND tofill SQL was run against production Dune (public STRK token, a finite block window) — parses, runs, and returns newest-first rows as the lazy-chunk fill expects.The live TUI gap-row interaction itself was not driven in a terminal (covered by unit tests + the SQL check).
🤖 Generated with Claude Code