Skip to content

fix: prevent SQLite lock churn and validate EVM RPC capabilities - #107

Draft
quqi1599 wants to merge 1 commit into
GMWalletApp:masterfrom
quqi1599:codex/upstream-sqlite-rpc-health-fix
Draft

fix: prevent SQLite lock churn and validate EVM RPC capabilities#107
quqi1599 wants to merge 1 commit into
GMWalletApp:masterfrom
quqi1599:codex/upstream-sqlite-rpc-health-fix

Conversation

@quqi1599

@quqi1599 quqi1599 commented Aug 4, 2026

Copy link
Copy Markdown

Summary

This fixes two production failure modes that can silently reduce payment-recognition reliability in the default pure-Go SQLite deployment:

  • repeated SQLITE_BUSY / database is locked errors while cleaning transaction locks and updating EVM scan cursors;
  • RPC nodes being marked healthy when their TCP port is reachable but the required eth_getLogs or eth_subscribe capability is rate-limited or disabled.

It also makes live EVM WebSocket subscriptions start at latest. Without an explicit FromBlock, go-ethereum serializes the filter as fromBlock: 0x0, which some public providers reject as an oversized historical range.

Root cause

The pure-Go SQLite driver uses modernc.org/sqlite. Its per-connection PRAGMA syntax is _pragma=...; the previous _busy_timeout=5000 DSN option was ignored. Running PRAGMA busy_timeout=5000 once after opening the database only configured one pooled connection, while the runtime database allowed multiple concurrent writers.

RPC health checks only performed a TCP dial. That allowed endpoints returning HTTP 403/429 or WebSocket subscription quota errors to remain ok and be selected repeatedly by listeners and backfill scanners.

Changes

  • apply WAL, synchronous=NORMAL, and a 5-second busy timeout to every pure-Go SQLite connection;
  • serialize runtime SQLite writes through one connection;
  • reuse the bounded SQLite busy retry for expired transaction-lock cleanup;
  • verify EVM HTTP nodes with eth_blockNumber plus the scanner's cursor-based historical eth_getLogs filter;
  • verify EVM WebSocket nodes by establishing the actual filtered log subscription;
  • start ETH/BSC/Polygon/Plasma live subscriptions at latest;
  • use capability-aware checks in the admin RPC health endpoint;
  • replace the rate-limited default BSC WebSocket endpoint and add a working general HTTP backfill endpoint;
  • add regression tests for per-connection busy timeout, cleanup retry, HTTP log capability, WebSocket subscription capability, and fromBlock: latest.

Validation

  • go test ./...
  • go vet ./...
  • CGO_ENABLED=0 go build -trimpath .
  • targeted -race runs for all newly added SQLite, retry, HTTP RPC, and WebSocket RPC tests

In a single-instance deployment, the change stopped new SQLite busy errors during the observation window, restored a continuously advancing BSC backfill cursor, and correctly classified quota-limited/unsupported RPC nodes as down.

No schema migration is introduced. A real on-chain payment was not executed as part of validation.

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