From cd049c2501e8f5d5e606a7d1704439f23e4ec6c1 Mon Sep 17 00:00:00 2001 From: Human and Agent dVPN <271368948+Sentinel-Autonomybuilder@users.noreply.github.com> Date: Sat, 2 May 2026 13:26:15 -0700 Subject: [PATCH] fix(chain): refresh DEFAULT_RPC_POOL, drop stale rpc.sentinel.co as primary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rpc.sentinel.co has been stuck behind tip while still reporting catching_up=false, so it serves stale ABCI bank balances. Apps that pick it as primary (which the latency-first pool does on cold start, since sentinel.co usually answers /status quickly) end up reading wallet balances and subscription state that are weeks old — see the e2e report in findings/2026-04-30-cli-e2e-real-money-report.md where every broadcast attempt failed against the old 3-entry pool. Replace with an 8-endpoint audited pool (verified 2026-05-02 against a known funded sent1 address — every entry reported catching_up=false AND served a correct ABCI bank balance): busurnode, suchnode, publicnode, trinitystake (sub-500ms) polkachu, autostake, freshSTAKING (community validators) rpc.sentinel.co (kept last as stale-fallback only) Consumers (deploy.ts, settings.ts) already pull DEFAULT_RPC_POOL through the latency-aware failover, so no other code change is needed. Existing unit test in tests/unit/chain.test.ts continues to pass — it only asserts length >= 3 and https:// prefix, both still true. README updated to match. --- README.md | 2 +- src/main/services/chain.ts | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 34b8448..9fdb0f8 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Electron ABI. If you later want to run unit tests, run | Address format | bech32; app + nodes use the `sent` HRP, chain-side node identity is `sentnode` | | At-rest encryption | Electron `safeStorage` (OS keychain: Keychain / DPAPI / libsecret) | | Balance query | `StargateClient.getBalance(addr, 'udvpn')` | -| RPC pool | Three endpoints (rpc.sentinel.co + AutoStake + Polkachu) with latency-aware failover | +| RPC pool | Eight audited endpoints (busurnode → suchnode → publicnode → trinitystake → polkachu → autostake → freshSTAKING → sentinel.co) with latency-aware failover. Audited 2026-05-02; sentinel.co kept last as a stale-fallback only. | | Send / MsgSend | `SigningSentinelClient.sendTokens` with explicit StdFee; error codes classified | | Operator seeding | 1 DVPN auto-transferred to each new node's operator address on deploy | | QR code | Real SVG from `qrcode` in main, inlined in renderer | diff --git a/src/main/services/chain.ts b/src/main/services/chain.ts index b3a2c2b..f89e064 100644 --- a/src/main/services/chain.ts +++ b/src/main/services/chain.ts @@ -16,14 +16,27 @@ export const DEFAULT_GAS_PRICE_UDVPN = '0.1'; /** * Public RPC pool. The app picks whichever endpoint answers fastest and - * falls through on failure. These are the three endpoints named by the - * Sentinel docs + two community validators (AutoStake + Polkachu) with - * historically strong uptime. + * falls through on failure. + * + * Audited 2026-05-02 against a known funded address — every entry below + * reported `catching_up=false` AND served a correct ABCI bank balance. + * `rpc.sentinel.co` is kept last as a stale-fallback only: it has been + * stuck behind tip while reporting `catching_up=false`, returning stale + * balances for several weeks. New code should not rely on it as primary. + * + * Primary picks (busurnode + suchnode + publicnode + trinitystake) are + * sub-500ms in the audit; community validators (polkachu, freshSTAKING) + * follow; sentinel.co last. */ export const DEFAULT_RPC_POOL: readonly string[] = [ - 'https://rpc.sentinel.co:443', - 'https://sentinel-mainnet-rpc.autostake.com:443', + 'https://rpc-sentinel.busurnode.com', + 'https://rpc.sentinel.suchnode.net', + 'https://sentinel-rpc.publicnode.com', + 'https://rpc.trinitystake.io', 'https://sentinel-rpc.polkachu.com:443', + 'https://sentinel-mainnet-rpc.autostake.com:443', + 'https://sentinel-rpc.freshstaking.com', + 'https://rpc.sentinel.co:443', ]; export const udvpnToDvpn = (u: string | number | bigint): number => {