From 90eb381d6610ab5ee456aefa83f6d8aaf5abcb7b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 7 Oct 2026 08:12:29 -0700 Subject: bolt12-test: committed regtest offer/invoice fixtures instead of a vanished scratchpad The default fixture paths pointed into an old session's scratchpad, so the test died reading them (exit 1, no output). Fresh pair from the regtest stack: offer from clc, invoice fetched by cln-ark. Network and expiry checks no longer assume mainnet or a recent wall clock. Co-Authored-By: Claude Opus 5.5 --- tools/bolt12-test.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'tools/bolt12-test.js') diff --git a/tools/bolt12-test.js b/tools/bolt12-test.js index 28909d3..ab5109a 100644 --- a/tools/bolt12-test.js +++ b/tools/bolt12-test.js @@ -1,6 +1,7 @@ // BOLT 12 decode + signature verification against a REAL offer/invoice pair // (fetched from a live CLN via fetchinvoice) plus tamper checks. // Run: bun tools/bolt12-test.js [offer-file invoice-file] +// Default fixtures: regtest clc offer, invoice fetched by cln-ark for 12345 msat. import { readFileSync } from 'node:fs'; import { decodeOffer, decodeBolt12Invoice, verifyOfferInvoice, encodeBech32Raw, decodeBech32Raw, @@ -14,8 +15,9 @@ const check = (name, ok, detail = '') => { const throws = (fn) => { try { fn(); return null; } catch (e) { return e.message; } }; const [offerFile, invoiceFile] = process.argv.slice(2); -const offerStr = readFileSync(offerFile || '/tmp/claude-1000/-home-adam-coinosv3/556b3f05-c728-4e11-a426-50382ad8bd8d/scratchpad/fixture-offer.txt', 'utf8').trim(); -const invStr = readFileSync(invoiceFile || '/tmp/claude-1000/-home-adam-coinosv3/556b3f05-c728-4e11-a426-50382ad8bd8d/scratchpad/fixture-invoice.txt', 'utf8').trim(); +const fixture = (name) => new URL(`fixtures/${name}`, import.meta.url).pathname; +const offerStr = readFileSync(offerFile || fixture('bolt12-offer.txt'), 'utf8').trim(); +const invStr = readFileSync(invoiceFile || fixture('bolt12-invoice.txt'), 'utf8').trim(); console.log('[codec]'); const rt = decodeBech32Raw(invStr); @@ -25,7 +27,7 @@ check('bech32 roundtrips', encodeBech32Raw('lni', rt.bytes) === invStr.toLowerCa console.log('\n[offer]'); const offer = decodeOffer(offerStr); check('decodes', !!offer.records.length, `${offer.records.length} records`); -check('mainnet', offer.network === 'mainnet'); +check('network known', ['mainnet', 'testnet', 'signet', 'regtest'].includes(offer.network), offer.network); check('describes itself', typeof offer.description === 'string', offer.description); console.log('\n[invoice]'); @@ -34,7 +36,8 @@ check('payment hash present', /^[0-9a-f]{64}$/.test(inv.paymentHash || ''), inv. check('amount = 12345 msat', inv.amountMsat === 12345n, String(inv.amountMsat)); check('amount rounds up to 13 sat', inv.amountSat === 13); check('signer named', /^[0-9a-f]{66}$/.test(inv.nodeId || ''), inv.nodeId); -check('expiry sane', inv.expiresAt > Date.now() - 86400_000, new Date(inv.expiresAt).toISOString()); +check('same network as the offer', inv.network === offer.network, inv.network); +check('expiry sane', inv.expiresAt > inv.createdAt * 1000, new Date(inv.expiresAt).toISOString()); console.log('\n[verification]'); check('real invoice verifies', throws(() => verifyOfferInvoice(offer, inv)) === null, -- cgit v1.2.3