aboutsummaryrefslogtreecommitdiffstats
path: root/tools/electrum-ws.test.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-27 08:49:09 -0700
committerAdam Soltys <[email protected]>2026-06-27 08:49:09 -0700
commit1d0c1c9bfb9ccfb8a28e0cf147af12c37655cdcc (patch)
tree443c23a9320f4e1d494e51e2a13e6f3acaf4f426 /tools/electrum-ws.test.js
parenta9a903e7a1f80ed4a6f4163419b25d4e6de5db01 (diff)
downloadcoinosv3-1d0c1c9bfb9ccfb8a28e0cf147af12c37655cdcc.tar.gz
coinosv3-1d0c1c9bfb9ccfb8a28e0cf147af12c37655cdcc.zip
Regtest realtime via a local Electrum-over-WebSocket bridge
On regtest there's no realtime push (coinos watcher is mainnet-only), so the UI only updated on the 5–10s poll — a funded tx took a while to appear and a just-mined block stayed "pending" until the next reconcile. electrs speaks the Electrum protocol the watcher already understands, but only over TCP; route it through a small WS<->TCP bridge (see coinos-server/electrum-ws) so the wallet subscribes scripthashes and reconciles instantly on each notification. Data still comes from esplora; this only adds the push channel. Configurable in Settings (default ws://localhost:50003); falls back to polling if unreachable. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Diffstat (limited to 'tools/electrum-ws.test.js')
-rw-r--r--tools/electrum-ws.test.js44
1 files changed, 44 insertions, 0 deletions
diff --git a/tools/electrum-ws.test.js b/tools/electrum-ws.test.js
new file mode 100644
index 0000000..1d5b5d0
--- /dev/null
+++ b/tools/electrum-ws.test.js
@@ -0,0 +1,44 @@
+// Verify the regtest electrum-ws bridge gives realtime push: subscribe to an
+// address scripthash over ws://localhost:50003, fund it, expect a notification.
+// Run (stack + ews up): bun tools/electrum-ws.test.js
+import { $ } from 'bun';
+import { p2wpkh } from '@scure/btc-signer/payment';
+import * as btc from '@scure/btc-signer';
+import { secp256k1 } from '@noble/curves/secp256k1';
+import { sha256 } from '@noble/hashes/sha2';
+import { bytesToHex } from '@noble/hashes/utils';
+
+const REGTEST = { ...btc.TEST_NETWORK, bech32: 'bcrt' };
+const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+const bcli = (...a) => $`docker exec bc bitcoin-cli -regtest -rpcuser=admin1 -rpcpassword=123 ${a}`.text();
+
+const pub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey(), true);
+const pay = p2wpkh(pub, REGTEST);
+const sh = sha256(pay.script).reverse(); // electrum scripthash (reversed)
+const shHex = bytesToHex(sh);
+console.log('address', pay.address, '\nscripthash', shHex);
+
+const ws = new WebSocket('ws://localhost:50003');
+let gotInitial = false, gotPush = false;
+ws.onmessage = (ev) => {
+ for (const line of String(ev.data).split('\n')) {
+ if (!line.trim()) continue;
+ let m; try { m = JSON.parse(line); } catch { continue; }
+ if (m.id === 2) { gotInitial = true; console.log('subscribe ok (initial status:', m.result, ')'); }
+ if (m.method === 'blockchain.scripthash.subscribe') { gotPush = true; console.log('PUSH notification received:', JSON.stringify(m.params)); }
+ }
+};
+await new Promise((res, rej) => { ws.onopen = res; ws.onerror = rej; });
+ws.send(JSON.stringify({ id: 1, method: 'server.version', params: ['test', '1.4'] }) + '\n');
+ws.send(JSON.stringify({ id: 2, method: 'blockchain.scripthash.subscribe', params: [shHex] }) + '\n');
+
+await sleep(1500);
+if (!gotInitial) { console.log('FAIL — no subscribe response'); process.exit(1); }
+
+console.log('funding the address…');
+await bcli('-rpcwallet=coinos', 'sendtoaddress', pay.address, '0.005');
+await bcli('generatetoaddress', '1', (await bcli('-rpcwallet=coinos', 'getnewaddress')).trim());
+
+for (let i = 0; i < 20 && !gotPush; i++) await sleep(500);
+console.log(gotPush ? '\nPASS — realtime push delivered over the WS bridge' : '\nFAIL — no push within timeout');
+process.exit(gotPush ? 0 : 1);