aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-15 21:10:56 -0700
committerAdam Soltys <[email protected]>2026-06-15 21:10:56 -0700
commit011d18f65ca7895260370bbc2d29b513705593e3 (patch)
tree28bf6f8926620e6853b643603aa8ae0efabe2043 /src
parent36057966438b26327285e43ee00ce4895fd179c3 (diff)
downloadcoinosv3-011d18f65ca7895260370bbc2d29b513705593e3.tar.gz
coinosv3-011d18f65ca7895260370bbc2d29b513705593e3.zip
Route explorer traffic through VPS proxy (temporary)
This IP is rate-limited/banned by mempool.space, so REST + WS now go through an nginx CORS proxy on the OVH VPS (mempool via /mp, blockstream via /bs). Controlled by a single PROXY constant in api.js — set it to '' to revert to the public explorers once the ban is lifted. Hosts are tagged by kind so fee format detection still works. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/api.js40
-rw-r--r--src/wallet.js6
2 files changed, 36 insertions, 10 deletions
diff --git a/src/api.js b/src/api.js
index 5d0da77..0135369 100644
--- a/src/api.js
+++ b/src/api.js
@@ -6,10 +6,38 @@
// - a 429 from ANY request immediately backs off ALL subsequent requests
// (global exponential pause), easing back as requests succeed.
-const BACKENDS = {
- mainnet: ['https://mempool.space/api', 'https://blockstream.info/api'],
- testnet: ['https://mempool.space/testnet/api', 'https://blockstream.info/testnet/api'],
-};
+// TEMPORARY: route explorer traffic through a VPS while this IP is rate-limited
+// by mempool.space. Set PROXY = '' to go back to the public explorers directly.
+const PROXY = 'http://51.79.52.200:8088';
+
+const BACKENDS = PROXY
+ ? {
+ mainnet: [
+ { base: `${PROXY}/mp/api`, kind: 'mempool' },
+ { base: `${PROXY}/bs/api`, kind: 'esplora' },
+ ],
+ testnet: [
+ { base: `${PROXY}/mp/testnet/api`, kind: 'mempool' },
+ { base: `${PROXY}/bs/testnet/api`, kind: 'esplora' },
+ ],
+ }
+ : {
+ mainnet: [
+ { base: 'https://mempool.space/api', kind: 'mempool' },
+ { base: 'https://blockstream.info/api', kind: 'esplora' },
+ ],
+ testnet: [
+ { base: 'https://mempool.space/testnet/api', kind: 'mempool' },
+ { base: 'https://blockstream.info/testnet/api', kind: 'esplora' },
+ ],
+ };
+
+// WebSocket URL (mempool) — through the proxy when configured.
+export function wsUrl(net) {
+ const path = net === 'testnet' ? '/testnet/api/v1/ws' : '/api/v1/ws';
+ if (PROXY) return PROXY.replace(/^http/, 'ws') + '/mp' + path;
+ return 'wss://mempool.space' + path;
+}
const REQUEST_TIMEOUT_MS = 10000;
@@ -20,7 +48,7 @@ export class Api {
// Hosts are tried in order (mempool first); a host that 429s is parked on
// cooldown so we stop hammering it (Blockstream rate-limits aggressively).
- this._hosts = (BACKENDS[net] || BACKENDS.mainnet).map((base) => ({ base, cooldownUntil: 0 }));
+ this._hosts = (BACKENDS[net] || BACKENDS.mainnet).map((h) => ({ ...h, cooldownUntil: 0 }));
this._timeoutMs = REQUEST_TIMEOUT_MS;
// Serialized scheduler: one request at a time, min gap between starts.
@@ -162,7 +190,7 @@ export class Api {
async feeRates() {
for (const host of this._hosts) {
if (host.cooldownUntil > Date.now()) continue;
- const isMempool = host.base.includes('mempool');
+ const isMempool = host.kind === 'mempool';
try {
const res = await this.#run(host, isMempool ? '/v1/fees/recommended' : '/fee-estimates');
if (!res.ok) continue;
diff --git a/src/wallet.js b/src/wallet.js
index 241572a..b3c6a25 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -16,7 +16,7 @@ import { sha256 } from '@noble/hashes/sha256';
import * as btc from '@scure/btc-signer';
import { p2wpkh } from '@scure/btc-signer/payment';
-import { Api, pool } from './api.js';
+import { Api, pool, wsUrl } from './api.js';
// No look-ahead: stop scanning a chain at the first unused address. This wallet
// only ever exposes ONE unused address at a time (freshReceive = first unused;
@@ -481,9 +481,7 @@ export class Wallet {
// Pushes us new mempool/confirmed transactions for our addresses so history
// and balances update with no polling.
wsUrl() {
- return this.netName === 'testnet'
- ? 'wss://mempool.space/testnet/api/v1/ws'
- : 'wss://mempool.space/api/v1/ws';
+ return wsUrl(this.netName);
}
// Addresses worth watching: those holding coins (to catch spends) plus a