aere-quantum/agents/proba-agent-ancora-testnet.mjs

74 lines
7.0 KiB
JavaScript

// Proba lantului ca martor al registrului unui agent, CAP LA CAP pe testnetul public 28001: capul unui registru real se noteaza pe
// AereNotary cu cheia de dezvoltator a testnetului, verificatorul AIP-23 publicat ii da finalitatea post-cuantica, iar momentul
// firstSeen devine ancora cu care verifyLedger prinde o intrare antedatata si o alta ramura. Refuza orice alt lant decat 28001
// (citeste eth_chainId). Cheia de dezvoltator se citeste din fisierul dat in AERE_TESTNET_KEY_FILE, in proces, si nu se tipareste.
// Scrie dovada (registrele, capul notarizat, ancorele, verdictele; nicio cheie privata) in dovezi-ancora-28001/.
// AERE_TESTNET_KEY_FILE=<fisier> AERE_VERIFY_PROOF=<verify-proof.mjs> node proba-agent-ancora-testnet.mjs [--rpc URL]
// Iesire 0 = toate cum trebuia; 1 = una rosie; 2 = NEMASURAT (fara cheie, fara verificator, lantul nu e 28001, finalitatea n-a venit)
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { definePolicy } from './agent-policy.mjs';
import { newAgentIdentity, openLedger, resumeLedger, verifyLedger } from './agent-ledger.mjs';
import { ledgerHeadEnvelope, notarizeHead, anchorsFromNotarizedHeads, NOTARI } from './agent-ancora.mjs';
import { incarcaEthers } from './x402/wallet.mjs';
const AICI = path.dirname(fileURLToPath(import.meta.url));
const argv = process.argv.slice(2); const RPC = argv.includes('--rpc') ? argv[argv.indexOf('--rpc') + 1] : 'https://testnet-rpc.aere.network';
const kf = process.env.AERE_TESTNET_KEY_FILE;
const DEV_VERIFY = path.resolve(AICI, '..', '..', 'verificator-falcon', 'verify-proof.mjs');
const VERIFY = process.env.AERE_VERIFY_PROOF || (fs.existsSync(DEV_VERIFY) ? DEV_VERIFY : '');
if (!kf || !fs.existsSync(kf)) { console.log('NEMASURAT: AERE_TESTNET_KEY_FILE nu numeste un fisier cu cheia de dezvoltator a testnetului'); process.exit(2); }
if (!VERIFY || !fs.existsSync(VERIFY)) { console.log('NEMASURAT: lipseste verificatorul AIP-23 (AERE_VERIFY_PROOF=<verify-proof.mjs>)'); process.exit(2); }
let ethers; try { ethers = incarcaEthers(); } catch (e) { console.log('NEMASURAT: ' + e.message); process.exit(2); }
const provider = new ethers.JsonRpcProvider(RPC);
const chainId = Number((await provider.getNetwork()).chainId);
if (chainId !== 28001) { console.log(`NEMASURAT: ${RPC} serveste lantul ${chainId}, nu 28001`); process.exit(2); }
let ok = 0, rau = 0; const cer = (c, ce, d = '') => { console.log(` ${c ? 'OK ' : 'RAU'} ${ce}${c || !d ? '' : ' -- ' + d}`); c ? ok++ : rau++; };
const acum = () => Math.floor(Date.now() / 1000);
const id = newAgentIdentity();
const { policy, policyHash } = definePolicy({ agentId: id.agentId, spend: { amount: '1000', windowSeconds: 3600 }, recipients: ['0xbbbb'] });
// intrarile 0 si 1 scrise acum 15 minute (ceasul registrului injectat), capul (seq 1) notarizat acum: firstSeen ~ acum
const T0 = acum() - 900; let t = T0; const ceas = () => t;
const L = openLedger({ identity: id, policy, policyHash, now: ceas });
L.record({ kind: 'payment', to: '0xbbbb', amount: '10' }); t += 5; L.record({ kind: 'payment', to: '0xbbbb', amount: '10' });
const inainte = L.export();
const cap = ledgerHeadEnvelope(inainte, { seq: 1 });
const n = await notarizeHead({ envelope: cap, rpc: RPC, keyFile: kf, ethers });
cer(n.ok && n.envelope.notarization.chainId === 28001 && n.envelope.notarization.notary === NOTARI[28001], `1. capul (seq 1) notarizat pe 28001${n.ok ? `: firstSeen ${n.envelope.notarization.firstSeen}, bloc ${n.envelope.notarization.block}` : ''}`, n.motiv);
if (!n.ok) { console.log(`\nagent-ancora-testnet: ${ok}/${ok + rau} cum trebuia`); process.exit(1); }
const notarizat = n.envelope;
// finalitatea post-cuantica vine la urmatoarea ancora certificata: se asteapta pana la 6 minute
let r = null; const start = Date.now();
while (Date.now() - start < 360000) {
r = await anchorsFromNotarizedHeads(inainte, [notarizat], { verifyProof: VERIFY, rpc: RPC, chain: 28001 });
if (r.stare !== 'NEMASURAT') break;
await new Promise((ok2) => setTimeout(ok2, 20000));
}
if (r.stare === 'NEMASURAT') { console.log('NEMASURAT: finalitatea post-cuantica nu a venit in 6 minute: ' + JSON.stringify(r.randuri)); process.exit(2); }
cer(r.stare === 'OK' && r.anchors.length === 1, `2. verificatorul AIP-23 publicat da finalitate post-cuantica si ancora ${r.anchors[0] ? `{seq ${r.anchors[0].seq}, at ${r.anchors[0].at}}` : ''} (dupa ${Math.round((Date.now() - start) / 1000)} s)`, JSON.stringify(r.randuri));
const anc = r.anchors;
cer(anc[0] && anc[0].at === notarizat.notarization.firstSeen, '2. momentul certificat post-cuantic = firstSeen citit din contract');
// dupa notarizare: o continuare cinstita (acum) si una ANTEDATATA (T0 + 50, sub firstSeen - 300), semnate cu cheia agentului
t = acum(); const cinstit = resumeLedger({ identity: id, policy, policyHash, ledger: inainte, now: ceas }); cinstit.record({ kind: 'payment', to: '0xbbbb', amount: '10' });
t = T0 + 50; const antedatat = resumeLedger({ identity: id, policy, policyHash, ledger: inainte, now: ceas }); antedatat.record({ kind: 'payment', to: '0xbbbb', amount: '10' });
const vC = verifyLedger(cinstit.export(), { policy, anchors: anc });
cer(vC.ok && vC.time.lowerBound === 'witnessed', '3. continuarea cinstita, cu ancora lantului: ok, marginea de jos "witnessed"', JSON.stringify(vC).slice(0, 200));
const vA0 = verifyLedger(antedatat.export(), { policy });
cer(vA0.ok, '3. MARTORUL MASURII: fara ancora, continuarea antedatata trece');
const vA = verifyLedger(antedatat.export(), { policy, anchors: anc });
cer(!vA.ok && /backdated/.test(vA.error || ''), '3. cu ancora lantului, continuarea antedatata e prinsa', JSON.stringify(vA).slice(0, 200));
// alta ramura a agentului: aceeasi sesiune, intrarea 1 diferita
t = T0; const ramura = openLedger({ identity: id, policy, policyHash, now: ceas }); ramura.record({ kind: 'payment', to: '0xbbbb', amount: '10' }); t += 5; ramura.record({ kind: 'payment', to: '0xbbbb', amount: '99' });
const rR = await anchorsFromNotarizedHeads(ramura.export(), [notarizat], { verifyProof: VERIFY, rpc: RPC, chain: 28001 });
cer(rR.stare === 'FAILED' && !verifyLedger(ramura.export(), { policy, anchors: anc }).ok, '4. o alta ramura nu are capul notarizat: FAILED, si verifyLedger o refuza cu ancora');
// dovada, fara nicio cheie privata
const D = path.join(AICI, 'dovezi-ancora-28001'); fs.mkdirSync(D, { recursive: true });
const zi = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
fs.writeFileSync(path.join(D, `ancora-agent-${zi}.json`), JSON.stringify({ v: 1, kind: 'aere-agent-ledger-anchor-evidence', network: 'eip155:28001', rpc: RPC, policy, policyHash,
ledgerBefore: inainte, notarizedHead: notarizat, anchors: anc, honest: cinstit.export(), backdated: antedatat.export(), otherBranch: ramura.export(),
verdicts: { honestWithAnchor: vC.ok, backdatedWithoutAnchor: vA0.ok, backdatedWithAnchor: vA.ok, backdatedError: vA.error, otherBranch: rR.stare } }, null, 1) + '\n');
console.log(`\nagent-ancora-testnet: ${ok}/${ok + rau} cum trebuia (dovada in dovezi-ancora-28001/ancora-agent-${zi}.json)`);
process.exitCode = rau ? 1 : 0;