amanusk / amanusk/snbeat

perf(address): per-WS-event work on large Calls lists is O(n): full re-sort, linear dedup, and a full SQLite rewrite per enrichment

Open
#92 0 comments 0 reactions 0 assignees View on GitHub
M performance snbeat
Dominant language
Rust
Stars
6
Forks
1
Avg merge
7m
Merged PRs (30d)
1

Description

## Problem

For a contract with a long history (tens of thousands of cached calls), each WS event on the viewed address triggers several operations proportional to the whole list, all on the UI thread or the shared network task:

- `Action::AddressWsEvent` (`src/app/mod.rs`): dedups with `calls.items.iter().any(..)` (O(n)), pushes a stub, then `sort_by` on the entire `Vec` (O(n log n)).
- `Action::AddressCallsEnriched`: `iter_mut().find()` per enriched call (O(n·m)), then `self.address.calls.items.clone()` (52k `ContractCallSummary`s with `String`s and `Vec`s) is sent as `Action::PersistAddressCalls`.
- `save_address_calls` (`src/data/cache.rs`) serializes every row to JSON, then `DELETE`s the address's rows and re-`INSERT`s all of them in one transaction. At 52k rows that is a full-table rewrite per WS event, both CPU (serde) and SQLite I/O on the r2d2 worker.
- `call_gap_render_positions` / `gap_render_positions` (`src/app/views/address_info.rs`) locate each gap with a linear `position()` over all rows; called at least once per frame.

None of these is the dominant cost of the reported input lag (that was per-frame rendering), but they add tens of milliseconds of UI-thread work per event and a heavy write per event.

## Proposed fix

- Calls are kept sorted by `block_number` descending: insert with `partition_point` instead of push + sort; keep a `HashSet` of tx hashes (or a `HashMap` index) for dedup and for `AddressCallsEnriched` lookups.
- Persist only what changed: upsert the touched rows keyed by tx hash (or by index) instead of delete-all + reinsert, or at minimum debounce `PersistAddressCalls` so bursts collapse into one write.
- `gap_render_positions`: binary search on the sorted key (nonce desc for txs, block desc for calls) instead of `position()`.

## Severity

Medium: bounded per event, but it scales with history size and fires on every WS event while the user is viewing a busy contract.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.