diff --git a/src/config.js b/src/config.js index 13de3e7..6346fba 100644 --- a/src/config.js +++ b/src/config.js @@ -1,9 +1,8 @@ -export const BEACON = "bchtest:qp8njaa9a3ahg7259s5qajnce526n0rttsq8qwx4jl"; -// TLD-certificate beacon (Decentralized.DNS/DESIGN-tld-registry.md §3). -// Distinct from the name BEACON so a client that only wants the TLD list can -// walk one address instead of every name-registration transaction. Chipnet. -// Scripthash (electrum encoding): c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8 -export const TLD_BEACON = "bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh"; +import { NETWORK } from "./lib/resolver-web.js"; +// Beacons of the active network (BNS_NETWORK; chipnet unless set). The table +// itself lives in lib/resolver-web.js — see the note there. +export const BEACON = NETWORK.beacon; +export const TLD_BEACON = NETWORK.tldBeacon; export const PREFIX = "BNS1"; export const TLD = ".bch"; export const BEACON_DUST_SAT = 600; diff --git a/src/gateway/public-gateway.mjs b/src/gateway/public-gateway.mjs index cbc29a1..a5e1bfd 100644 --- a/src/gateway/public-gateway.mjs +++ b/src/gateway/public-gateway.mjs @@ -28,7 +28,16 @@ import WebSocket from "ws"; // resolver-web.js lives at ../lib/, not alongside this file — the previous // `./resolver-web.js` import was broken (file was moved into lib/ but this // import wasn't updated). Fix while touching the file. -import { resolveName, buildIndex, normalizeName, connectAny, CHIPNET_ELECTRUM, TLD_BEACON_SCRIPTHASH } from "./resolver-web.js"; +import { resolveName, buildIndex, normalizeName, connectAny, NETWORK, requireBeacons } from "./resolver-web.js"; +// Everything chain-specific comes from the network table (BNS_NETWORK env; +// chipnet unless set). Refuse to start on a network whose beacons are unpinned. +requireBeacons(NETWORK); +const TLD_BEACON_SCRIPTHASH = NETWORK.tldBeaconScripthash; +// Public electrum servers that answer wallet queries (listunspent). Our own +// beacon-only indexers are filtered out by the table's beaconOnly pattern. +const FULL_ELECTRUM = NETWORK.electrum.filter((s) => !NETWORK.beaconOnly.test(s.url)); +// Sia bucket holding operator-provided hosting: //… +const HOSTING_BUCKET = NETWORK.hostingBucket; import { pickRecord, isSubdomainOf } from "./record-picker.js"; import { buildTldSnapshot } from "./tld-index.js"; import { verifyListing } from "./market-tx.js"; @@ -43,10 +52,7 @@ import { readFileSync as readFileSyncOracle } from "node:fs"; let _tldSnap = { at: 0, snap: null }; async function getTldSnapshot() { if (_tldSnap.snap && Date.now() - _tldSnap.at < 30000) return _tldSnap.snap; - const BNS_INDEXER_URLS = /silentmode\.st\/electrum|coinspectrum\.duckdns\.org:50011/; - const candidates = CHIPNET_ELECTRUM - .map((s) => (typeof s === "string" ? { url: s } : s)) - .filter((s) => !BNS_INDEXER_URLS.test(s.url)); + const candidates = FULL_ELECTRUM; let el; for (const s of candidates) { try { el = await connectAny([s], WebSocket); break; } catch { /* try next */ } @@ -131,7 +137,7 @@ function recoverSigner(sigB64, msg, likeAddress) { const digest = sha256.hash(utf8ToBin(msg)); const pub = secp256k1.recoverPublicKeyCompressed(sigBytes.slice(1), (sigBytes[0] - 27) & 3, digest); if (typeof pub === "string") return null; - const prefix = String(likeAddress || "bchtest:").split(":")[0] || "bchtest"; + const prefix = String(likeAddress || NETWORK.prefix + ":").split(":")[0] || NETWORK.prefix; const enc = encodeCashAddress({ prefix, type: "p2pkh", payload: ripemd160.hash(sha256.hash(pub)) }); return typeof enc === "string" ? enc : (enc?.address ?? null); } catch { return null; } @@ -139,8 +145,7 @@ function recoverSigner(sigB64, msg, likeAddress) { // One full-electrum call (beacon-only indexers don't serve listunspent). async function withFullElectrum(fn) { - const BNS_INDEXER_URLS = /silentmode\.st\/electrum|coinspectrum\.duckdns\.org:50011/; - const candidates = CHIPNET_ELECTRUM.map((s) => (typeof s === "string" ? { url: s } : s)).filter((s) => !BNS_INDEXER_URLS.test(s.url)); + const candidates = FULL_ELECTRUM; let el = null, lastErr = null; for (const s of candidates) { try { el = await connectAny([s], WebSocket); break; } catch (e) { lastErr = e; } } if (!el) throw new Error("no full electrum reachable: " + String(lastErr?.message || lastErr)); @@ -987,12 +992,8 @@ const server = http.createServer(async (req, res) => { if (scripthashes.length > 64) { res.writeHead(400); res.end(JSON.stringify({ error: "at most 64 scripthashes per request" })); return; } - // Skip beacon-only indexers (silentmode.st/electrum on 443, our own - // bns-indexer on :50011) — they don't implement listunspent. - const BNS_INDEXER_URLS = /silentmode\.st\/electrum|coinspectrum\.duckdns\.org:50011/; - const candidates = CHIPNET_ELECTRUM - .map((s) => (typeof s === "string" ? { url: s } : s)) - .filter((s) => !BNS_INDEXER_URLS.test(s.url)); + // Skip beacon-only indexers — they don't implement listunspent. + const candidates = FULL_ELECTRUM; let el, lastErr; for (const s of candidates) { try { el = await connectAny([s], WebSocket); break; } @@ -1218,7 +1219,7 @@ const server = http.createServer(async (req, res) => { // prefix as the on-chain owner address (chipnet = "bchtest", // mainnet = "bitcoincash"). The prefix comes from the owner // string itself so we don't have to hardcode chain. - const ownerPrefix = String(entry.owner).split(":")[0] || "bchtest"; + const ownerPrefix = String(entry.owner).split(":")[0] || NETWORK.prefix; const pubkeyHash = ripemd160.hash(sha256.hash(recovered)); const _enc = encodeCashAddress({ prefix: ownerPrefix, type: "p2pkh", payload: pubkeyHash }); // libauth returns { address } in newer versions and a bare string in @@ -1487,7 +1488,7 @@ const server = http.createServer(async (req, res) => { catch (e) { res.setHeader("content-type", "application/json"); res.writeHead(400); res.end(JSON.stringify({ error: e.message })); return; } const entry = (await getIndex()).get(name); if (!entry) { res.setHeader("content-type", "application/json"); res.writeHead(404); res.end(JSON.stringify({ error: `"${name}" not registered` })); return; } - const prefix = `bns/${name}/`; + const prefix = `${HOSTING_BUCKET}/${name}/`; // GET ...?src=live — a READ-ONLY view of wherever the name's on-chain // records say the site lives right now: a CLI-published bucket such as // bns/