igneum/site/block.html
igneum-josh 99cb0dee4a site: the simple nav, the miner and app pages, the live devnet redrawn, one design system for every page (not deployed)
Nav sitewide: Litepaper, Miner, App, Wallet, Live devnet, Ledger and the
Download button; the rest in the sheet and the footer. /miner is the
product page for the installers: the shipped app in its frame, the card
picker with the live time to a block, the downloads with sizes, HiveOS,
the fee in full view, three real shots. /app is new: the Igneum Ember app
page by page (Overview, Cards with Ember, the chain drawn live by the
module the app ships, Earnings, Prove, Settings, phone width, what keeps
it mining), light and dark, every shot a real capture or a render from
the RTX 5090 Windows rig's live state with the hostname painted out.
/live is redrawn to show the system working: the step scene, six live
cells, finality in plain words, miner lanes, provers paid, recent blocks
landing, the light client in one line, the DAG below. site.css carries
the shared product components (frames, download list, lines, your-card
line, phone download bar); yourcard.js reads the network rate. The
ledger and wallet pages no longer overflow at 390 px.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 08:44:15 +01:00

287 lines
27 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Igneum block</title>
<meta name="description" content="One Igneum block: header, parents, mergeset, transactions, proof records and, when it is a checkpoint, its finality certificate.">
<link rel="canonical" href="https://igneum.network/block">
<meta name="robots" content="noindex">
<meta name="theme-color" content="#0C0C0E">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Igneum">
<meta property="og:title" content="Igneum block">
<meta property="og:description" content="One Igneum block: header, parents, mergeset, transactions, proof records and its finality certificate.">
<meta property="og:url" content="https://igneum.network/block">
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Igneum block">
<meta name="twitter:description" content="One Igneum block: header, parents, mergeset, transactions, proof records and its finality certificate.">
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
<link rel="icon" href="/favicon.ico" sizes="48x48">
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
<link rel="manifest" href="/site.webmanifest">
<!-- head:start -->
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/site.css">
<style>
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
</style>
<script>
/* theme before first paint: the footer control stores "light" or "dark" under igneum-theme; nothing stored means the system setting */
(function(){try{var t=localStorage.getItem("igneum-theme");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t);}catch(e){}})();
</script>
<!-- head:end -->
<style>
/* page block; tokens, type and components are in /site.css */
/* the explorer pages share this block with block.html and address.html; same tokens as live.html */
--card-pad:clamp(18px,3vw,28px);--card-r:18px;--tile-pad:18px 20px;--tile-r:14px;--gap:24px;--gap-tile:12px;
--fs-h1:clamp(32px,5.5vw,56px);--fs-h3:clamp(18px,2vw,22px);--fs-tile:clamp(20px,2.2vw,26px)}
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--ember);outline-offset:3px;border-radius:6px}
.mono{font-family:var(--f-mono)}
h1,h2{font-family:var(--f-display);margin:0;line-height:1.08;text-wrap:balance}
.head{padding-block:var(--head) var(--gap);display:flex;flex-direction:column;gap:14px}
.head p{color:var(--ink-2);max-width:64ch;font-size:16px}
.search{display:flex;gap:10px;max-width:760px;margin-top:4px}
.search input{flex:1;min-width:0;min-height:48px;padding:10px 14px;border-radius:10px;border:1px solid var(--line-2);background:var(--graphite);color:var(--bone);font:500 15px/1.3 var(--f-mono)}
.search input::placeholder{color:var(--ash)}
.btn.primary:hover{background:#FF6A2B;border-color:#FF6A2B;color:var(--ember-ink)}
.msg{font-family:var(--f-mono);font-size:13px;color:var(--molten);min-height:18px}
.strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--gap-tile)}
@media (max-width:700px){.strip{grid-template-columns:repeat(2,minmax(0,1fr))}}
.cell{background:var(--graphite);border:1px solid var(--line);border-radius:var(--tile-r);padding:var(--tile-pad);display:flex;flex-direction:column;gap:6px;min-width:0}
.cell .k{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash)}
.cell .v{font-family:var(--f-display);font-weight:700;font-size:var(--fs-tile);line-height:1.1;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cell .v small{font-family:var(--f-mono);font-weight:500;font-size:13px;color:var(--ash);margin-left:4px;letter-spacing:.04em}
@media (max-width:700px){.cell .v{font-size:19px}}
.cell .s{font-family:var(--f-mono);font-size:12px;color:var(--ash);text-wrap:balance}
.cell.status .v{display:flex;align-items:center;gap:10px}
.off .dot{background:var(--ash);animation:none}.off .cell.status .v{color:var(--ash)}.on .cell.status .v{color:var(--molten)}
@media (prefers-reduced-motion:reduce){.dot{animation:none}}
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
tbody tr:hover td{background:rgba(255,255,255,.025)}
.id{font-family:var(--f-mono);color:var(--molten)}
.hash{font-family:var(--f-mono)}
.sw.chain{background:var(--ember);border-color:var(--blue)}.sw.blue{background:rgba(92,184,255,.7);border-color:var(--blue)}.sw.red{background:linear-gradient(45deg,transparent 44%,var(--ash) 44%,var(--ash) 56%,transparent 56%) center/8px 8px no-repeat}
.chip{display:inline-block;font-family:var(--f-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:3px 8px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin-right:6px}
.chip.hot{border-color:var(--molten);color:var(--molten)}.chip.ok{border-color:var(--green);color:var(--green)}
dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 20px;margin:12px 0 0;font-size:14px}
dt{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash);padding-top:3px}
dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
@media (max-width:640px){dl{grid-template-columns:1fr;gap:2px 0}dd{margin-bottom:8px}}
.two{display:grid;gap:var(--gap);grid-template-columns:1fr}
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
.two-wrap{margin-top:var(--gap)}
main{padding-bottom:var(--sec)}
</style>
</head>
<body>
<!-- nav:start -->
<a class="skip" href="#main">Skip to content</a>
<nav class="nav" aria-label="Main">
<div class="wrap">
<a href="/" class="brand" aria-label="Igneum home">
<svg class="mark" viewBox="0 0 1024 1024" width="28" height="28" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
<span class="word">IGNEUM</span>
</a>
<div class="links" id="nav-links">
<a href="/litepaper" data-nav="litepaper">Litepaper</a>
<a href="/miner" data-nav="miner">Miner</a>
<a href="/app" data-nav="app">App</a>
<a href="/wallet" data-nav="wallet">Wallet</a>
<a href="/live" data-nav="live" aria-current="page">Live devnet</a>
<a href="/ledger" data-nav="ledger">Ledger</a>
</div>
<a href="/miner#get" class="btn primary small cta">Download</a>
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Menu"><span class="bars"></span></button>
<div class="nav-sheet" id="nav-sheet">
<a href="/litepaper" data-nav="litepaper">Litepaper</a>
<a href="/miner" data-nav="miner">Miner</a>
<a href="/app" data-nav="app">App</a>
<a href="/wallet" data-nav="wallet">Wallet</a>
<a href="/live" data-nav="live">Live devnet</a>
<a href="/ledger" data-nav="ledger">Ledger</a>
<a href="/bench" data-nav="bench">Engineering log</a>
<a href="/evidence" data-nav="evidence">Evidence</a>
<a href="/explorer">Explorer</a>
<a href="https://github.com/igneum-network/spec" rel="noopener">GitHub</a>
<a href="/miner#get" class="btn primary">Download the miner</a>
</div>
</div>
</nav>
<script>
(function(){
// the menu: open on the button, closed by any link, Escape (focus back on the button) or a resize past 900 px
var n=document.querySelector('.nav'),b=document.getElementById('nav-burger'),s=document.getElementById('nav-sheet');if(!n||!b||!s)return;
function set(o){n.classList.toggle('open',o);b.setAttribute('aria-expanded',o?'true':'false');document.documentElement.style.overflow=o?'hidden':'';}
b.addEventListener('click',function(){set(!n.classList.contains('open'));});
s.addEventListener('click',function(e){if(e.target.closest('a'))set(false);});
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('open')){set(false);b.focus();}});
var mq=window.matchMedia('(min-width:901px)');if(mq.addEventListener)mq.addEventListener('change',function(){set(false);});
})();
</script>
<!-- nav:end -->
<main id="main" class="wrap">
<div class="head">
<div class="eyebrow"><a href="/explorer">Explorer</a> · block</div>
<h1 class="hash" id="title">Block</h1>
<div id="chips"></div>
<div class="msg" id="msg" aria-live="polite"></div>
</div>
<div id="body" hidden>
<div class="two two-wrap">
<div class="card"><div class="viz-head"><h2>Summary</h2></div><dl id="summary"></dl></div>
<div class="card"><div class="viz-head"><h2>Header</h2></div><dl id="header"></dl></div>
</div>
<div class="two two-wrap">
<div class="card"><div class="viz-head"><h2>Parents</h2><div class="eyebrow" id="parents-n"></div></div><div id="parents"></div><div class="viz-head" style="margin-top:18px"><h2>Children</h2><div class="eyebrow">seen within 10 min</div></div><div id="children"></div></div>
<div class="card"><div class="viz-head"><h2>Mergeset</h2><div class="eyebrow">what this block merges</div></div><div id="mergeset"></div><p class="note">A chain block merges the blocks in its past that no earlier chain block merged. Blue ones are paid by this block's coinbase; red ones are excluded from the order and their reward goes to this block's miner.</p></div>
</div>
<div class="card"><div class="viz-head"><h2>Transactions</h2><div class="eyebrow" id="tx-n"></div></div><div id="coinbase"></div><div class="tbl" id="txs"></div></div>
<div class="card"><div class="viz-head"><h2>Proof records and shards</h2><div class="eyebrow" id="proof-eyebrow"></div></div><div id="proofs"></div></div>
<div class="card"><div class="viz-head"><h2>Finality</h2><div class="eyebrow" id="fin-eyebrow"></div></div><div id="finality"></div></div>
</div>
</main>
<!-- footer:start -->
<footer class="foot">
<div class="wrap">
<div class="foot-grid">
<div class="foot-brand">
<a href="/" class="brand" aria-label="Igneum home"><svg class="mark" viewBox="0 0 1024 1024" width="26" height="26" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span></a>
<p>Mined by GPUs. Proven by fire.</p>
</div>
<nav class="foot-col" aria-label="Read">
<div class="eyebrow">Read</div>
<a href="/litepaper">Litepaper</a>
<a href="/litepaper#limits">What Igneum does not claim</a>
<a href="/litepaper#randomx">Igneum vs RandomX</a>
<a href="/litepaper#shoulders">Built on the shoulders</a>
<a href="/bench">Engineering log</a>
<a href="/evidence">Evidence</a>
<a href="/ledger">Ledger: every criticism</a>
</nav>
<nav class="foot-col" aria-label="Run">
<div class="eyebrow">Run</div>
<a href="/miner">The miner</a>
<a href="/app">The app</a>
<a href="/wallet">The wallet</a>
<a href="/miners">GPU bench table</a>
<a href="/miner#fee">The dev fee</a>
<a href="/faucet">Testnet faucet</a>
</nav>
<nav class="foot-col" aria-label="Follow">
<div class="eyebrow">Follow</div>
<a href="/live">Live devnet</a>
<a href="/explorer">Explorer</a>
<a href="/litepaper#roadmap">Journey</a>
<a href="/metamask">Add Igneum to MetaMask</a>
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
<a href="/miner#get">Miner downloads: devnet build</a>
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
</nav>
</div>
<div class="foot-base">
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
<span class="theme" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></span>
<span class="mono">igneum.network</span>
</div>
</div>
</footer>
<script>
(function(){
// theme control: stores light or dark under igneum-theme; system clears it. The head applied the stored value before paint.
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
function cur(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
function paint(){var c=cur();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});}
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}
if(v==='system')document.documentElement.removeAttribute('data-theme');else document.documentElement.setAttribute('data-theme',v);paint();});});
paint();
})();
</script>
<!-- footer:end -->
<script type="module">
import { ign, ignFromWei, shortHash, rel, int, utc } from '/lib/explorer.mjs';
const $ = id => document.getElementById(id);
const esc = s => String(s ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const link = h => `<a class="hash" href="/block/${esc(h)}" title="${esc(h)}">${esc(shortHash(h, 12, 8))}</a>`;
const addr = a => a ? `<a class="hash" href="/address/${esc(a)}">${esc(a)}</a>` : 'n/a';
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
const id = decodeURIComponent(location.pathname.split('/').pop() || '');
const query = /^\d{1,12}$/.test(id) ? 'height=' + id : 'block=' + encodeURIComponent(id.replace(/^0x/i, ''));
async function load() {
const r = await fetch('/api/explorer?' + query); const j = await r.json();
if (!j.ok) { $('msg').textContent = j.error || 'Not found.'; $('title').textContent = /^\d/.test(id) ? 'Chain block ' + id : shortHash(id, 10, 8); return; }
const b = j.block, d = b.detail || {}, now = new Date(j.now).getTime();
document.title = `Igneum block ${shortHash(b.hash, 8, 6)}`;
$('title').textContent = b.hash;
const chips = [b.chain ? '<span class="chip hot">chain block</span>' : `<span class="chip">${esc(b.color)}</span>`];
if (j.checkpoint) chips.push(`<span class="chip ${j.checkpoint.state === 'locked' ? 'ok' : ''}">checkpoint ${j.checkpoint.index}, ${esc(j.checkpoint.state)}</span>`);
if (b.proof_records) chips.push(`<span class="chip">${b.proof_records} proof record${b.proof_records === 1 ? '' : 's'}</span>`);
if (b.tx_count) chips.push(`<span class="chip">${b.tx_count} transaction${b.tx_count === 1 ? '' : 's'}</span>`);
$('chips').innerHTML = chips.join('');
$('summary').innerHTML = dl([
['Number', b.number === null ? '<span style="color:var(--ash)">none, not a chain block</span>' : int(b.number)],
['Time', `${utc(b.ts)} <span style="color:var(--ash)">(${rel(now - b.ts)})</span>`],
['DAA score', int(b.daa)], ['Blue score', int(b.blue_score)],
['Miner', addr(b.evm_miner)], ['Coinbase address', addr(b.miner)],
['Vote key', `<span class="id">${esc(b.miner_id || 'n/a')}</span> <span class="hash" style="color:var(--ash);font-size:12px">${esc(b.vote_key_hash || '')}</span>`],
b.engine ? ['Engine', esc(b.engine)] : null,
['Difficulty', d.difficulty ? int(d.difficulty) : 'n/a'],
['Declared subsidy', b.subsidy_sompi ? `${ign(b.subsidy_sompi, 8)} IGN <span style="color:var(--ash)">E(DAA) of spec 2.5, paid when a later chain block merges this one</span>` : 'n/a'],
['Coinbase paid', b.paid_sompi ? `${ign(b.paid_sompi, 8)} IGN <span style="color:var(--ash)">to the blocks it merges</span>` : 'n/a'],
['Merged by', b.chain ? 'itself (chain block)' : (j.merged_by ? link(j.merged_by) : '<span style="color:var(--ash)">not yet</span>')],
['Selected parent', b.selected_parent ? link(b.selected_parent) : 'n/a'],
]);
$('header').innerHTML = dl([
['Hash', `<span class="hash">${esc(b.hash)}</span>`], ['Version', esc(d.version)], ['Bits', esc(d.bits)], ['Nonce', `<span class="hash">${esc(d.nonce)}</span>`],
['Blue work', `<span class="hash">${esc(d.blue_work)}</span>`], ['Hash merkle root', `<span class="hash">${esc(d.hash_merkle_root)}</span>`],
['Accepted id merkle root', `<span class="hash">${esc(d.accepted_id_merkle_root)}</span>`], ['UTXO commitment', `<span class="hash">${esc(d.utxo_commitment)}</span>`],
['Pruning point', `<span class="hash">${esc(d.pruning_point)}</span>`], ['Parent levels', esc(d.parents_by_level ?? 'n/a')],
]);
$('parents-n').textContent = `${b.parent_hashes.length} at level 0`;
$('parents').innerHTML = b.parent_hashes.length ? '<div class="hash" style="display:flex;flex-direction:column;gap:6px">' + b.parent_hashes.map(link).join('') + '</div>' : '<div class="empty">Genesis has no parents.</div>';
$('children').innerHTML = j.children.length ? '<div class="hash" style="display:flex;flex-direction:column;gap:6px">' + j.children.map(link).join('') + '</div>' : '<div class="empty">No child seen yet.</div>';
const ms = d.mergeset || { blues: [], reds: [] };
$('mergeset').innerHTML = (ms.blues.length || ms.reds.length) ? `<div style="display:flex;flex-direction:column;gap:6px">${ms.blues.map(h => `<div><i class="sw blue"></i>${link(h)}</div>`).join('')}${ms.reds.map(h => `<div><i class="sw red"></i>${link(h)}</div>`).join('')}</div>` : '<div class="empty">Empty.</div>';
const cb = d.coinbase;
$('tx-n').textContent = `${b.tx_count ?? 0} EVM, 1 coinbase`;
$('coinbase').innerHTML = cb ? `<dl>${dl([['Coinbase', `<span class="hash">${esc(cb.id)}</span>`], ['Outputs', cb.outputs.map(o => `${o.pool ? '<span style="color:var(--ash)">proving pool (burns on the UTXO side, credited on the EVM side)</span>' : addr(o.address)} <b>${ign(o.value, 8)} IGN</b>`).join('<br>') || 'none'], ['Carries', `${cb.records} proof record${cb.records === 1 ? '' : 's'}${cb.reveal ? ', a key reveal' : ''}${(d.certificates || []).length ? `, certificate ${d.certificates.join(', ')}` : ''}`]])}</dl>` : '<div class="empty">No coinbase decoded.</div>';
const txs = d.txs || []; const ev = j.evm && j.evm.transactions ? new Map(j.evm.transactions.map(t => [t.hash, t])) : null;
$('txs').innerHTML = txs.length ? `<table><thead><tr><th>Transaction</th><th>From</th><th>To</th><th class="n">Value</th><th class="n">Bytes</th></tr></thead><tbody>${txs.map(t => { const e = ev && ev.get(t.hash); return `<tr id="tx-${esc((t.hash || '').replace(/^0x/, ''))}"><td class="hash">${esc(t.hash || '?')}</td><td>${e ? addr(e.from) : '<span style="color:var(--ash)">needs an EVM RPC</span>'}</td><td>${e ? addr(e.to) : ''}</td><td class="n">${e ? ignFromWei(e.value) + ' IGN' : ''}</td><td class="n">${t.size ?? ''}</td></tr>`; }).join('')}</tbody></table>` : '<div class="empty" style="margin-top:8px">No EVM transactions in this block.</div>';
if (j.evm && !j.evm.error) $('txs').insertAdjacentHTML('beforeend', `<p class="note">EVM view of this chain block: gas used ${int(j.evm.gas_used)}, state root <span class="hash">${esc(shortHash(j.evm.state_root, 10, 6))}</span>${j.evm.igneum ? `, rewards ${j.evm.igneum.rewards.map(r => ignFromWei(r.wei) + ' IGN to ' + shortHash(r.miner, 6, 4)).join(', ')}, proving pool credit ${ignFromWei(j.evm.igneum.proving_pool_credit)} IGN` : ''}.</p>`);
const sh = j.shards;
$('proof-eyebrow').textContent = b.chain ? `${sh.length} shard${sh.length === 1 ? '' : 's'} planned for this chain block` : 'not a chain block';
$('proofs').innerHTML = `<p style="font-size:14px;color:var(--ink-2)">This block carries <b>${b.proof_records ?? 0}</b> proof record${b.proof_records === 1 ? '' : 's'} for earlier chain blocks (274 bytes each, in the coinbase extra data).</p>` +
(sh.length ? `<div class="tbl"><table><thead><tr><th class="n">Shard</th><th>State</th><th>Prover</th><th class="n">pgas</th><th class="n">Proof lag, DAA</th><th>Carried by</th><th class="n">Payout</th></tr></thead><tbody>${sh.map(s => `<tr><td class="n">${s.i} of ${s.n}</td><td><span class="chip ${s.state === 'paid' ? 'ok' : s.state === 'verified' ? 'hot' : ''}">${esc(s.state)}</span></td><td class="id">${esc(s.prover || '')}</td><td class="n">${int(s.pgas)}</td><td class="n">${s.lag === null ? '' : int(s.lag)}</td><td>${s.carried_by ? link(s.carried_by) : ''}</td><td class="n">${s.payout_wei ? ignFromWei(s.payout_wei, 6) + ' IGN' : ''}</td></tr>`).join('')}</tbody></table></div>` : (b.chain ? '<div class="empty">No shard plan recorded (the proving feed was not reading this block).</div>' : ''));
const cp = j.checkpoint, certs = j.certificates || [];
$('fin-eyebrow').textContent = cp ? `checkpoint ${cp.index}` : (certs.length ? 'carries a certificate' : 'not a checkpoint');
$('finality').innerHTML = (cp ? `<dl>${dl([['State', `<span class="chip ${cp.state === 'locked' ? 'ok' : ''}">${esc(cp.state)}</span>`], ['Signed weight', `${int(cp.signed)} of ${int(cp.total)} (${(cp.fraction_total * 100).toFixed(1)}% of all weight, ${(cp.fraction_active * 100).toFixed(1)}% of active)`], ['Votes', `${int(cp.votes)} of ${int(cp.voters)} voters`], cp.locked_at ? ['Locked', utc(new Date(cp.locked_at).getTime())] : null])}</dl>` : '') +
certs.map(c => `<dl style="margin-top:14px">${dl([[c.role === 'checkpoint' ? 'Certificate' : 'Carries certificate', `index ${c.index}, ${c.voter_count} voters, aggregator <span class="id">${esc(shortHash(c.aggregator, 8, 0))}</span>, ${c.role === 'checkpoint' ? 'carried by ' + link(c.carrier) : 'for checkpoint ' + link(c.checkpoint)}`], ['Weight', `${int(c.total_weight)} total, ${int(c.active_weight)} active at the lock`], c.previous ? ['Previous lock', `index ${c.previous.index}, ${link(c.previous.hash)}${c.headers_complete ? ', header chain stored' : ''}`] : null, ['Verify', `<a href="/api/checkpoint">/api/checkpoint</a> serves the newest certificate for the in-browser verifier`]])}</dl>`).join('') +
(!cp && !certs.length ? '<div class="empty">This block is neither a checkpoint nor a certificate carrier. Checkpoints are every 30 blue score; a lock needs two thirds of all 30-day weight.</div>' : '');
$('body').hidden = false;
}
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
</script>
</body>
</html>