Skip to content

Feat/evm hot v2 - #5

Open
S0c5 wants to merge 8 commits into
mainfrom
feat/evm-hot-v2
Open

Feat/evm hot v2#5
S0c5 wants to merge 8 commits into
mainfrom
feat/evm-hot-v2

Conversation

@S0c5

@S0c5 S0c5 commented Jun 27, 2026

Copy link
Copy Markdown
Member

Summary

  • Storage migration (redb → SQLite) with embedded, auto-applied versioned migrations + one-shot migrate_redb_to_sqlite importer; includes swap fixes and a buffer-overrun panic fix.
  • Persistent webhook delivery: webhooks persisted to a new webhook_deliveries table and delivered by a background worker. Non-2xx (incl. 503) retried with configurable limits; a lease prevents duplicate POSTs. Adds POST /admin/retry_webhooks.

Webhook details

  • Statuses: pendingdelivered (2xx) / failed (retries exhausted). Idempotent on (id, event).
  • Worker wakes on enqueue and on admin retry; otherwise polls.
  • New env: WEBHOOK_MAX_RETRIES, WEBHOOK_RETRY_DELAY_MS, WEBHOOK_RETRY_POLL_INTERVAL, WEBHOOK_RETRY_BATCH_SIZE, WEBHOOK_LEASE_SECONDS.

Migrations

migrations/V2__webhook_deliveries.sql is include_str!'d and applied on startup. Rebuild + restart to apply.

Notes

  • A one-off script with real customer PII was intentionally kept out of the repo (gitignored); use POST /admin/retry_webhooks for operational retries.

Test plan

  • cargo build --release and cargo test pass
  • Fresh DB boots with webhook_deliveries (PRAGMA user_version = 2)
  • Existing V1 DB migrates without data loss
  • Webhook retried on 503, failed after max retries
  • POST /admin/retry_webhooks re-queues a failed delivery

S0c5 and others added 5 commits June 26, 2026 20:10
Co-authored-by: Cursor <cursoragent@cursor.com>
Webhooks are now persisted to a new webhook_deliveries table and delivered
by a background worker instead of inline in the monitor/sweeper. Failed
deliveries (non-2xx, including 503) are retried with configurable limits,
and a lease prevents duplicate POSTs. Adds POST /admin/retry_webhooks to
re-queue permanently failed deliveries.

Co-authored-by: Cursor <cursoragent@cursor.com>
Polygon fell thousands of blocks behind head because catch_up scanned one
block at a time, each costing a full get_block_by_number plus a chain-wide
(unfiltered) eth_getLogs call, with get_logs_with_retry treating an empty
result as a failure and retrying up to 30x.

- get_logs_with_retry now returns immediately on any Ok (including empty)
  and retries only on Err.
- eth_getLogs is filtered to the chain's allowed token addresses instead of
  scanning every Transfer event on the chain.
- When the gap between last-processed and head exceeds 10 blocks, catch_up
  switches to a batched path: one ranged, address-filtered eth_getLogs call
  per catch_up_chunk_size blocks (default 500), bisecting the range on
  provider errors (e.g. Alchemy's response-size cap) instead of retrying the
  identical request, plus concurrent eth_getBlockByNumber fetches (up to
  block_fetch_concurrency) for native transfers. Checkpoints once per chunk;
  replay is idempotent via the existing deposit-recording dedup.
- Adds catch_up_chunk_size and block_fetch_concurrency chain config options.

Covered by 7 new tests (regression, address filter, batch happy path,
bisection, bisection floor, concurrent native fetch, idempotent replay).

Co-authored-by: Cursor <cursoragent@cursor.com>
S0c5 and others added 3 commits July 8, 2026 19:43
The monitor/sweeper/webhook-retry loops called rusqlite (via Db) directly
from async fns with no spawn_blocking, and the r2d2 read pool had no
connection_timeout (defaulting to 30s). During a large catch-up backlog,
this let a busy chain pin a Tokio worker thread for tens of seconds,
stalling everything else sharing that runtime.

- Add Db::blocking, which offloads a Db closure onto spawn_blocking; route
  every DB call reached from async code (monitor, sweeper, webhook,
  register) through it.
- Set an explicit 5s r2d2 connection_timeout instead of the 30s default.
- Add tokio::task::yield_now() between blocks/logs in the batch catch-up
  path so one chunk can't monopolize a worker thread across many
  non-yielding blocking calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
Fix async-runtime stalls: move DB calls off async threads, yield during catch-up
Accelerate Monitor catch-up for backlogged chains
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.

1 participant