Merge site-ui-5 70ddf80d into master (gate: green on 70ddf80d, recorded by tools/ci/pre-push.sh; the full gate runs in CI on this merge)

This commit is contained in:
igneum-labs 2026-10-07 16:45:01 +00:00
commit d960dc5cef
101 changed files with 272 additions and 37 deletions

View file

@ -41,7 +41,7 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml`
| 14 | Ethereum bytecode runs unchanged, with the documented differences of spec 7.1 | Homepage Build card; litepaper Building | tested by the team | as row 13; fixes `F-exec-A`, `F-exec-B` (spec 7.5) | `tools/evm-smoke/smoke.mjs`: deploy via viem, `increment`, `hashLoop`, `eth_estimateGas`, `eth_getLogs`; `tools/exec-attacks` scenarios 1 and 3; bench-log "execution layer attack fixes" | Deployment, calls, reverts, logs and gas estimates behave as viem expects; chain id 4463; the prototype pgas table gives 0.0095 to 0.028 pgas per gas, below the design's band before calibration, 3 October 2026. 4 October 2026: a transaction that would cross the block's proving budget is refused by the mempool and, if forced in, aborted and charged with its nonce advanced (25 of 25 checks; 30 of 30 malformed cases). Apple M5 Max. The `Prover` precompile, proof records and the shard planner are not in the node | none yet |
| 15 | Every block is proven, with the proof landing within about a minute at launch | Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate | implemented | repo `d7e1f89` (GPU proof), `e01a3cc`, `292e800`, `eedd136` (`proving/igneum-prove`: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6 | `proving/windows-wsl2` (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; `igneum-prove-host --mode block` on `proving/fixtures/`; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards" | First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture `block-78-increment` (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in `docs/benchmarks/proving-e2e.md`. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on PC 2 in 34 s, verified on the Mac in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind `proving_v1_activation_daa` (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one | none yet |
| 16 | A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves) | Litepaper Proving ("The proving budget"); roadmap gate 2 | designed | spec 5.1 (Target), 7.6 (`S_p` provisional, 7,500,000 pgas = `B_p` / 4) | `PROVE-SHARD.bat` on the RTX 5090 (pending); the end-to-end standard in `docs/benchmarks/proving-e2e.md`; bench-log "proving: devnet v4 shards" | Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional `S_p` is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card | none yet |
| 17 | The chip resistance claim: the strongest chip in the public model reaches 5x to 9x per joule against an RTX 5090 today (modelled); class v4 brings it to 2.1x (k = 1) to 3.9x (k about 0.33, claimed by a withdrawn product) and its second rung to about 2.8x (modelled on measured watts); class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item (designed, +0.2 ms verifier); the hot-set cache bounded at 1.067x at the ceiling (measured census of 1,024 programs) and the weak-day FPGA at most 12 percent on 12 days a century (measured census) are bounded and routed to the next class; datacentre silicon (H100 SXM, measured 7 October) does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years (modelled) | The home page's chip line, the litepaper's chip model section, the miner page's line (the texts of `docs/plans/counter-asic-3-public-text-2026-10-07.md`) | tested by the team (every card, the verifier, the two attack-pass censuses, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/funding.md` (the three lots) | The chip model re-run on the measured class v3 and v4 rates, watts and verifier times; the hot-set census of 1,024 programs and the weak-day census of 2^24 days on the attack-pass branch; the H100 SXM bench row | 136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 5.1x to 9.2x; 2.1x, 3.9x, 2.8x; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 6 and 7 October 2026 | none yet; the three cryptanalysis lots are the next test |
| 17 | The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (k = 1) to 3.9x (k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 12 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state) | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/funding.md` (the three lots) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.9x, 2.8x at launch; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 | none yet; the three cryptanalysis lots are the next test |
| 18 | The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache | Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page | tested by the team | readwidth e752fc7 (`docs/plans/read-width.md`), ca2-era 78c0ee4, ca2-cache 2de19e5 (`docs/plans/hot-table.md`) | The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load | Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026 | none yet |
| 19 | The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors | Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page | tested by the team | ca2-mixer 1ab8b21 (`tests/mixer.rs`, `tests/scratch.rs`), ca2-era 78c0ee4, ca2-soundness a465881 (`docs/analysis/scratch-soundness.md`), `igneum-pow/tests/packs.rs` | The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card | Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (PC 1 job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing) | none yet |
| 20 | No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%) | Homepage stats and Economics tiles; litepaper Supply, Economics | implemented | repo `6ac80a3`; fork "igneum-node devnet v0"; `consensus/core/src/igneum.rs`, `coinbase.rs` | `cargo test -p kaspa-consensus-core igneum` (8 pass: subsidy table, ramp, split, cap) and `cargo test -p kaspa-consensus coinbase` (8 pass); `igneum-miner inspect 40`; bench-log "igneum-node devnet v0" | Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the `igneum-proving-pool-v0` output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened | none yet |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 KiB

After

Width:  |  Height:  |  Size: 553 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 KiB

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 KiB

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 KiB

After

Width:  |  Height:  |  Size: 537 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 KiB

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 590 KiB

After

Width:  |  Height:  |  Size: 567 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 KiB

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 KiB

After

Width:  |  Height:  |  Size: 475 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 516 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 KiB

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 KiB

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 KiB

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 KiB

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 414 KiB

After

Width:  |  Height:  |  Size: 504 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 571 KiB

After

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 676 KiB

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 KiB

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 KiB

File diff suppressed because one or more lines are too long

View file

@ -250,7 +250,7 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
<tr data-status="tested by the team"><td class="n">14</td><td class="claim">Ethereum bytecode runs unchanged, with the documented differences of spec 7.1<div class="where">Homepage Build card; litepaper Building</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">as row 13; fixes <code>F-exec-A</code>, <code>F-exec-B</code> (spec 7.5)</td><td><code>tools/evm-smoke/smoke.mjs</code>: deploy via viem, <code>increment</code>, <code>hashLoop</code>, <code>eth_estimateGas</code>, <code>eth_getLogs</code>; <code>tools/exec-attacks</code> scenarios 1 and 3; bench-log "execution layer attack fixes"</td><td>Deployment, calls, reverts, logs and gas estimates behave as viem expects; chain id 4463; the prototype pgas table gives 0.0095 to 0.028 pgas per gas, below the design's band before calibration, 3 October 2026. 4 October 2026: a transaction that would cross the block's proving budget is refused by the mempool and, if forced in, aborted and charged with its nonce advanced (25 of 25 checks; 30 of 30 malformed cases). Apple M5 Max. The <code>Prover</code> precompile, proof records and the shard planner are not in the node</td><td class="iv">none yet</td></tr>
<tr data-status="implemented"><td class="n">15</td><td class="claim">Every block is proven, with the proof landing within about a minute at launch<div class="where">Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate</div></td><td><span class="st st-1">implemented</span></td><td class="mono">repo <code>d7e1f89</code> (GPU proof), <code>e01a3cc</code>, <code>292e800</code>, <code>eedd136</code> (<code>proving/igneum-prove</code>: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6</td><td><code>proving/windows-wsl2</code> (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; <code>igneum-prove-host --mode block</code> on <code>proving/fixtures/</code>; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards"</td><td>First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture <code>block-78-increment</code> (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in <code>docs/benchmarks/proving-e2e.md</code>. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on the RTX 5090 Windows rig in 34 s, verified on the Apple M5 Max in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind <code>proving_v1_activation_daa</code> (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one</td><td class="iv">none yet</td></tr>
<tr data-status="designed"><td class="n">16</td><td class="claim">A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves)<div class="where">Litepaper Proving ("The proving budget"); roadmap gate 2</div></td><td><span class="st st-0">designed</span></td><td class="mono">spec 5.1 (Target), 7.6 (<code>S_p</code> provisional, 7,500,000 pgas = <code>B_p</code> / 4)</td><td><code>PROVE-SHARD.bat</code> on the RTX 5090 (pending); the end-to-end standard in <code>docs/benchmarks/proving-e2e.md</code>; bench-log "proving: devnet v4 shards"</td><td>Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional <code>S_p</code> is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card</td><td class="iv">none yet</td></tr>
<tr data-status="designed"><td class="n">17</td><td class="claim">The chip resistance claim: the strongest chip in the public model reaches 5x to 9x per joule against an RTX 5090 today (modelled); class v4 brings it to 2.1x (k = 1) to 3.9x (k about 0.33, claimed by a withdrawn product) and its second rung to about 2.8x (modelled on measured watts); class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item (designed, +0.2 ms verifier); the hot-set cache bounded at 1.067x at the ceiling (measured census of 1,024 programs) and the weak-day FPGA at most 12 percent on 12 days a century (measured census) are bounded and routed to the next class; datacentre silicon (H100 SXM, measured 7 October) does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years (modelled)<div class="where">The home page's chip line, the litepaper's chip model section, the miner page's line (the texts of <code>docs/plans/counter-asic-3-public-text-2026-10-07.md</code>)</div></td><td><span class="st st-0">tested by the team (every card, the verifier, the two attack-pass censuses, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured</span></td><td class="mono"><code>docs/analysis/chip-model-v3.md</code> 5 and 6; <code>docs/analysis/latency-shadow-2026-10-06.md</code>; <code>docs/plans/counter-asic-3-status.md</code>; <code>docs/analysis/attack-pass/f8-uniform.md</code>, <code>f4-weakday.md</code>; <code>docs/design/class-v5-stored-state.md</code>; the H100 and market-cap rows of 7 October; <code>docs/plans/funding.md</code> (the three lots)</td><td>The chip model re-run on the measured class v3 and v4 rates, watts and verifier times; the hot-set census of 1,024 programs and the weak-day census of 2^24 days on the attack-pass branch; the H100 SXM bench row</td><td>136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 5.1x to 9.2x; 2.1x, 3.9x, 2.8x; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 6 and 7 October 2026</td><td class="iv">none yet; the three cryptanalysis lots are the next test</td></tr>
<tr data-status="designed"><td class="n">17</td><td class="claim">The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (k = 1) to 3.9x (k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 12 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state)<div class="where">the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line</div></td><td><span class="st st-0">tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured</span></td><td class="mono"><code>docs/analysis/chip-model-v3.md</code> 5 and 6; <code>docs/analysis/latency-shadow-2026-10-06.md</code>; <code>docs/plans/counter-asic-3-status.md</code>; <code>docs/analysis/attack-pass/f8-uniform.md</code>, <code>f4-weakday.md</code>, <code>docs/analysis/ca3-v4-uniform.md</code>; <code>docs/design/class-v5-stored-state.md</code>; the H100 and market-cap rows of 7 October; <code>docs/plans/funding.md</code> (the three lots)</td><td>the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses <code>tools/attack/f8-uniform</code> and the F4 census; the verifier by <code>igneum-pow bench</code></td><td>136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.9x, 2.8x at launch; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, the RTX 5090 Windows rig's RTX 5090, the three-card Windows rig's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1</td><td class="iv">none yet; the three cryptanalysis lots are the next test</td></tr>
<tr data-status="tested by the team"><td class="n">18</td><td class="claim">The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache<div class="where">Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">readwidth e752fc7 (<code>docs/plans/read-width.md</code>), ca2-era 78c0ee4, ca2-cache 2de19e5 (<code>docs/plans/hot-table.md</code>)</td><td>The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load</td><td>Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026</td><td class="iv">none yet</td></tr>
<tr data-status="tested by the team"><td class="n">19</td><td class="claim">The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors<div class="where">Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">ca2-mixer 1ab8b21 (<code>tests/mixer.rs</code>, <code>tests/scratch.rs</code>), ca2-era 78c0ee4, ca2-soundness a465881 (<code>docs/analysis/scratch-soundness.md</code>), <code>igneum-pow/tests/packs.rs</code></td><td>The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card</td><td>Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing)</td><td class="iv">none yet</td></tr>
<tr data-status="implemented"><td class="n">20</td><td class="claim">No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%)<div class="where">Homepage stats and Economics tiles; litepaper Supply, Economics</div></td><td><span class="st st-1">implemented</span></td><td class="mono">repo <code>6ac80a3</code>; fork "igneum-node devnet v0"; <code>consensus/core/src/igneum.rs</code>, <code>coinbase.rs</code></td><td><code>cargo test -p kaspa-consensus-core igneum</code> (8 pass: subsidy table, ramp, split, cap) and <code>cargo test -p kaspa-consensus coinbase</code> (8 pass); <code>igneum-miner inspect 40</code>; bench-log "igneum-node devnet v0"</td><td>Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the <code>igneum-proving-pool-v0</code> output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened</td><td class="iv">none yet</td></tr>

View file

@ -219,7 +219,7 @@
<div class="home-three rows">
<div class="home-row"><span class="n">01</span><div><b>The same card finds the block and proves it.</b><p>Both jobs pay. When you stop, the card still games.</p></div></div>
<div class="home-row"><span class="n">02</span><div><b>A fair start.</b><p>Nobody holds a coin before block one. The protocol carries no fee. The one payment to the project is the Ember software’s optional 1% dev fee, like other GPU miners, off with one flag.</p></div></div>
<div class="home-row"><span class="n">03</span><div><b>Built for graphics cards.</b><p>A new mining program every hour, so no chip is built for it. In our public model the strongest chip reaches 5x to 9x per joule against an RTX 5090 today; class v4, now on the vote, brings that to 2.1x to 3.9x. <a href="/litepaper#chip-model">The model and every measurement are public.</a></p></div></div>
<div class="home-row"><span class="n">03</span><div><b>Built for graphics cards.</b><p>At launch the strongest chip in our public model reaches 2.1x to 3.9x per joule against an RTX 5090, under class v4 from the first block. Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item. Without class v4 the same chip would reach 5x to 9x. <a href="/litepaper#chip-model">The model and every measurement are public.</a></p></div></div>
</div>
</div>
</section>

View file

@ -208,7 +208,7 @@
<section class="page-hero">
<div class="container">
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>The journey</span></div>
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Six phases · updated 6 Oct 2026</div>
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Six phases · updated 7 Oct 2026</div>
<h1>The journey.</h1>
<p class="lead">Six phases from the specification to a fair launch. Each closes at its gate, a measurement published whether it passes or fails, so there is no date to slip. Below the phases, the latest entries of the engineering log.</p></div></div>
</div>
@ -222,7 +222,8 @@
<div class="milestone next" id="phase-5"><div class="when">Weeks away: when the go checklist closes</div><div><span class="badge">Next</span><h3>5. Public testnet</h3><p>Three seed nodes and the public RPC are up; the one-click miner app on Windows, macOS and Linux, HiveOS, pools, the first rollup as a proving customer, no coin yet</p><p class="gate"><b>Gate:</b> 1,000 independent miners run 30 days and rollup proofs are delivered on time</p></div></div>
<div class="milestone next" id="phase-6"><div class="when">After the testnet has passed its gate (1,000 independent miners for 30 days, rollup proofs on time) and one proving customer has signed: a customer paying for proofs at a published rate, or a letter of intent with a volume</div><div><span class="badge">Next</span><h3>6. Mainnet fair launch</h3><p>Genesis with no premine, 30-day ramp. No listing is arranged, promised or sought by the project</p></div></div></div>
<div class="section-head" style="margin-top:100px"><div><div class="eyebrow"><span class="line"></span>The log, newest first</div><h2>Lately, in the&nbsp;log.</h2></div><div class="searchbar" style="min-width:min(100%,360px)"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/></svg><label for="log-q" class="visually-hidden">Filter the log</label><input id="log-q" data-filter-input="log" placeholder="Filter: a card, a date, a word" autocomplete="off" spellcheck="false"><span class="small" data-filter-count="log"></span></div></div>
<div class="record-count" data-filter-count="log"></div><div class="record-grid" data-filter-list="log"><article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0</h3><p>Counter ASIC 3.0: the class v4 rehearsal</p></article>
<div class="record-count" data-filter-count="log"></div><div class="record-grid" data-filter-list="log"><article class="record"><div class="record-top"><time datetime="2026-10-07">7 Oct 2026</time><span class="badge">log</span></div><h3>The first 16 GB card</h3><p>The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0</h3><p>Counter ASIC 3.0: the class v4 rehearsal</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>16:01Z: Ember run 6 on the three-card Windows rig</h3></article>
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0 item 2</h3><p>Counter ASIC 3.0 item 2: the per-day derivation</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0 item 8</h3><p>Counter ASIC 3.0 item 8: program work in the latency shadow</p></article>
@ -255,13 +256,12 @@
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>The program id split</h3><p>The program id split: why the Apple M5 Max rejected the RTX 5090 Windows rig's proofs, and the verifier at 114 s</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>Live devnet: the first shards proven, verified and paid</h3></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>One-click Windows workers</h3><p>One-click Windows workers: what the Apple M5 Max could measure</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First live hourly swap: no pause on Mac, NVIDIA or AMD</h3><p>First hourly program swap on the live devnet: compile-ahead, no pause, two cards</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine</h3></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First live finality lock: 77.4% of weight, 17 voters</h3><p>First finality lock on the live devnet: checkpoint 242 at 77.4% of all weight, two hours after genesis</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>The gfx1036 worker fault and what the Apple M5 Max could and could…</h3><p>The gfx1036 worker fault and what the Apple M5 Max could and could not reproduce</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>A node 60 s behind the clock is silently dead</h3></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First machine on the one-click app: a 5090 at 118 MH/s</h3><p>First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Difficulty rule v2</h3><p>Difficulty rule v2: the live oscillation, its cause, the DAG replay, the fix behind a height switch</p></article>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>The observer stored nothing for 78 minutes, then 7,022 blocks in two…</h3><p>The observer stored nothing for 78 minutes, then 7,022 blocks in two minutes</p></article></div>
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First machine on the one-click app: a 5090 at 118 MH/s</h3><p>First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe</p></article></div>
<p class="empty-state" data-filter-empty="log" hidden>Nothing in the log matches that.</p>
<p class="note">Every entry is a dated heading of <a href="/bench">the engineering log</a>, where the commands and the hardware are. The phases and their gates are the litepaper’s <a href="/litepaper#roadmap">roadmap</a>.</p>
<div class="onward"><a href="/bench" class="btn">The engineering log</a><a href="/evidence" class="btn">Every claim and its status</a><a href="/live" class="btn">The live devnet</a></div>

View file

@ -1,5 +1,5 @@
{
"updated": "2026-10-06",
"updated": "2026-10-07",
"stage": "phase-3",
"phases": [
{
@ -50,6 +50,11 @@
}
],
"log": [
{
"date": "2026-10-07",
"text": "The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig",
"short": "The first 16 GB card"
},
{
"date": "2026-10-06",
"text": "Counter ASIC 3.0: the class v4 rehearsal",
@ -215,6 +220,11 @@
"text": "One-click Windows workers: what the Apple M5 Max could measure",
"short": "One-click Windows workers"
},
{
"date": "2026-10-04",
"text": "First hourly program swap on the live devnet: compile-ahead, no pause, two cards",
"short": "First live hourly swap: no pause on Mac, NVIDIA or AMD"
},
{
"date": "2026-10-04",
"text": "Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine",
@ -239,16 +249,6 @@
"date": "2026-10-04",
"text": "First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe",
"short": "First machine on the one-click app: a 5090 at 118 MH/s"
},
{
"date": "2026-10-04",
"text": "Difficulty rule v2: the live oscillation, its cause, the DAG replay, the fix behind a height switch",
"short": "Difficulty rule v2"
},
{
"date": "2026-10-04",
"text": "The observer stored nothing for 78 minutes, then 7,022 blocks in two minutes",
"short": "The observer stored nothing for 78 minutes, then 7,022 blocks in two…"
}
]
}

View file

@ -310,7 +310,7 @@ body.all .pager{display:none}
<article>
<section id="abstract">
<h2>Abstract</h2>
<p class="lead">Igneum is a proof-of-work blockchain built for graphics cards, where NVIDIA cards also prove every block with zero-knowledge proofs and sell proving to other chains. The strongest chip in our public model reaches 5x to 9x per joule against an RTX 5090 today; class v4, now on the vote, brings that to 2.1x to 3.9x, and class v5 makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item: <a href="#chip-model">the chip model</a>, every number labelled measured, modelled, claimed or designed.</p>
<p class="lead">Igneum is a proof-of-work blockchain built for graphics cards, where NVIDIA cards also prove every block with zero-knowledge proofs and sell proving to other chains. At launch the strongest chip in our public model reaches 2.1x to 3.9x per joule against an RTX 5090, under class v4 from the first block; class v5 makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item; without class v4 the same chip would reach 5x to 9x: <a href="#chip-model">the chip model</a>, every number labelled measured, modelled, claimed or designed.</p>
<p>It runs the Ethereum virtual machine, so anything built for Ethereum runs on Igneum unchanged. Transactions are included in about one second, proven within about a minute at launch, and locked by miners within about two. There is no premine, no pre-sale, no treasury taken from emission, no stake anywhere in consensus, and no dependence on any other chain. Mining stays open to anyone with a GPU because the mining program changes every hour, so a chip built for one program is useless for the next, and a chip for the whole program space is a GPU without the graphics parts. No scheduled human release is needed to keep it that way. Writing new code, including an emergency fix to the proof system, is the one thing that takes a person, and it activates only on miner signalling.</p>
<div class="stats">
<div class="stat"><div class="v">1 / s</div><div class="k">blocks, rising to 10</div></div>
@ -435,17 +435,17 @@ body.all .pager{display:none}
<p>Three ideas carry the chip resistance. <strong>The hash rewrites itself.</strong> A new program every hour, drawn from the chain. Its memory pattern changes with it. The rules change on a schedule fixed at launch. No release, no vote. These are automatic schedule changes: they defeat a chip wired for one datapath and they need no human fork. Against a chip that stores the dataset every drawn parameter is firmware, and what meets that chip is the latency-shadow work (class v4) and the price per joule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). <strong>It waits on memory, not maths.</strong> Every hash is a chain of random reads into a table too big for a chip to carry. The wait is the same physics for everyone. <strong>Miners hold the switch.</strong> Spare defences are written into the rules, switched off. A miner signal turns one on, at the class-change threshold: miners signal three things at three thresholds, 60 percent of blue blocks over two weeks for a parameter genesis leaves open, 90 percent for an upgrade (new code), and 95 percent with a floor height for a class change. No fork.</p>
<p><strong>The work that waits can grow.</strong> Class v4 adds a block of latency-shadow arithmetic to every hash, about 100,000 integer operations that run while the memory reads are in flight, so a chip that stores the whole dataset still has to pay for a core. That size sits on a ladder fixed at genesis, six rungs from about 100,000 to about 1,000,000 operations, and it moves one rung at a time only when 90 percent of blue blocks in each of seven consecutive days ask for it; it can never move two rungs inside a week and never past a rung the reference verifier cannot check under 10 ms with its sibling thread busy (measured on the build server, 6 October 2026: the first three rungs pass at 8.8, 8.9 and 9.2 ms, the fourth misses by 0.08 ms on a loaded box and stays out until a quiet re-measurement, the two doublings are out at 12.4 and 15.0 ms). What it buys, on the measured cards: against a dataset-storing chip whose core costs what an RTX 5090's does per operation, the chip's per-joule edge falls from 2.1x at the first rung to 1.3x at the third; against a core as good as the one Bitmain claimed for its withdrawn Antminer X9 (about 3x per joule over a desktop CPU, never measured), from 3.9x to 2.8x. What it costs, per rung, is measured too: the Apple tier gives up 3 points of rate at the first step and 6 more at the second, the RTX 5090 nothing until the second; so the miners who pay for a step are the ones who take it (<a href="/ledger#M34">ledger M34</a>).</p>
<h3 id="chip-model">The chip model</h3>
<p>We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090’s hash at 1.15x the tuned 5090’s hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms.</p>
<p>We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. Class v4 is live from the first block on the testnet and the mainnet (the ladder’s rung 0 at genesis), so the launch number is the class v4 row. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090’s hash at 1.15x the tuned 5090’s hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms.</p>
<div class="tbl"><table><thead><tr><th>The chip and the class</th><th>Edge over an RTX 5090 per joule</th><th>Label and date</th></tr></thead><tbody>
<tr><td>A memory-controller chip that stores the whole dataset (the Ethash class), class v3</td><td>5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x)</td><td>modelled, 6 October 2026; the precedent measured by others, 2020 to 2022</td></tr>
<tr><td>The same chip under class v4 (about 100,000 integer ops per hash in the latency shadow, so the chip carries a GPU-class datapath beside its memory)</td><td>2.1x with a core as costly per op as the GPU’s (k = 1); 3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped</td><td>modelled on measured card watts, 6 October 2026; the X9 figure claimed, never measured</td></tr>
<tr><td>The same chip at the ladder’s second rung (about 200,000 ops per hash)</td><td>about 2.8x</td><td>modelled, 7 October 2026</td></tr>
<tr><td>At launch: a memory-controller chip that stores the whole dataset, under class v4 (about 100,000 integer ops per hash in the latency shadow, so the chip carries a GPU-class datapath beside its memory)</td><td>2.1x with a core as costly per op as the GPU’s (k = 1); 3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped</td><td>modelled on measured card watts, 6 October 2026; the X9 figure claimed, never measured</td></tr>
<tr><td>The same chip at the ladder’s second rung (about 200,000 ops per hash), reached by miner signal</td><td>about 2.8x</td><td>modelled, 7 October 2026</td></tr>
<tr><td>Any chip under class v5, where the dataset is the chain’s own state</td><td>a stateless or stale chip is wrong on every item, so the stored-dataset chip and the recompute chip are removed as categories; the verifier pays 0.2 ms more per warp</td><td>designed, 7 October 2026</td></tr>
<tr><td>A chip caching the hottest 0.1 percent of items (about 1 MB of SRAM)</td><td>bounded at 1.067x at the ceiling, 1.005x on about half the hours and 1.048x on 5 percent</td><td>measured census of 1,024 programs, 7 October 2026; the source rule in the next class</td></tr>
<tr><td>A per-day FPGA that recomputes the dataset with cheap multipliers on a weak day</td><td>at most 12 percent more hash rate on 12 days a century, nothing on the other days and nothing for any chip</td><td>measured census of 2^24 days, 7 October 2026; the rule in the next class</td></tr>
<tr><td>When a stored-dataset chip pays for itself</td><td>at about USD 100 M of market cap in the first two years, not before</td><td>modelled, 7 October 2026</td></tr>
<tr><td>The baseline the work started from: the same chip under class v3, without the shadow (the Ethash class)</td><td>5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x)</td><td>modelled, 6 October 2026; the precedent measured by others, 2020 to 2022; never the launch state</td></tr>
</tbody></table></div>
<p>What a miner sees from this. Class v4 costs a 5090 about 80 W more for 0.2 percent of rate, an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (all measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at the testnet genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). The next test of the model is not ours: the cryptanalysis plan buys three external lots against the mixer, the chained cache and the acceptance rule.</p>
<p>What a miner sees from this. Class v4 costs a 5090 about 80 W more for 0.2 percent of rate, an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (all measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). On the devnet, which started on class v3, class v4 arrives by miner signal at a published height (a devnet fact, not a launch one). The next test of the model is not ours: the cryptanalysis plan buys three external lots against the mixer, the chained cache and the acceptance rule.</p>
<p>No hash has stayed free of chips forever. Igneum does not claim to. It states the gain its own model finds, the response takes a week, and both are measured. The model is public: <a href="/bench#counter-asic-2-0-the-numbers">the numbers</a>; the claim is tested by paid independent cryptanalysis and the public benchmark. Monero has run on RandomX since 2019 (approximate) with no chip shipped. Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked. A box with about a 2x per joule edge over the best CPUs, and about 3x over a desktop, was withdrawn rather than face a RandomX re-tune of 1.5x or more. That is the band Igneum’s class v4 model sits in (2.1x to 3.9x over an RTX 5090), and the defence that held was a maintained algorithm with a credible upgrade path, which is what the ladder is.</p>
<p>One thing takes a person, here and on every chain that exists: writing new code. A chain cannot safely write its own generator, and it cannot safely tell a chip from a wave of honest new cards by hashrate alone. If the design above ever failed, anyone could publish a new generator and miners would switch it on by signalling, as Monero's community can fork. Igneum is built to make that day unlikely, and does not depend on avoiding it.</p>
</section>

View file

@ -302,7 +302,7 @@ pre b{color:var(--molten-text);font-weight:500}
</tbody>
</table></div>
<p class="fair"><b>Graphics cards only.</b> A new mining program every hour, so no chip is built for it. 80% of every block to the card that finds it, 20% to the cards that prove it. No premine, no stake, no fee to any team. Every number above has a row in <a href="/miners">the bench table</a>.</p>
<p class="fair">Your card against the strongest chip we can price: an RTX 5090 at 136 MH/s on 350 W (measured 6 October 2026), the chip 5x to 9x per joule in the public model today, 2.1x to 3.9x under class v4 (modelled on measured watts), and under class v5 wrong on every item because the dataset is the chain’s own state (designed); <a href="/litepaper#chip-model">the model and the measurements are public</a>.</p>
<p class="fair">Your card against the strongest chip we can price: an RTX 5090 at 136 MH/s on 350 W (measured 6 October 2026); at launch the chip reaches 2.1x to 3.9x per joule under class v4 (modelled on measured watts), and under class v5 it is wrong on every item because the dataset is the chain’s own state (designed). Without class v4 it would be 5x to 9x. <a href="/litepaper#chip-model">The model and the measurements are public</a>.</p>
</div>
</section>

File diff suppressed because one or more lines are too long

View file

@ -213,7 +213,8 @@ p.notice{display:block;margin:14px 0 0;font-size:13px;line-height:1.7}
.dl-bar{display:none}
@media (max-width:720px){.dl-bar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:30;justify-content:space-between;align-items:center;gap:var(--s-3);padding:10px var(--gutter) calc(10px + env(safe-area-inset-bottom));background:var(--top-bg);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-top:1px solid var(--line)}.dl-bar span{font:400 var(--t-sm)/1.4 var(--f-mono);color:var(--ash);min-width:0}body.has-dl-bar{padding-bottom:72px}}
.band{background:var(--ember);color:var(--ember-ink)}
.band .wrap{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s-5);padding-top:56px;padding-bottom:56px}
.band .wrap,.band .container{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s-5);padding-top:56px;padding-bottom:56px}
@media (max-width:560px){.band .wrap,.band .container{padding-top:40px;padding-bottom:40px}}
.band h2{color:var(--ember-ink);font-weight:900;margin-bottom:var(--s-2)}
.band p{margin:0;max-width:56ch}
.btn.dark{background:var(--obsidian);color:var(--bone);border-color:var(--obsidian)}
@ -497,9 +498,62 @@ article .status{white-space:normal;flex-wrap:wrap;overflow:visible}
article .status .badge:not([data-mark]){white-space:normal;overflow-wrap:anywhere;line-height:1.5;max-width:100%}
/* data tables size to their content and scroll inside their frame, never squeeze a column to a sliver (site-ui-5) */
.tbl table,.table-wrap table{width:100%;min-width:720px;table-layout:auto}
.tbl td,.table-wrap td{white-space:normal;overflow-wrap:anywhere;vertical-align:top;min-width:9ch}
.tbl td,.table-wrap td{white-space:normal;overflow-wrap:break-word;vertical-align:top;min-width:9ch}
.tbl td .cardname,.table-wrap td .cardname{white-space:nowrap}
.phero .os span{display:inline-flex;align-items:center}
.download-platform{display:flex;align-items:center;gap:14px}
/* the evidence table's status pills wrap inside their cell (overlap sweep, 7 Oct 2026) */
table#claims .st{white-space:normal;display:inline-block;line-height:1.4;max-width:100%}
/* the padding sweep (tools/ci/padding-check.mjs, 7 Oct 2026): every section's vertical padding on the scale (a multiple of 4
from 24), every card's inner padding 24, so no text or control sits under 24 px from a filled edge */
.page-hero,main .obs-head,.lost{padding-top:64px;padding-bottom:48px}
@media (max-width:560px){.page-hero{padding:24px 0}}
.site-footer{padding-bottom:24px}
.footer-bottom{padding-top:24px}
.doc-section,article section{padding-bottom:40px;margin-bottom:40px}
@media (max-width:860px){.sec{padding:72px 0}}
.lost{padding-bottom:96px}
.grid>section.card{padding-top:36px;padding-bottom:36px}
.motion{padding:24px}
.lab{padding-top:48px}
.dl-card,.home-tile,.tiles6>div,.mstats>div,.label,.card,.feature,.tool-card,.stat{padding:24px}
.dl-card{gap:14px 16px}
.dl-card .body{grid-column:1/-1}
.footer-bottom{padding-bottom:0}
@media (max-width:560px){.footer-bottom{padding-bottom:0}}
/* the ledger's count table keeps each status badge whole: the table scrolls, the word never breaks */
.counts .badge:not([data-mark]){white-space:nowrap;overflow-wrap:normal}
/* the same scale and 24 px rule where a page's own style block sits later in the cascade (the sweep's second round) */
main .layout article section{padding-bottom:40px;margin-bottom:40px}
main .lost{padding-top:64px;padding-bottom:96px}
main .motion{padding:24px}
main .lab{padding-top:48px}
main .tiles6>div,main .mstats>div{padding:24px 25px}
main .labels .label{padding:24px}
main .state-card,main .milestone{padding:24px}
main .strip{padding-top:24px;padding-bottom:24px}
/* the sweep's third round: the live inspector and toolbar at 24, the band and the download card 24 from their edges on phones */
main .icol{padding:24px}
main .toolbar{padding:24px 25px}
@media (max-width:560px){.band .wrap,.band .container{padding-left:24px;padding-right:24px}.download-card{padding:24px}}
/* the journey's phases are cards in this system: the old timeline rail and marker (drawn for an unboxed list) go, the badge says the state; the when column keeps clear of the body */
main .milestone:before,main .milestone:after{display:none}
main .milestone .when{padding-right:12px;padding-top:2px}
@media (max-width:560px){main .milestone{padding:24px}}
/* the litepaper's body paragraphs share one measure (the eye pass: the first paragraph sat narrower than the second) */
main .layout article section>p{max-width:76ch}
/* the ledger's count table: a filter chip stays on one line, the table scrolls before a pill wraps */
main table .chip{white-space:nowrap}
/* no orphan word on its own line (copy law 18): the browser's pretty wrapping on body text; headings already balance */
p,li,dd,figcaption,.lead,.d,.sub{text-wrap:pretty}
/* a comparison table's label column holds a short phrase on one or two lines, never one word per line */
main .tbl td:first-child,main .table-wrap td:first-child{min-width:14ch}
/* a section lifted into a derived page keeps its own .container: the inner one adds no second gutter; a card's table clears the text above it */
main .container .container,main .wrap .wrap{padding-left:0;padding-right:0}
.feecard .tbl,.feecard .table-wrap{margin-top:16px}
/* the eye pass on /faucet and /metamask: the headline keeps a gap above its lead, two cards in a grid line up at the top, the page ends 72 px above the footer */
main.wrap h1+p,main.wrap h1+.lead,.page-hero h1+.lead{margin-top:16px}
main.wrap>.grid{align-items:start}
main.wrap{padding-bottom:72px}
@media (max-width:560px){main.wrap{padding-bottom:48px}}
main.wrap>.grid{margin-bottom:40px}

View file

@ -14,8 +14,8 @@ const REQUIRED = {
['X2', 'Public testnet: not yet open; the devnet build is here for people who want to look'],
['X7', 'hello@igneum.network'],
['X31', 'The public testnet is weeks away: three seed nodes and the public RPC are up, and it opens when the go checklist closes.'],
// 7 Oct 2026, 14:3x: the chip line of docs/plans/counter-asic-3-public-text-2026-10-07.md (the X9 label now lives on the litepaper)
['X35', 'class v4, now on the vote, brings that to 2.1x to 3.9x'],
// 7 Oct 2026, 18:3x: the launch-first chip line of docs/plans/counter-asic-3-public-text-2026-10-07.md section 1
['X35', 'At launch the strongest chip in our public model reaches 2.1x to 3.9x per joule against an RTX 5090, under class v4 from the first block'],
],
'litepaper.html': [
['X3', 'Live rows arrive with the public testnet.'],
@ -25,7 +25,7 @@ const REQUIRED = {
['C2', '2019 (approximate)'],
['X34', 'was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026'],
['X36', 'Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked.'],
['X35', 'class v4, now on the vote, brings that to 2.1x to 3.9x'],
['X35', 'so the launch number is the class v4 row'],
['X35', '3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped'],
['X36', 'the X9 figure claimed, never measured'],
['M34', 'The work that waits can grow.'],

170
tools/ci/padding-check.mjs Normal file
View file

@ -0,0 +1,170 @@
#!/usr/bin/env node
// The padding and visuals sweep (site-ui-5, 7 October 2026; the project lead's /wallet band whose heading touched the band's top edge and
// whose button touched its bottom). Renders every served page at five widths in both themes and flags what a reader sees as
// cramped or broken, five classes:
// TIGHT text or a control closer than 24 px to the edge of the filled band, card or section that holds it
// SCALE a section whose vertical padding is off the design system's scale (0, or a multiple of 4 from 24 up)
// TOUCH two controls (buttons, links styled as buttons, inputs, selects) that touch or nearly touch (under 6 px apart)
// OVERRUN an image or canvas that runs out of its frame (the nearest .frame, .app-window, .scene, .panel or figure)
// UNDER-BAR a heading that renders under the sticky bar on load, or an anchor target the bar would cover on arrival
// The things that are small and filled by design (buttons, pills, badges, chips, tabs, table cells, the bar, tooltips) are
// containers whose own padding is theirs, so they are never the container of a TIGHT finding; segmented controls (.tabs,
// .theme-group, .zoom, [role=tablist]) are exempt from TOUCH.
//
// node tools/ci/padding-check.mjs --self-test the fixture (the exact /wallet band with its padding lost, a
// touching pair, an image over its frame, a heading under the bar)
// must fail with one finding of each class; the clean fixture passes
// node tools/ci/padding-check.mjs --site [dir] every *.html of the site (default site/)
// options: --widths 390,768,1024,1440,1600 --themes dark,light --only <substring> --json <file> --jobs 3
//
// Needs a browser: Playwright from $IGNEUM_PLAYWRIGHT_DIR, /srv/builds/_bin/overlap (the box) or this tree's node_modules.
// Without one it says so and exits 0 (CI installs Playwright; the box has it; the Mac renders nothing). Pages are served by
// tools/site/serve.mjs with /api answering 502, so every page renders its rest state; ?theme= and ?motion=off are passed.
import { readdirSync, readFileSync, writeFileSync, mkdtempSync, rmSync, existsSync } from 'node:fs';
import { createRequire } from 'node:module';
import { join, dirname } from 'node:path';
import { tmpdir } from 'node:os';
import { fileURLToPath } from 'node:url';
import { spawn } from 'node:child_process';
import http from 'node:http';
const here = dirname(fileURLToPath(import.meta.url)), repo = join(here, '..', '..');
const args = process.argv.slice(2);
const opt = (k, d) => { const i = args.indexOf(k); return i >= 0 && args[i + 1] ? args[i + 1] : d; };
const WIDTHS = opt('--widths', '390,768,1024,1440,1600').split(',').map(Number);
const THEMES = opt('--themes', 'dark,light').split(',');
const ONLY = opt('--only', ''), JSON_OUT = opt('--json', ''), JOBS = Number(opt('--jobs', '3'));
function playwright() {
for (const root of [process.env.IGNEUM_PLAYWRIGHT_DIR, '/srv/builds/_bin/overlap', repo].filter(Boolean)) {
try { return createRequire(join(root, 'package.json'))('playwright'); } catch (e) { /* next */ }
}
return null;
}
const pw = playwright();
if (!pw) { console.log('padding-check: no Playwright here (the box and CI have it); nothing checked'); process.exit(0); }
// what runs inside the page: returns the findings for this render
const INSPECT = `(() => {
const MIN = 24, GAP = 6, out = [];
const vis = el => { const r = el.getBoundingClientRect(); const cs = getComputedStyle(el); return r.width > 0 && r.height > 0 && cs.visibility !== 'hidden' && cs.display !== 'none' && Number(cs.opacity) > 0.05; };
const txt = el => (el.textContent || '').replace(/\\s+/g, ' ').trim().slice(0, 60);
const path = el => { const parts = []; for (let e = el; e && e !== document.body && parts.length < 4; e = e.parentElement) parts.unshift(e.tagName.toLowerCase() + (e.id ? '#' + e.id : '') + (e.classList.length ? '.' + [...e.classList].slice(0, 2).join('.') : '')); return parts.join(' > '); };
const alpha = c => { const m = /rgba?\\(([^)]+)\\)/.exec(c); if (!m) return c === 'transparent' ? 0 : 1; const p = m[1].split(',').map(s => parseFloat(s)); return p.length > 3 ? p[3] : 1; };
// a filled container has a background, or a border on every side (a framed box); a rule above or below a block is not a box
const filled = el => { const cs = getComputedStyle(el); const bordered = ['Top','Right','Bottom','Left'].every(s => parseFloat(cs['border' + s + 'Width']) > 0 && alpha(cs['border' + s + 'Color']) > 0.02); return alpha(cs.backgroundColor) > 0.02 || cs.backgroundImage !== 'none' || bordered; };
const SMALL = el => el.matches('a,button,input,select,textarea,label,td,th,.pill,.badge,.osmark,.chip,.tag,.tab,.tb,.state,.kind,.st,.sw,.lgi,.dot,code,kbd,summary,[role=tab],.nav,nav,.tip,.chip-zoom,.gen,.step-index,.n,.number,.num,.dev-label,.devnet,.hash-btn,.linkish,.switch,.track,.record-top .badge,.mini');
// 1. TIGHT: the nearest filled, sizeable container of each text or control, and the distance to its edges
const containerOf = el => { for (let e = el.parentElement; e && e !== document.body; e = e.parentElement) { if (SMALL(e)) return null; if (filled(e)) { const r = e.getBoundingClientRect(); const radius = parseFloat(getComputedStyle(e).borderTopLeftRadius) || 0; /* a row (radius 12 or under) is the app's compact row, its own padding is its own; a card is 14 and up */ if (r.height >= 72 && r.width >= 200 && !(radius > 0 && radius <= 12)) return e; return null; } } return null; };
const seen = new Set();
for (const el of document.querySelectorAll('h1,h2,h3,h4,p,li,a.btn,button,input,select,.eyebrow,.lead,figcaption,dt,dd,.k,.v,.d,.mk,.mv,.mf,.key,strong.v')) {
if (!vis(el) || !txt(el) && !el.matches('a,button,input,select')) continue;
if (el.closest('.nav,.tip,.chip-zoom,table,.tabs,.theme-group,.zoom,.mode,.nav-sheet,.panels,figcaption,.frame .bar,.window-top,.hive-sheet,.footer-dl,.sheet-social,.social')) continue;
if (el.matches('figcaption')) continue;
const c = containerOf(el); if (!c) continue;
const r = el.getBoundingClientRect(), cr = c.getBoundingClientRect(), cs = getComputedStyle(c);
const inset = { top: r.top - cr.top, bottom: cr.bottom - r.bottom, left: r.left - cr.left, right: cr.right - r.right };
// a container that scrolls or clips (a table frame, a window) is judged by what is inside its padding box only
const bad = Object.entries(inset).filter(([k, v]) => v >= -1 && v < MIN).map(([k, v]) => k + ' ' + Math.round(v) + 'px');
if (bad.length) { const key = path(c) + '|' + bad.join(','); if (!seen.has(key)) { seen.add(key); out.push({ kind: 'TIGHT', what: txt(el) || el.tagName.toLowerCase(), where: path(el), container: path(c), detail: bad.join(', ') }); } }
}
// 2. SCALE: section paddings on the scale
for (const el of document.querySelectorAll('section,.sec,.band,.page-hero,.fold,.site-footer,.cta-band,main > .obs-head')) {
if (!vis(el)) continue; const cs = getComputedStyle(el);
for (const side of ['paddingTop', 'paddingBottom']) { const v = Math.round(parseFloat(cs[side])); if (v !== 0 && (v < 24 || v % 4 !== 0)) out.push({ kind: 'SCALE', what: side + ' ' + v + 'px', where: path(el), detail: 'not 0 and not a multiple of 4 from 24 up' }); }
}
// 3. TOUCH: controls that touch
const ctrls = [...document.querySelectorAll('a.btn,button,input,select,.community a,.dl-list a,.dl-row a,.footer-dl a')].filter(e => vis(e) && !e.closest('.tabs,.theme-group,.zoom,.mode,[role=tablist],.nav,.nav-sheet,.panels,table'));
for (let i = 0; i < ctrls.length; i++) for (let j = i + 1; j < ctrls.length; j++) {
const a = ctrls[i].getBoundingClientRect(), b = ctrls[j].getBoundingClientRect(); if (ctrls[i].contains(ctrls[j]) || ctrls[j].contains(ctrls[i])) continue;
const dx = Math.max(a.left, b.left) - Math.min(a.right, b.right), dy = Math.max(a.top, b.top) - Math.min(a.bottom, b.bottom);
if ((dx < GAP && dy < 0) || (dy < GAP && dx < 0)) out.push({ kind: 'TOUCH', what: (txt(ctrls[i]) || ctrls[i].tagName) + ' / ' + (txt(ctrls[j]) || ctrls[j].tagName), where: path(ctrls[i]), detail: 'gap ' + Math.round(Math.max(dx, dy)) + 'px' });
}
// 4. OVERRUN: media out of its frame
for (const el of document.querySelectorAll('img,canvas,video')) {
if (!vis(el)) continue; const f = el.closest('.frame,.app-window,.scene,.panel,.fold-scene,.proof-scene,figure,.wallet-card'); if (!f) continue;
const r = el.getBoundingClientRect(), fr = f.getBoundingClientRect(), over = Math.max(r.right - fr.right, r.bottom - fr.bottom, fr.left - r.left, fr.top - r.top);
if (over > 2 && getComputedStyle(f).overflow === 'visible') out.push({ kind: 'OVERRUN', what: el.tagName.toLowerCase() + ' ' + (el.getAttribute('src') || el.id || '').split('/').pop(), where: path(f), detail: Math.round(over) + 'px past the frame' });
}
// 5. UNDER-BAR: the bar covers a heading on load, or an anchor the bar would cover on arrival
const nav = document.querySelector('.nav'); const navH = nav ? nav.getBoundingClientRect().height : 0;
const h1 = [...document.querySelectorAll('h1')].find(vis);
if (h1 && navH && h1.getBoundingClientRect().top < navH - 1) out.push({ kind: 'UNDER-BAR', what: txt(h1), where: path(h1), detail: 'top ' + Math.round(h1.getBoundingClientRect().top) + 'px under a ' + Math.round(navH) + 'px bar' });
const sp = parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop) || 0;
for (const el of document.querySelectorAll('section[id],h2[id],h3[id],article[id],div[id].doc-section')) { const sm = parseFloat(getComputedStyle(el).scrollMarginTop) || 0; if (navH && Math.max(sp, sm) < navH) { out.push({ kind: 'UNDER-BAR', what: '#' + el.id, where: path(el), detail: 'scroll padding ' + Math.round(Math.max(sp, sm)) + 'px under a ' + Math.round(navH) + 'px bar' }); break; } }
return out;
})()`;
async function serve(dir) {
const port = 4800 + Math.floor(Math.random() * 200);
const child = spawn(process.execPath, [join(repo, 'tools', 'site', 'serve.mjs'), String(port), dir, 'http://127.0.0.1:1'], { stdio: 'ignore' });
await new Promise((res, rej) => { let n = 0; const t = setInterval(() => { http.get(`http://127.0.0.1:${port}/`, () => { clearInterval(t); res(); }).on('error', () => { if (++n > 80) { clearInterval(t); rej(new Error('serve.mjs did not answer')); } }); }, 100); });
return { port, stop: () => child.kill() };
}
async function sweep(dir, pages, browser) {
const { port, stop } = await serve(dir);
const findings = []; let renders = 0;
const jobs = []; for (const p of pages) for (const w of WIDTHS) for (const t of THEMES) jobs.push({ p, w, t });
async function one({ p, w, t }) {
const ctx = await browser.newContext({ viewport: { width: w, height: w < 500 ? 844 : 900 }, deviceScaleFactor: 1, reducedMotion: 'reduce' });
const page = await ctx.newPage();
const route = p === 'index' ? '/' : '/' + p;
try {
await page.goto(`http://127.0.0.1:${port}${route}?theme=${t}&motion=off`, { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(250);
const found = await page.evaluate(INSPECT);
renders++;
for (const f of found) findings.push({ page: p, width: w, theme: t, ...f });
} catch (e) { findings.push({ page: p, width: w, theme: t, kind: 'RENDER', what: e.message.split('\n')[0].slice(0, 120), where: route, detail: '' }); }
await ctx.close();
}
let i = 0; await Promise.all(Array.from({ length: Math.max(1, JOBS) }, async () => { while (i < jobs.length) await one(jobs[i++]); }));
stop();
return { renders, findings };
}
const fmt = f => ` FAIL ${f.page} ${f.width}px ${f.theme}: ${f.kind} "${f.what}" in ${f.where}${f.container ? ' (container ' + f.container + ')' : ''}${f.detail ? ': ' + f.detail : ''}`;
const browser = await pw.chromium.launch({ headless: true, args: ['--no-sandbox'] });
try {
if (args.includes('--self-test')) {
// the fixture: the site's own stylesheet and bar, the exact /wallet band with its padding lost, a touching pair, an image over
// its frame, a heading under the bar; then the same page with each fixed
const site = join(repo, 'site');
const fx = mkdtempSync(join(tmpdir(), 'padding-check-'));
const nav = readFileSync(join(site, 'partials', 'nav.html'), 'utf8'), head = readFileSync(join(site, 'partials', 'head.html'), 'utf8');
const css = readFileSync(join(site, 'site.css'), 'utf8');
writeFileSync(join(fx, 'site.css'), css);
const page = (broken) => `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>fixture</title>${head.replace(/href="\/fonts\//g, 'href="/nofonts/').replace(/url\(\/fonts\//g, 'url(/nofonts/')}
<style>${broken ? '.band .container{padding-top:0!important;padding-bottom:0!important}.pair .btn+.btn{margin-left:0!important}.pair{gap:0!important}.frame img{width:120%!important;max-width:none!important}.page-hero{margin-top:-120px}' : ''}</style></head><body>
${nav}
<main id="main"><section class="page-hero"><div class="container"><h1>Fixture.</h1><p class="lead">A page for the padding check.</p></div></section>
<section class="section"><div class="container"><div class="actions pair"><a class="btn primary" href="#a">One</a><a class="btn" href="#b">Two</a></div>
<figure class="frame" style="max-width:400px;overflow:visible"><div class="bar"><i></i><i></i><i></i></div><img src="/icon-192.png" width="192" height="192" alt=""></figure></div></section></main>
<div class="band"><div class="container"><div><h2>The miner pays this wallet.</h2><p>Install the miner, press Start, and the address it makes is the one this wallet imports with one click.</p></div><a href="/miner" class="btn dark">The miner</a></div></div>
</body></html>`;
writeFileSync(join(fx, 'broken.html'), page(true)); writeFileSync(join(fx, 'clean.html'), page(false));
writeFileSync(join(fx, '404.html'), '<!doctype html><title>404</title>'); writeFileSync(join(fx, 'icon-192.png'), readFileSync(join(site, 'icon-192.png')));
const saveW = WIDTHS.splice(0, WIDTHS.length, 1440), saveT = THEMES.splice(0, THEMES.length, 'dark');
const r = await sweep(fx, ['broken', 'clean'], browser);
rmSync(fx, { recursive: true, force: true });
const broken = r.findings.filter(f => f.page === 'broken'), clean = r.findings.filter(f => f.page === 'clean');
const kinds = new Set(broken.map(f => f.kind));
const band = broken.find(f => f.kind === 'TIGHT' && /band/.test(f.container || ''));
let ok = true;
for (const k of ['TIGHT', 'TOUCH', 'OVERRUN', 'UNDER-BAR']) if (!kinds.has(k)) { console.error('self-test: the broken fixture did not raise ' + k); ok = false; }
if (!band) { console.error('self-test: the /wallet band with its padding lost was not flagged TIGHT'); ok = false; }
if (clean.length) { console.error('self-test: the clean fixture should pass\n' + clean.map(fmt).join('\n')); ok = false; }
if (!ok) process.exit(1);
console.log(`self-test passed: the band with no padding (${band.detail}), a touching pair, an image over its frame and a heading under the bar are caught; the clean fixture passes`);
WIDTHS.push(...saveW); THEMES.push(...saveT);
}
if (args.includes('--site')) {
const dir = opt('--site', '').startsWith('--') || !opt('--site', '') ? join(repo, 'site') : opt('--site');
const pages = readdirSync(dir).filter(f => f.endsWith('.html')).map(f => f.replace(/\.html$/, '')).filter(p => !ONLY || p.includes(ONLY));
const t0 = Date.now();
const r = await sweep(dir, pages, browser);
if (JSON_OUT) writeFileSync(JSON_OUT, JSON.stringify(r.findings, null, 1));
for (const f of r.findings) console.log(fmt(f));
const byKind = {}; for (const f of r.findings) byKind[f.kind] = (byKind[f.kind] || 0) + 1;
console.log(`padding-check (site): ${r.renders} renders, ${r.findings.length} findings${r.findings.length ? ' (' + Object.entries(byKind).map(([k, n]) => k + ' ' + n).join(', ') + ')' : ''} in ${((Date.now() - t0) / 1000).toFixed(1)} s`);
if (r.findings.length) process.exitCode = 1;
}
} finally { await browser.close(); }

Some files were not shown because too many files have changed in this diff Show more