// Proves the BNS-only indexer serves the electrum protocol correctly, using REAL // chipnet data (no BCHN needed): pull the beacon history + txs from a public // electrum, seed the indexer, serve it locally, and confirm resolver-web resolves // a name through OUR indexer identically to the public server. Also unit-tests // scripthashOf + processTx against a real beacon transaction. import WebSocket from "ws"; import { resolveName, BEACON_SCRIPTHASH } from "../src/lib/resolver-web.js"; import { BeaconIndex, RpcSource, startElectrumWS, scripthashOf } from "../src/indexer/bns-indexer.js"; // Dial by IP + SNI (this machine's resolver daemon breaks Node getaddrinfo). const PUBLIC = { url: "wss://chipnet.bch.ninja:50004", ip: "135.148.236.244" }; const PUBLIC_IPURL = "wss://135.148.236.244:50004"; const PUBLIC_SNI = "chipnet.bch.ninja"; const NAME = "hello.bch"; const PORT = 50099; let failures = 0; const ok = (c, m) => { console.log((c ? " ✅ " : " ❌ ") + m); if (!c) failures++; }; // tiny electrum client function elClient(url, opts) { return new Promise((resolve, reject) => { const ws = new WebSocket(url, opts); let id = 0, buf = ""; const pending = new Map(); ws.on("open", () => resolve({ call(method, params = []) { return new Promise((res, rej) => { const i = ++id; pending.set(i, { res, rej }); ws.send(JSON.stringify({ id: i, method, params }) + "\n"); setTimeout(() => { if (pending.has(i)) { pending.delete(i); rej(new Error("timeout " + method)); } }, 20000); }); }, close() { ws.close(); }, })); ws.on("error", reject); const settle = (line) => { try { const m = JSON.parse(line); const p = pending.get(m.id); if (p) { pending.delete(m.id); m.error ? p.rej(new Error(JSON.stringify(m.error))) : p.res(m.result); } } catch {} }; ws.on("message", (d) => { buf += d.toString(); let nl; while ((nl = buf.indexOf("\n")) >= 0) { const line = buf.slice(0, nl).trim(); buf = buf.slice(nl + 1); if (line) settle(line); } const rest = buf.trim(); // some servers omit the trailing newline if (rest) { try { JSON.parse(rest); settle(rest); buf = ""; } catch {} } }); }); } console.log("1) pulling REAL beacon data from", PUBLIC.url, "(via IP", PUBLIC.ip + ") …"); const pub = await elClient(PUBLIC_IPURL, { servername: PUBLIC_SNI }); const history = await pub.call("blockchain.scripthash.get_history", [BEACON_SCRIPTHASH]); ok(Array.isArray(history) && history.length > 0, `beacon history fetched (${history.length} txs)`); const txMap = {}; for (const { tx_hash } of history) txMap[tx_hash] = await pub.call("blockchain.transaction.get", [tx_hash, true]); ok(Object.keys(txMap).length === history.length, `fetched all ${history.length} verbose txs`); // resolve the reference answer via the PUBLIC server (directIP → uses pinned ip) const reference = await resolveName(NAME, { WebSocket, electrum: [PUBLIC], directIP: true }); pub.close(); ok(!!reference, `${NAME} resolves on the public server (records: ${reference ? Object.keys(reference.records) : "—"})`); console.log("2) unit-testing scripthashOf + processTx on a real beacon tx …"); // find a real output that pays the beacon and check our scripthash math let matched = null; for (const tx of Object.values(txMap)) { for (const v of tx.vout || []) { if (v.scriptPubKey && v.scriptPubKey.hex && scripthashOf(v.scriptPubKey.hex) === BEACON_SCRIPTHASH) { matched = tx; break; } } if (matched) break; } ok(!!matched, "scripthashOf() reproduces the beacon scripthash from a real output"); const probe = new BeaconIndex(BEACON_SCRIPTHASH); ok(matched && probe.processTx(matched, 100) === true, "processTx() flags a real beacon tx as touching"); console.log("3) serving the SAME data through our indexer and resolving through it …"); const index = new BeaconIndex(BEACON_SCRIPTHASH); index.seed(history, txMap); const wss = startElectrumWS(index, { bind: "127.0.0.1", port: PORT }, null); // rpc=null: cache-only const mine = await resolveName(NAME, { WebSocket, electrum: [{ url: `ws://127.0.0.1:${PORT}` }] }); ok(!!mine, `${NAME} resolves through OUR indexer`); ok(mine && reference && JSON.stringify(mine.records) === JSON.stringify(reference.records), "records IDENTICAL to the public server"); ok(mine && reference && mine.category === reference.category, "token category matches"); wss.close(); console.log(failures === 0 ? "\n🎉 ALL PASSED — indexer is protocol-correct" : `\n💥 ${failures} check(s) failed`); process.exit(failures === 0 ? 0 : 1);