deviant/scripts/chipnet-asm-parallel-test-genesis.mjs
Local Dev ced2eda48d @
chore: checkpoint in-flight work across domains

Sweep of accumulated uncommitted work on design/dex-p2p-architecture into
one checkpoint (multiple sessions share this tree). Main areas:

- anthemus: covenant-wiring follow-ups (engine, ExchangePanel), AgoraScreen seam
- spv: ServerPool + p2p header transport (pool.ts, core/spv/*), wallet.ts wiring
- walletconnect: responder/useConnect updates + connect-responder-compat test
- wallet: send-tier-a rework + swap.ts, plus send-tier-a unit tests
- asm: chipnet throughput/stress harness (scripts/chipnet-asm-*) + ASM_Native docs
- app UI: screens/* and shell.css touch-ups; sat -> bits copy migration
- docs: new snapshots (INDEX regenerated), Parameters (WalletConnect/SSH/ASM),
  KnowledgeBase, WALLET-COORDINATION changelog

Checkpoint only; not a release. Secrets (Keys/, .chipnet-keys*, .env) remain
gitignored and were verified absent from the staged set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-08-14 02:00:43 +02:00

97 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* chipnet-asm-parallel-test-genesis.mjs — the CORRECTED parallel ASM test.
*
* Prior test (chipnet-asm-parallel-test.mjs) used the SHARED-RESERVOIR claim path:
* every op spent the one reservoir UTXO → 1 accepted, N-1 rejected (contention).
* That contention is a property of the shared-reservoir DESIGN, not of BCH→MBA.
*
* This test uses the per-address model: each wallet SWAPS BCH → its OWN unique
* self-backed MBA via a CashToken genesis. The token category is derived from
* that wallet's own input[0] outpoint, so every tx spends a DIFFERENT UTXO and
* mints a DIFFERENT category. No shared state → N parallel broadcasts, N accepted,
* ZERO collisions — regardless of concurrent count.
*
* Each genesis output is self-backed: amount units carrying amount×RATE sats.
* Broadcast in parallel via Promise.all. No retries. Chipnet only.
*/
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { TestNetWallet } from 'mainnet-js';
const ROOT = join(import.meta.dirname, '..');
const WALLETS = (process.env.WALLETS ?? 'a,c,d,e').split(',').map((s) => s.trim().toLowerCase());
const UNITS = BigInt(process.env.UNITS ?? '100'); // FT units to mint
const RATE = BigInt(process.env.RATE ?? '1000'); // sats backing per unit (self-backed)
const BACKING = UNITS * RATE; // sats carried on the FT output
const KEYS = Object.fromEntries(['a', 'b', 'c', 'd', 'e', 'f', 'g'].map((w) => [
w, join(ROOT, w === 'a' ? '.chipnet-keys.json' : `.chipnet-keys-${w}.json`),
]));
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function main() {
// Load each wallet.
const wallets = [];
for (const w of WALLETS) {
const { wif } = JSON.parse(readFileSync(KEYS[w], 'utf8'));
wallets.push({ label: w.toUpperCase(), wallet: await TestNetWallet.fromWIF(wif) });
}
// tip at start (via the first wallet's provider)
let tip = 0;
try { tip = await wallets[0].wallet.provider.getBlockHeight(); } catch { /* best effort */ }
const batchISO = new Date().toISOString();
const t0 = Date.now();
console.log(`\nCONVERGENT-BY-DESIGN? NO. Each address mints its OWN unique MBA.`);
console.log(`Batch broadcast @ ${batchISO} (chipnet tip ${tip})`);
console.log(`Each: SWAP ${BACKING} sats BCH → ${UNITS} units of a NEW self-backed MBA (rate ${RATE})\n`);
// ── PARALLEL BROADCAST (Promise.all) — each is an independent genesis tx ──
const results = await Promise.all(wallets.map(async ({ label, wallet }) => {
const started = Date.now() - t0;
try {
const res = await wallet.tokenGenesis({
cashaddr: wallet.tokenaddr, // FT lands on this wallet's own token address
amount: UNITS, // fungible units
value: BACKING, // sats carried inside → self-backed MBA
});
const txid = res?.txId ?? res?.txid;
const category = (res?.tokenIds && res.tokenIds[0]) ?? '(unknown)';
return { label, started, txid, category, error: null };
} catch (e) {
return { label, started, txid: null, category: null, error: (e?.message ?? String(e)).slice(0, 200) };
}
}));
// ── STATUS POLL (5s) ──
await sleep(5000);
const prov = wallets[0].wallet.provider;
for (const r of results) {
if (!r.txid) { r.at5s = 'rejected-at-broadcast'; continue; }
try { await prov.getRawTransaction(r.txid); r.at5s = 'in-mempool/confirmed'; }
catch { r.at5s = 'not-found'; }
}
// ── REPORT ──
console.log(`=== Per-address parallel genesis (BCH → unique self-backed MBA) ===`);
console.log(`Batch timestamp: ${batchISO} Chipnet tip at start: ${tip}\n`);
console.log(`Wallet | Δms | new MBA category (tokenId) | TXID or error | 5s later`);
for (const r of results) {
console.log(`${r.label} | +${r.started} | ${r.category ?? '—'} | ${r.txid ?? 'ERR: ' + r.error} | ${r.at5s}`);
}
const accepted = results.filter((r) => r.txid).length;
const rejected = results.filter((r) => !r.txid).length;
const categories = results.filter((r) => r.category).map((r) => r.category);
const uniqueCats = new Set(categories).size;
console.log(`\nAccepted: ${accepted} Rejected: ${rejected} (of ${results.length})`);
console.log(`Distinct MBA categories minted: ${uniqueCats} / ${categories.length} (all unique = no collision)`);
if (rejected) { console.log('Rejection reasons:'); for (const r of results.filter((x) => !x.txid)) console.log(` ${r.label}: ${r.error}`); }
console.log(`\nInterpretation: ${accepted === results.length && uniqueCats === categories.length
? 'ALL parallel broadcasts accepted, every address minted a DISTINCT self-backed MBA — zero collisions. Per-address MBA generation has no shared contested UTXO.'
: 'See per-row results above.'}`);
}
main().then(() => process.exit(0)).catch((err) => { console.error('HARNESS ERROR:', err?.message ?? err); if (err?.stack) console.error(err.stack); process.exit(1); });