// Igneum light client, version zero, browser driver. Fetches /api/checkpoint and verifies it in this tab with // core.js, then fills the homepage card. Everything is computed here; the server only ships data. // Libraries, pinned: BLAKE2b from @noble/hashes 2.4.0, BLS12-381 from @noble/curves 2.4.0 (pure JavaScript, // served by jsdelivr as ES modules). import { blake2b } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/blake2.js/+esm'; import { bls12_381 } from 'https://cdn.jsdelivr.net/npm/@noble/curves@2.4.0/bls12-381.js/+esm'; import { verifyCheckpoint } from './core.js'; export const LIBRARIES = { '@noble/hashes': '2.4.0', '@noble/curves': '2.4.0' }; const deps = { blake2b, bls: bls12_381 }; export async function fetchCheckpoint(url = '/api/checkpoint') { const r = await fetch(url, { cache: 'no-store' }); let body = null; try { body = await r.json(); } catch { body = null; } if (!body) return { ok: false, error: `api answered ${r.status}` }; return body; } export function verify(data) { return verifyCheckpoint(data, deps); } // The homepage card. Cells carry data-lc="..." so the layout and classes stay as they are. const $ = sel => document.querySelector(sel); const pct = x => `${(x * 100).toFixed(1)}%`; export function renderCard(result, data) { const badge = $('[data-lc="badge"]'), badgeText = $('[data-lc="badge-text"]'); const cp = $('[data-lc="checkpoint"]'), proof = $('[data-lc="proof"]'), sys = $('[data-lc="system"]'), tab = $('[data-lc="tab"]'); const line = $('[data-lc="line"]'); if (!cp) return; if (proof) proof.textContent = 'not yet'; if (sys) sys.textContent = 'BLS aggregate, version 1'; if (result.verified) { const count = (window.__igneumVerified = (window.__igneumVerified || 0) + 1); cp.textContent = `${count} verified in this tab`; cp.title = `checkpoint ${result.index} on ${result.network}, block ${String(result.hash).slice(0, 12)}, ${result.headers_checked} headers checked`; tab.textContent = `${result.ms} ms · ${pct(result.weight_fraction_total)} of weight`; tab.title = `${result.signers} of ${result.voters} voters signed: ${pct(result.weight_fraction_active)} of active weight, ${pct(result.weight_fraction_total)} of total${result.weights_exact ? '' : ` (weights read at checkpoint ${result.weights_at_index})`}`; tab.style.color = ''; if (badgeText) badgeText.textContent = data.source === 'test' ? 'LIVE · test network' : 'LIVE'; if (badge) badge.classList.add('on'); if (line) line.textContent = data.source === 'test' ? `Checkpoint ${result.index} of the test network, certified by ${result.signers} miners. Verified here.` : `Checkpoint ${result.index}, certified by ${result.signers} miners. Verified here.`; } else { cp.textContent = 'could not verify'; cp.title = result.reason || ''; tab.textContent = result.reason ? result.reason : 'could not verify'; tab.style.color = 'var(--molten)'; if (badgeText) badgeText.textContent = 'PREVIEW'; if (badge) badge.classList.remove('on'); } } export async function run(url) { const data = await fetchCheckpoint(url); const result = verify(data); window.__igneumLightClient = { result, data }; renderCard(result, data); return result; } if (typeof document !== 'undefined' && document.querySelector('[data-lc="checkpoint"]')) { const start = () => run().catch(e => renderCard({ verified: false, reason: String(e.message || e) }, {})); if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start); else start(); }