/** * راستی‌آزمایی مستقل زنجیرهٔ معاملات تورنومنت بیتفا — بدون اعتماد به سرور. * * اجرا: node verify-chain.mjs (یا: bun verify-chain.mjs) * * چه می‌کند: * ۱) همهٔ معاملات را از API عمومی می‌گیرد (صفحه‌بندی‌شده). * ۲) زنجیرهٔ هش را از صفر خودش بازمحاسبه می‌کند و با chain_hash هر ردیف می‌سنجد. * ۳) هش سر زنجیره را با آخرین لنگر ثبت‌شده مقایسه می‌کند. * برای بررسی خود لنگر در برابر بلاک‌چین بیت‌کوین، فایل .ots همان لنگر را از صفحهٔ * شفافیت دانلود و با ابزار رسمی opentimestamps.org چک کنید: * ots verify --digest anchor-N.ots */ import { createHash } from 'node:crypto'; const API = 'https://bitfa.io/tournament/api/index.php'; const sha256 = (s) => createHash('sha256').update(s).digest('hex'); const canonical = (t) => ['v1', t.id, t.tournament_id, t.participant_id, t.order_id ?? '', t.position_id ?? '', t.market, t.side, t.action, t.leverage, t.price, t.ref_price ?? '', t.qty, t.quote_amount, t.fee, t.pnl ?? '', t.executed_at] .map((v) => String(v ?? '')).join('|'); let after = 0, prev = '', n = 0, bad = 0, committed = 0; for (;;) { const r = await fetch(`${API}/public/trades?after=${after}&limit=500`); const j = await r.json(); const rows = j.data?.trades || []; if (!rows.length) break; for (const t of rows) { if (t.revealed === false) { // commit–reveal: جزئیات هنوز مخفی است (پوزیشن باز و کمتر از ۳ ساعت). // هشِ تعهد همین حالا در زنجیره قفل است؛ بعد از افشا، اجرای دوبارهٔ همین // اسکریپت باید نشان دهد جزئیاتِ بازشده دقیقاً همین هش را می‌دهد. committed++; } else { const h = sha256(prev + '\n' + canonical(t)); if (h !== t.chain_hash) { console.error(`✖ ناسازگاری در معاملهٔ ${t.id}: محاسبه=${h.slice(0, 16)}… ثبت‌شده=${(t.chain_hash || '').slice(0, 16)}…`); bad++; if (bad > 5) { console.error('… متوقف شد'); process.exit(1); } } } prev = t.chain_hash; after = t.id; n++; } } console.log(`✔ ${n} معامله بررسی شد — زنجیره ${bad ? 'خراب' : 'سالم'} است` + (committed ? ` (${committed} تعهدِ در انتظار افشا — بعداً دوباره اجرا کنید)` : '')); console.log(` سر زنجیره: ${prev}`); const a = await fetch(`${API}/public/anchors`).then((r) => r.json()); const last = a.data?.anchors?.[0]; if (last) { console.log(` آخرین لنگر (${last.created_at} UTC): ${last.head_hash}`); console.log(last.head_hash === prev || last.head_id < after ? ' ✔ سر زنجیره با لنگر سازگار است (معاملات جدیدتر از لنگر طبیعی‌اند)' : ' ✖ سر زنجیره با لنگر نمی‌خواند!'); } process.exit(bad ? 1 : 0);