import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { Script, Tap, Tx } from '@cmdcode/tapscript'; import { LocalChain, tapscriptValid } from '../src/adapters/chain.js'; import { TestWallet } from '../src/adapters/wallet.js'; import { InscriptionAdapter, POSTAGE, FEE, envelope } from '../src/adapters/inscription.js'; import { MetadataIndex } from '../src/adapters/metadata-index.js'; import { getVin, getVout } from '../src/upstream/primitives.js'; import { census, rows } from '../src/orgchain/lineage.js'; import { ordClient, ordEvents, ordState } from '../src/indexer/ord.js'; import { compareWithLab } from '../src/indexer/compare.js'; // What ord answered after tools/regtest/rehearse.mjs, and the lab's public chain (tools/regtest/record.mjs). const fixture = JSON.parse(readFileSync(new URL('./fixtures/regtest-rehearsal.json', import.meta.url), 'utf8')); const replay = async url => { const hit = fixture.ord[new URL(url).pathname]; return new Response(hit?.body ?? '', { status: hit?.status ?? 404 }); }; const draw = (s, root) => rows(s, root).map(r => (r.type === 'group' ? `${r.guide}${r.label}` : `${r.guide}${r.path} ${r.node.name}${r.away ? ' · graduated' : ''}`)); const NUMS = ['OP_1', '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0']; const hex = script => Script.encode(script, false).hex; test('real ord indexed the regtest rehearsal, and the same reducer folds it into the trees the lab drew', async () => { const events = await ordEvents(ordClient('http://ord.test', replay), { from: fixture.from }); assert.equal(events.length, 26); assert.ok(events.every(e => e.protocol === 'lineage/v0' && e.parents <= 1 && /^[0-9a-f]{64}:\d+$/.test(e.location))); const s = ordState(events), id = name => [...s.nodes.values()].find(n => n.name === name).id; assert.ok(s.log.every(e => e.ok)); assert.deepEqual(s.roots.map(r => r.name), ['yolopreneur', 'lineage', 'acme']); assert.deepEqual(draw(s, id('yolopreneur')), ['● yolopreneur', '└─ orgs', " ├─ 0' well-known", ' │ └─ orgs', " │ ├─ 0' mailr", " │ └─ 1' lineage · graduated", " └─ 1' time", ' ├─ agents', " │ ├─ 0' luna", " │ ├─ 1' sol", " │ └─ 2' astra", ' └─ orgs', " ├─ 0' docscope", " ├─ 1' dollhouse", " ├─ 2' doodleloop", " └─ 3' hearthframe"]); assert.deepEqual(census(s, id('lineage')), { orgs: 0, agents: 0, belts: 0, decisions: 1, closed: 0 }); assert.deepEqual(s.nodes.get(id('scout')).badges.map(b => [b.skill, b.belt, s.nodes.get(b.by).name]), [['listen', 'white', 'well-known']]); assert.deepEqual([...s.items.values()].map(i => [i.name, s.nodes.get(i.maker).name]), [['launch-kit', 'sol']]); // Five keyrings, their proofs checked from ord's metadata (two 520-byte pushes each): lineage's first retired when it // graduated, and the one it published a block later stands. Four keyrings, four keys each, are bound. assert.deepEqual(s.log.filter(e => e.op === 'keyring').map(e => s.nodes.get(e.node).name), ['yolopreneur', 'sol', 'lineage', 'lineage', 'scout']); assert.deepEqual([...s.nodes.values()].filter(n => n.keyring).map(n => [n.name, n.keyring.retired]).sort(), [['lineage', null], ['scout', null], ['sol', null], ['yolopreneur', null]]); assert.equal(s.bound.size, 16); // Byte for byte: the same events in the same beats, the same metadata and parents, every inscription in the same // output (the launch kit where lineage's deal put it). Only the miner's order within blocks differs. const { problems, reordered } = compareWithLab({ chain: new LocalChain(fixture.chain) }, events); assert.deepEqual(problems, []); assert.equal(reordered, 9); }); test('a reveal commits to its exact script (BIP-341), and the lab still loads reveals made the old way', () => { const chain = new LocalChain(), w = TestWallet.create(); chain.mine(w.script); new InscriptionAdapter(chain, w).inscribe('found x', null, { op: 'found', name: 'x' }, { metaprotocol: 'lineage/v0' }); const prevout = raw => { const out = Tx.decode(raw).vout[0]; return { value: Number(out.value), scriptPubKey: out.scriptPubKey }; }; const reveal = Tx.decode(chain.mempool[1]); reveal.vin[0].prevout = prevout(chain.mempool[0]); assert.equal(tapscriptValid(reveal, 0), true); // Before v1.9 the leaf came from tapscript's encodeScript, which re-encodes the hex script; real Bitcoin rejected that. const old = new LocalChain(); old.mine(w.script); const [coin] = old.coins(w.script), script = envelope(w.pubkey, 'found y', null, { op: 'found', name: 'y' }, { metaprotocol: 'lineage/v0' }); const leaf = Tap.encodeScript(script), [tapkey, control] = Tap.getPubKey(w.pubkey, { target: leaf }); const commit = Tx.create({ vin: [getVin(coin.txid, coin.vout, coin.value, coin.scriptPubKey)], vout: [getVout(POSTAGE + FEE, ['OP_1', tapkey]), getVout(coin.value - POSTAGE - 2 * FEE, w.script)] }); commit.vin[0].witness = [w.sign(commit)]; const legacy = Tx.create({ vin: [getVin(Tx.util.getTxid(commit), 0, POSTAGE + FEE, ['OP_1', tapkey])], vout: [getVout(POSTAGE, w.script)] }); legacy.vin[0].witness = [w.sign(legacy, leaf, 0), Script.encode(script, false).hex, control]; const raws = [Tx.encode(commit).hex, Tx.encode(legacy).hex], check = Tx.decode(raws[1]); check.vin[0].prevout = prevout(raws[0]); assert.equal(tapscriptValid(check, 0), false); old.submitPackage(raws); // still accepted, so labs saved before v1.9 load assert.equal(new MetadataIndex(old).events.length, 1); }); test('a chain can start from coins imported from a real chain, and keeps them through a rebuild', () => { const chain = new LocalChain(), w = TestWallet.create(), coin = { txid: 'ab'.repeat(32), vout: 1, value: 2e8, script: hex(w.script) }; chain.importCoin(coin); assert.throws(() => chain.importCoin(coin), /already in this chain/); assert.throws(() => chain.importCoin({ ...coin, vout: 2, value: 51e8 }), /Invalid imported coin/); const id = new InscriptionAdapter(chain, w).inscribe('found x', null, { op: 'found', name: 'x' }, { metaprotocol: 'lineage/v0' }); chain.mine(NUMS); const copy = new LocalChain(chain.snapshot()); assert.deepEqual(copy.imports, [coin]); assert.deepEqual(copy.imported(coin.txid, 1), { value: 2e8, scriptPubKey: coin.script }); assert.deepEqual(new MetadataIndex(copy).events.map(e => [e.id, e.status]), [[id, 'confirmed']]); assert.equal(copy.coins(w.script).length, 2); // the reveal's postage and the commit's change });