// Proba verificatorului de plati (verifica-plati.mjs), fara retea: un RPC local care serveste raspunsurile INREGISTRATE de pe testnetul // 28001 pentru dosarul-dovada din dovezi-28001/ (inregistreaza-rpc.mjs), deci date reale de pe lant. Fiecare verificare are cazul ei // care trebuie sa o inroseasca, construit din datele reale schimbate intr-un singur loc. // node proba-verifica-plati.mjs iesire 0 = toate cum trebuia import fs from 'node:fs'; import path from 'node:path'; import http from 'node:http'; import { fileURLToPath } from 'node:url'; import { verificaPlati } from './verifica-plati.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const D = path.join(AICI, 'dovezi-28001'); const dovadaF = fs.readdirSync(D).filter((n) => n.startsWith('plati-agent-') && n.endsWith('.json')).sort().pop(); const inregF = fs.readdirSync(D).filter((n) => n.startsWith('rpc-inregistrat-') && n.endsWith('.json')).sort().pop(); let ok = 0, rau = 0; const cer = (c, ce) => { console.log((c ? ' OK ' : ' RAU ') + ce); c ? ok++ : rau++; }; if (!dovadaF || !inregF) { console.log(`NEMASURAT: lipseste dosarul-dovada sau inregistrarea RPC in ${D}`); process.exit(2); } const dovada = JSON.parse(fs.readFileSync(path.join(D, dovadaF), 'utf8')); const inreg = JSON.parse(fs.readFileSync(path.join(D, inregF), 'utf8')); const copie = (o) => JSON.parse(JSON.stringify(o)); // un RPC local peste inregistrare (sau peste o varianta schimbata a ei) async function rpcDin(rec) { const srv = http.createServer((req, res) => { let s = ''; req.on('data', (x) => { s += x; }); req.on('end', () => { const q = JSON.parse(s); let result = null; if (q.method === 'eth_chainId') result = rec.chainId; else if (q.method === 'eth_getTransactionReceipt') result = rec.receipts[String(q.params[0]).toLowerCase()] || null; else if (q.method === 'eth_getLogs') result = rec.transfersOut; res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ jsonrpc: '2.0', id: q.id, result })); }); }); await new Promise((r) => srv.listen(0, '127.0.0.1', r)); return { url: `http://127.0.0.1:${srv.address().port}`, close: () => srv.close() }; } async function judeca(dov, rec, allTransfers = true) { const r = await rpcDin(rec); try { return await verificaPlati(dov, { rpc: r.url, allTransfers }); } finally { r.close(); } } const pica = (v, re) => v.checks.some((c) => c.pass === false && re.test(c.name)); try { const v0 = await judeca(dovada, inreg); cer(v0.verdict === 'VALID' && v0.checks.every((c) => c.pass === true), `1. dosarul real, peste raspunsurile reale de pe 28001: VALID (${v0.checks.length} verificari)`); const tx1 = dovada.payments[1].transaction.toLowerCase(); const d2 = copie(dovada); d2.ledger.entries[dovada.payments[1].entrySeq].body.action.amount = '1'; cer(pica(await judeca(d2, inreg), /the ledger verifies/), '2. CONTROL: o suma schimbata in registru -> registrul nu mai verifica'); const d3 = copie(dovada); d3.payments[1].entryHash = 'ab'.repeat(32); cer(pica(await judeca(d3, inreg), /the entry is in the ledger/), '3. CONTROL: plata numeste o intrare care nu e in registru -> INVALID'); const d4 = copie(dovada); d4.wallet = '0x' + '11'.repeat(20); cer(pica(await judeca(d4, inreg, false), /allowed payment from the wallet/), '4. CONTROL: alt portofel decat cel din intrari -> INVALID'); const r5 = copie(inreg); r5.receipts[tx1].status = '0x0'; cer(pica(await judeca(dovada, r5), /status 1/), '5. CONTROL: chitanta cu status 0 -> INVALID'); const r6 = copie(inreg); for (const l of r6.receipts[tx1].logs) if (l.topics.length === 3 && l.topics[2] && !/^0x0{24}/.test(l.topics[2])) l.topics[2] = '0x' + 'cd'.repeat(32); cer(pica(await judeca(dovada, r6), /AuthorizationUsed/), '6. CONTROL: nonce-ul de pe lant nu e sha256(hash-ul intrarii) -> INVALID'); const r7 = copie(inreg); for (const l of r7.receipts[tx1].logs) if (l.data && l.data !== '0x') l.data = '0x' + (1n).toString(16).padStart(64, '0'); cer(pica(await judeca(dovada, r7), /Transfer\(wallet/), '7. CONTROL: suma din Transfer-ul de pe lant alta decat in intrare -> INVALID'); const r8 = copie(inreg); r8.transfersOut = [...r8.transfersOut, { ...r8.transfersOut[0], transactionHash: '0x' + 'ee'.repeat(32) }]; cer(pica(await judeca(dovada, r8), /every Transfer out of the wallet/), '8. CONTROL: un Transfer din portofel fara plata in registru -> INVALID'); const r9 = copie(inreg); r9.chainId = '0xaf0'; const v9 = await judeca(dovada, r9); cer(v9.verdict === 'UNMEASURED', `9. CONTROL: un RPC al altui lant (2800) -> ${v9.verdict}, nu VALID si nu INVALID`); const v10 = await verificaPlati(dovada, { rpc: 'http://127.0.0.1:9', allTransfers: true }); cer(v10.verdict === 'UNMEASURED', `10. CONTROL: un RPC care nu raspunde -> ${v10.verdict}`); } catch (e) { cer(false, `proba s-a oprit: ${String(e.message || e).slice(0, 160)}`); } console.log(`\nverifica-plati: ${ok}/${ok + rau} ${rau ? 'CU ESECURI' : 'cum trebuia'}`); process.exitCode = rau ? 1 : 0;