diff options
| -rw-r--r-- | tools/electrum-ws.test.js | 66 |
1 files changed, 39 insertions, 27 deletions
diff --git a/tools/electrum-ws.test.js b/tools/electrum-ws.test.js index 1d5b5d0..f743819 100644 --- a/tools/electrum-ws.test.js +++ b/tools/electrum-ws.test.js @@ -1,6 +1,9 @@ // 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 +// Run (stack + ews up): bun test tools/electrum-ws.test.js +// Integration test: skips (with a note) when no bridge listens on :50003 — the +// WS<->TCP bridge (coinos-server/electrum-ws) in front of a regtest electrs. +import { test, expect } from 'bun:test'; import { $ } from 'bun'; import { p2wpkh } from '@scure/btc-signer/payment'; import * as btc from '@scure/btc-signer'; @@ -8,37 +11,46 @@ import { secp256k1 } from '@noble/curves/secp256k1'; import { sha256 } from '@noble/hashes/sha2'; import { bytesToHex } from '@noble/hashes/utils'; +const URL = 'ws://localhost:50003'; 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); +// open the socket up front so an absent bridge becomes a skip, not a failure +const ws = await new Promise((res) => { + const s = new WebSocket(URL); + const t = setTimeout(() => { s.close(); res(null); }, 3000); + s.onopen = () => { clearTimeout(t); res(s); }; + s.onerror = () => { clearTimeout(t); res(null); }; +}); +if (!ws) console.log(`SKIP: no Electrum-over-WebSocket bridge at ${URL} (start the regtest ews bridge to run this)`); -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'); +test.skipIf(!ws)('realtime scripthash push over the WS bridge', async () => { + const pub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey(), true); + const pay = p2wpkh(pub, REGTEST); + const shHex = bytesToHex(sha256(pay.script).reverse()); // electrum scripthash (reversed) + console.log('address', pay.address, '\nscripthash', shHex); -await sleep(1500); -if (!gotInitial) { console.log('FAIL — no subscribe response'); process.exit(1); } + 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)); } + } + }; + 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'); -console.log('funding the address…'); -await bcli('-rpcwallet=coinos', 'sendtoaddress', pay.address, '0.005'); -await bcli('generatetoaddress', '1', (await bcli('-rpcwallet=coinos', 'getnewaddress')).trim()); + await sleep(1500); + expect(gotInitial).toBe(true); -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); + 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); + ws.close(); + expect(gotPush).toBe(true); +}, 30000); |
