diff --git a/app/igneum-app/src/jobbuild.rs b/app/igneum-app/src/jobbuild.rs index 204dadd4a..12d0795d9 100644 --- a/app/igneum-app/src/jobbuild.rs +++ b/app/igneum-app/src/jobbuild.rs @@ -135,6 +135,9 @@ pub struct Manifest { pub node_commit: String, /// the 40-hex commit (manifest node.commit_full, packer of 6 October 2026); empty in older manifests pub node_commit_full: String, + /// the commit's author time (manifest node.commit_time, unix seconds): SOURCE_DATE_EPOCH of every build stage, so mimalloc's + /// __DATE__/__TIME__ and anything else that reads the clock give one answer per commit (6 October 2026, the 0.3.14 repro) + pub node_commit_time: u64, pub node_dirty: bool, pub app_version: String, pub builds: Vec, @@ -161,7 +164,7 @@ pub fn parse_manifest(text: &str) -> Result { let s = |k: &str| v.get(k).and_then(|x| x.as_str()).unwrap_or("").trim().to_string(); let node = v.get("node").cloned().unwrap_or(Value::Null); let ns = |k: &str| node.get(k).and_then(|x| x.as_str()).unwrap_or("").trim().to_string(); - let mut m = Manifest { created_at: s("created_at"), node_branch: ns("branch"), node_commit: ns("commit"), node_commit_full: ns("commit_full"), node_dirty: node.get("dirty").and_then(|x| x.as_bool()).unwrap_or(false), app_version: s("app_version"), ..Default::default() }; + let mut m = Manifest { created_at: s("created_at"), node_branch: ns("branch"), node_commit: ns("commit"), node_commit_full: ns("commit_full"), node_commit_time: node.get("commit_time").and_then(|x| x.as_u64()).unwrap_or(0), node_dirty: node.get("dirty").and_then(|x| x.as_bool()).unwrap_or(false), app_version: s("app_version"), ..Default::default() }; let builds = v.get("builds").and_then(|b| b.as_array()).ok_or("manifest.json has no \"builds\" list")?; for (i, b) in builds.iter().enumerate() { let dir = b.get("dir").and_then(|x| x.as_str()).unwrap_or("").trim().to_string(); @@ -329,6 +332,11 @@ pub fn build_script(p: &BuildParams, job_id: &str, m: &Manifest, target: &str) - s.push_str(&windows_env()); } s.push_str(&format!("echo \"STAGE {target} start $(now)\"\n")); + if m.node_commit_time > 0 { + // reproducible builds: the commit's author time and UTC for every compiler of this stage; the target dir is the one + // persistent $CARGO_TARGET_DIR (never a per-run name: prost's generated code embeds OUT_DIR) + s.push_str(&format!("export SOURCE_DATE_EPOCH={} TZ=UTC; echo \"SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH TZ=UTC\"\n", m.node_commit_time)); + } s.push_str(&format!("mkdir -p \"$OUT/{target}\"\n")); s.push_str("rc_all=0\n"); // the node's full commit from the manifest (each stage is its own script; the extract stage read it too) @@ -498,7 +506,7 @@ mod tests { use super::*; use serde_json::json; - const MANIFEST: &str = r#"{"created_at":"2026-10-04T20:00:00Z","node":{"branch":"devnet-v4","commit":"3bfe346f","dirty":false,"source":"vendor/igneum-node-v4"},"repo":{"commit":"0f44edd","branch":"build-job","dirty":true},"app_version":"0.3.4", + const MANIFEST: &str = r#"{"created_at":"2026-10-04T20:00:00Z","node":{"branch":"devnet-v4","commit":"3bfe346f","commit_time":1791300000,"dirty":false,"source":"vendor/igneum-node-v4"},"repo":{"commit":"0f44edd","branch":"build-job","dirty":true},"app_version":"0.3.4", "builds":[{"dir":"node","packages":["kaspad","igneum-miner"],"features":["kaspad/igneum-pow"],"bins":["igneumd","igneum-miner"],"targets":["linux","windows"]}, {"dir":"app/igneum-app","packages":["igneum-app"],"bins":["igneum-app"],"optional_on":["linux"]}], "tests":[{"dir":"app/igneum-app","packages":["igneum-app"]},{"dir":"node","packages":["igneum-miner"]},{"dir":"node","packages":[]}]}"#; @@ -577,6 +585,8 @@ mod tests { let lin = build_script(&p, id, &m, "linux"); assert!(lin.contains("cargo build --release $JOBS -p kaspad -p igneum-miner --features kaspad/igneum-pow 2>&1")); assert!(lin.contains("cd \"$SRC/app/igneum-app\"")); + // reproducible builds (6 October 2026): the commit's author time and UTC exported before any cargo build of the stage + assert!(lin.contains("export SOURCE_DATE_EPOCH=1791300000 TZ=UTC") && lin.find("SOURCE_DATE_EPOCH=1791300000").unwrap() < lin.find("cargo build").unwrap(), "{lin}"); assert!(lin.contains("optional on linux: not fatal")); assert!(!lin.contains("--target x86_64-pc-windows-gnu")); // the windows stage ships the runtime DLLs of its own toolchain next to the exes; the linux stage does not diff --git a/docs/analysis/51-percent.md b/docs/analysis/51-percent.md new file mode 100644 index 000000000..e26dc4bcf --- /dev/null +++ b/docs/analysis/51-percent.md @@ -0,0 +1,84 @@ +# What a 51 percent attacker can and cannot do on Igneum + +6 October 2026. For the litepaper and the ledger. Written for a reader who maintains Monero or Kaspa and does not take a finality claim on trust. Every number names its model or its measurement; "approximate" marks the rest. Models and runs: `sim/horizon/consensus-security/` (`ghostdag_sim.py`, `finality_horizon.py`, `cost_model.py`, `signalling.py`), the finality simulator `sim/finality_v2.py` with `sim/results_v2.md`, the specification `docs/spec/02-consensus.md` and `03-finality.md`. The long form is `docs/analysis/horizon/consensus-security.md`. + +Price basis: USD 11.7 per GH/s-hour, measured on rented pods on 6 October 2026 (`docs/bench-log.md`, "Rental cost of hash": 1,748 MH/s for USD 20.44 an hour; the market supplied no more than about 2 GH/s that evening, so every figure above that is a list-price extrapolation). An attacker holding share A of the total hash rents A/(1 - A) times the honest network N. + +## 1. What 51 percent buys, and at what price + +Igneum orders blocks by GHOSTDAG (a rusty-kaspa fork, k = 18 at 1 block/s) and locks a checkpoint every 30 blue blocks when two thirds of the trailing 30 days of blue blocks, per vote key, have signed it (spec 03, Q3). The lock lands 63 to 93 s after the checkpoint block (determined 60 blue score later, certified about 3 s after; `sim/results_v2.md` A). + +A majority of hash buys the ordering race up to that lock. The DAG simulator (`ghostdag_sim.py`, GHOSTDAG as `vendor/igneum-node/consensus/src/processes/ghostdag/protocol.rs` runs it, 20 seeds per cell, one-way delay 0.67 s = the cloud devnet's p99 propagation) gives, at 1 block/s: + +| attacker share | hold 30 s | hold 60 s | hold 90 s | hold 120 s | +|---|---|---|---|---| +| 20% | wins 10%, reorg median 0 / max 18 | 0%, 0 / 1 | 0%, 0 / 1 | 0%, 0 / 1 | +| 34% | 40%, 0 / 18 | 40%, 0 / 36 | 5%, 0 / 39 | 10%, 0 / 52 | +| 51% | 85%, 10 / 15 | 85%, 20 / 28 | 80%, 32 / 44 | 80%, 42 / 53 | +| 67% | 100%, 8 / 13 | 100%, 16 / 23 | 100%, 26 / 31 | 100%, 34 / 41 | + +"wins" = the private chain became the honest selected chain on release; "reorg" = chain blocks removed. The arithmetic: a private chain merges honest blocks as blue until its first block has k in its anticone, then every later honest block is red in it; it wins when its R blocks plus k exceed the honest N_h, always at or above 50 percent, below it only for holds under k A / ((1 - 2A) lambda) seconds (6 s at 20%, 56 s at 34%). Withholding longer than the lock latency is useless: the first checkpoint inside the hold locks at most 93 s after it is mined, and a chain missing a certified checkpoint is not a fork-choice candidate (spec 03 F1). Bound: the lock latency, 90 to 120 s. Price of the 90-s race at 51 percent: USD 0.30 at 1 GH/s, USD 304 at 1 TH/s (`cost_model.py`). What it earns: a deposit credited before its lock, which the four-state rule forbids (ledger P17: a wallet shows included, executed, proven, finalised and credits on the last). + +Repeated 60-s withholding at 51 percent turns 26 to 28 percent of honest blocks red; a red block's subsidy goes to its merger (spec 02 2.5), so the majority takes about a quarter of honest income and lifts its weight share to about 56 percent (approximate), reorganising the chain every minute in public. It does not reach two thirds. + +The proving pool is the one place 51 percent earns more than it spends today. Consensus checks a proof record's signature and its statement against the node's own execution, and not the proof (spec 07 7.7 item 4, 7.8 item 8; ledger P21). A producer who writes the correct statement, random proof bytes and its own payout address into its own block is paid the shard; at 51 percent of blocks that is at least 51 percent of the 20 percent pool (11,636 IGN an hour at full subsidy) and, since its fake rides its next block while an honest proof takes 9 to 11 s on a 5090, most of the shards outside the 10-s exclusive window. Proof verification in consensus closes it; it is the first item in section 5. + +## 2. What it cannot do, and why + +| it cannot | because | measured | +|---|---|---| +| Reverse a certified checkpoint | a candidate tip must pass through every certified checkpoint (F1); two certificates at one index need two thirds of total weight each, 4/3 in all, so a conflicting pair needs an equivocator holding a third of 30 days of blocks (spec 03 3.11.2) | 0 conflicting locks under 1/3 in every partition and eclipse seed; conflicts from 34% (`sim/results_v2.md` H, I, L3, M5; `finality_horizon.py` P and E) | +| Reach two thirds of weight with 51 percent of blocks | weight is blue blocks over a flat 30-day window: share = (t/30) A, ceiling A; 51% holds 51% on day 30 and never more while honest miners mine | the formula holds to 0.1 day (`results_v2.md` B, `finality_horizon.py` R); red-flooding lifts it to about 56% (approximate) | +| Buy weight faster than mining it | a pulsed rental buys 0.26 blocks per hash under the controller (`sim/difficulty/attacks` scenario 2); a bought key is worth its blocks and decays as the window slides, share = A (1 - t/30) + r t/30 (3.11.5) | `results_v2.md` K, `finality_horizon.py` K: keys worth 51% hold the veto to day 24 and are worth 30% on day 30 | +| Forge state | every full node executes natively and ignores a record whose statement differs from its own execution (the veto, spec 07 7.2 item 5); a soundness bug is a light-client problem (P7) | the exec-attacks suite, 96 of 97 checks on the shipped node (`docs/review/redteam-2026-10-04.md` row 28) | +| Change a rule | code activates when 95% of a day's blue blocks signal it, with a floor height as backstop (P2, `docs/plans/counter-asic-3-node.md` section 6); the signal has 0.07 points of noise over 86,400 blocks, so 94.9% never flips and 95.1% flips on day one | `signalling.py`; the fast-time gate's three cases and its failed case | +| Grind the hourly program | the epoch seed is a 10-minute class-group VDF of a checkpoint block fixed 20 minutes before the epoch; withholding a block to pick a program has expected gain 0 against a 300x evaluator margin (spec 04 4.1, 4.6) | `proto-vdf` Monte Carlo over 2,000,000 epochs | +| Stretch the clocks | a header is at most 10 s ahead of the clock and 10 s behind its parent; a sanitised clock pays a forgery back | a 50% forger drifts the rate +0.4 to +1.1% (M23 fixed, `sim/difficulty/attacks/README.md`) | + +## 3. The table: capability against share, time, cost and earnings + +| capability | share | time | rent at 1 GH/s | at 100 GH/s | at 1 TH/s | subsidy it earns meanwhile (IGN) | net | +|---|---|---|---|---|---|---|---| +| Reorder the last k blocks | any | 20 s | USD 0 | 2 | 24 | 0 | a loss | +| Win the lock-latency race (90 s) | 45 to 51% | 90 s | USD 0.3 | 30 | 304 | 1k | nothing credited under a lock | +| Reach the veto (1/3 of weight): pause finality at will | 51% | 20 days | USD 6k | 585k | 5.8M | 22M | the attacker earns 51% of it back | +| the same | 90% | 11.1 days | USD 28k | 2.8M | 28M | 22M | | +| Lock alone (2/3 of weight): certify any chain forward | 67% | 30 days | USD 17k | 1.7M | 17M | 44M | 33% of the period's subsidy at equilibrium | +| the same | 90% | 22.2 days | USD 56k | 5.6M | 56M | 44M | | +| Hold a pause once the veto is held | 1/3 | for ever | 0 marginal | 0 | 0 | keeps earning | free | +| 12-h double spend during a pause or the first 30 days | 51% | 12 h | USD 146 | 15k | 146k | 559k | the deposit | +| Orphan an hour of honest blocks beyond merge depth (pause only) | 51% | 1.5 h | USD 18 | 2k | 18k | 70k | the honest hour's subsidy, lost to all | +| Private DAG heavier over the window (cold-start node, no certificate) | 51% | 30 days | USD 9k | 877k | 8.8M | 34M | one fresh node misled | +| Capture the proving pool with fake records | any producer | continuous | 0 extra | 0 | 0 | up to 20% of emission | the one positive line | +| Block a rule change | 6% | per day until the floor | USD 18 | 1.8k | 18k | 6% of subsidy | about zero | +| Pause finality by taking the two hands down (tonight's topology) | 0 hash | | a DoS | | | 0 | free | + +At the rental-market equilibrium, where hash joins until rent equals subsidy (39, 156 and 780 GH/s at IGN prices of USD 0.005, 0.02 and 0.10, the three inputs of `docs/analysis/security-budget.md`, not predictions), the veto nets about 48 percent of 20 days of the chain's subsidy and locking alone about 33 percent of 30 days (`cost_model.py` section 3). + +## 4. The residual risks, plainly + +1. **The pause.** Finality pauses whenever less than two thirds of 30-day weight is connected and signing, and the chain runs on proof of work with a 12-hour depth meanwhile (spec 03 3.7 item 2, 3.9). A third of weight holds the pause for nothing once it has it (`finality_horizon.py` S: 0 locks for the whole silence at 34 to 90 percent, 0 conflicts). During a pause a 51 percent miner is a 51 percent miner on any proof-of-work chain, with the 12-hour depth and USD 146 at 1 GH/s to buy it. What we are building against it is in section 5. + + **The departure case** (not an attack, the same pause): tonight on the live devnet 20 keys holding 42.7 percent of the frozen weight table stopped mining within three minutes (a rehearsal job), the signing weight fell to 53.1 percent at checkpoint 6843 and finality paused at 18:39:40Z; rule v2 would have locked again after 35 minutes as the departed blocks aged out of the sliding table, and the frozen table (Q5, the live rule) holds the pause for one window, 2 hours there and 30 days on mainnet; locks had formed with the hand nodes down, so it was weight, not topology (`docs/analysis/horizon/finality-and-weight.md` 3.1 and 4.1; `finality_horizon.py` C: 51 percent leaving pauses 10.5 days under v2, 30.0 under v3). A sudden exit of a third or more of weight, by a price crash or a hosting failure, does the same. What an attacker can do during it is exactly the pause line: proof of work with a 12-hour depth, nothing against any certificate, no new lock to forge; what it cannot do is end the pause early or lock alone, since the departed weight is still in the denominator. The fix is a signed departure (LEAVE, section 5): a key that announces it is leaving is out of every denominator one hour later, which a partitioned key cannot fake. +2. **The first 20 to 30 days.** No lock forms before the window holds 30 days of history (spec 03 3.8, `min_daa` = window): the first month is proof of work with the 12-hour depth, by design, and the renter's day counts start at genesis. On day 30 an attacker producing share s of blocks from day k holds s (31 - k)/30 of the window: 75 percent from day 2 locks alone on day 30 (ledger F1). +3. **Sybil of keys buys nothing; buying keys buys their blocks.** Weight is blue blocks and every draw is by weight (W6; harness s2). A pool's key with its history can be sold or stolen and is worth exactly its 30 days of blocks, decaying linearly as the window slides (K); the sellers' price, not hash, is the limit, and a seller who keeps a copy strips the buyer by equivocating. +4. **Two thirds of total under churn.** The denominator is every key's blocks in the window. If half the honest miners leave, a miner at 51 percent of the old hash holds 51/(51 + 24.5) = 67.5 percent of the window after 30 days and locks alone (spec 03 3.7 item 4: "same as Bitcoin, with a month's warning"). A departure that stops mining and signing at once pauses finality 30 (1 - 1/(3A)) days under rule v2 and until the frozen table expires, 30 days after the last lock, under rule v3 (`finality_horizon.py` C), because a view cannot tell a departure from a partition. +5. **A partition longer than a window forks finality.** Each side fills its own table; under v3 neither side under two thirds locks for 30 days after the last common certificate, then both lock alone at once (`results_v2.md` M3) and an operator's trusted certificate resolves it (3.11.4). Under a third of weight, no equivocator shortens that. +6. **The proving pool.** Section 1's fake-record capture, until proofs are verified in consensus. + +## 5. What we are building next + +| rank | defence | what it closes | cost | liveness cost | +|---|---|---|---|---| +| 1 | Proof verification in consensus: a record whose aggregated proof does not verify against the pinned key is invalid | the pool capture of section 1 | 8 to 12 hours; per-record verify time to measure | none | +| 2 | Weight-gated deep fork choice: a tip forked more than D (about 10 min) back is a candidate only if the keys that built it hold a third of the weight table at the fork | the pause-time and first-month deep reorg: rented hash has no weight for 10 days, so a 12-h double spend needs the 20-day veto | 10 to 16 hours | none for certificates; a sub-third partition side cannot reorg the other past D, which is the intended outcome | +| 3 | Vote-or-burn: a block whose key has participation under 0.5 in its own past burns 20 percent of its producer share | the free pause: silence then costs 7,757 IGN an hour at 34 percent | 6 to 8 hours | none; partition-safe by construction | +| 4 | Peer floor and mesh: every box dials three others beside the hands; the node alarms under three peers or two checkpoints without a vote; no `unwrap` on any peer-driven sync path (a pruned node was crashed by one request tonight) | a star fleet pausing on one host; one request crashing any pruned node | 5 to 7 hours + 4 | none | +| 5 | The vote signs the execution root too | snapshot poisoning, and "ordered and executed" in one certificate | 8 to 12 hours | lock latency plus executor lag | +| 6 | Signalling over 7 consecutive daily windows, the floor a week past the publish | a one-day renter forcing a flip | 3 hours | a week's latency on class changes | +| 7 | LEAVE, the signed departure (lane 3's rank 1): a `leave` item carried in blocks, the key out of every denominator one hour after inclusion, sent by the app and the fleet library on a clean stop; F5's trusted certificate implemented | tonight's 30-day-scale pause after a planned departure; sim: first lock 1 h after a 34 to 50 percent departure, 0 conflicts in every partition row (`finality-and-weight.md` 6) | 6 + 4 hours | none | +| 8 | A client-shipped certified checkpoint | the cold-start private DAG | 3 hours | none | + +Not adopted: prover attestations as a finality leg (the provers are the miners, coverage is a few percent, every lock would wait on a proof); vesting weight (a bought key transfers vested weight); any automatic rule that keeps locks going after an abrupt departure (a view cannot tell it from a partition: `results_v2.md` L4, M3). + +The honest sentence for the litepaper: a hash majority on Igneum can reorder about two minutes, can buy a veto over finality in twenty public days and then pause it for free, can double-spend at a 12-hour depth only while finality is paused or in the first month, and today can take the proving pool without proving; it cannot reverse a certificate, cannot reach two thirds of weight while honest miners mine, cannot forge state, and cannot change a rule without 95 percent of a day's blocks. diff --git a/docs/analysis/chip-model-v3.md b/docs/analysis/chip-model-v3.md index 9eb536b17..b35e6bc10 100644 --- a/docs/analysis/chip-model-v3.md +++ b/docs/analysis/chip-model-v3.md @@ -181,7 +181,7 @@ speed, so HBM3E is HBM3 here, and 48 Gbps GDDR7 is 28 Gbps GDDR7. |---|---|---|---| | Channels, banks | 64 channels, 1,024 banks | 16 channels (32 pseudo-channels), up to 1,024 banks | 128 channels, 8,192 banks | | Bank-bound ceiling, banks / 45 ns (tRC, the HBM2 and GDDR5-class figure, approximate for both) | 22.8 G reads/s | 22.8 | 182 | -| Activate-bound ceiling (GDDR7: 4 per 12 ns per channel, approximate; HBM: 8 per 12 ns per channel, O'Connor Table 2) | 21.3 G reads/s | 10.7 | 85.3 | +| Activate-bound ceiling (GDDR7: 4 per 12 ns per channel, approximate; HBM: 8 per 12 ns per channel, O'Connor Table 2). UNMEASURED (6 October 2026, the Horizon lane analysis `docs/analysis/horizon/algorithm.md` section 5.1): the JEDEC HBM2 table gives tFAW 28 ns, 4 activates per channel per window (ICCAD 2021 Table I), which is 2.3 G reads/s for a 16-channel stack, and the one measured random-read rate of an HBM2 part (Shuhai, Alveo U280, FCCM 2020 Fig 7) is 2.4 G, equal to that tFAW ceiling; the 12 ns figure holds only if a bank-interleaved mapping lifts tFAW, which the die enforces per channel. The HBM columns below carry the 10.7 G row as the model's ceiling, unmeasured; an AWS F2 hour (Virtex UltraScale+ VU47P, the same HBM2 subsystem) is the measurement | 21.3 G reads/s | 10.7 (unmeasured; 2.3 at JEDEC tFAW) | 85.3 (unmeasured) | | The ceiling carried below | 21.3 G reads/s (the 5090 measures 17.5, 82 percent of it: the card is already near its memory's activate limit) | 10.7 | 85.3 | | Energy per random 32-byte read (approximate) | 2.0 nJ: 909 pJ activation (one atom per row opened, the HBM2 1 KB row taken for GDDR7's row) plus 4.5 pJ per bit x 256 bits of movement and I/O = 1,150 pJ | 1.2 nJ: the HBM2 sum (909 + (1.51 + 1.17 + 0.80) x 256 = 1,800 pJ) scaled by Samsung's 4.12 / 6.25 | 1.2 nJ | | Static power (refresh, standby, PLLs; approximate, from memory) | 20 W (about 1.25 W per device) | 4 W | 32 W | @@ -191,6 +191,8 @@ speed, so HBM3E is HBM3 here, and 48 Gbps GDDR7 is 28 Gbps GDDR7. | Reads per second per watt at the ceiling (memory, static and controller) | 0.27 G | 0.40 G | 0.49 G | | The 5090 for comparison | 17.5 G reads/s at 326 W = 0.054 G per W; 7,262 reads in flight (17.5 G x 415 ns), 22 per watt | | | +The FPGA line, public (6 October 2026, the Horizon lane analysis section 5.1): an HBM2 FPGA soft overlay (Alveo U280 or U55C class) carries only the measured row, 2.4 G reads/s per card (Shuhai, FCCM 2020 Fig 7, equal to the JEDEC tFAW ceiling of 2.3 G at 28 ns), which is 0.30x to 0.39x of the RTX 5090 per watt (U55C at 115 to 150 W; 0.20x on the U280). The 11.4 G bank-bound row and the 12.2 G ceiling quoted elsewhere rest on a 12 ns tFAW the JEDEC HBM2 table does not give and are unmeasured until an AWS F2 hour (f2.6xlarge, VU47P, 16 GB HBM2, USD 1.98 an hour on demand) runs the chase kernel at 1 GiB across all 32 pseudo-channels; the lane's pass line is 15 to 25 M reads/s/W, its alarm line 27 (0.5x of the 5090), and over 54 (1.0x) the FPGA lane becomes a Counter ASIC 4.0 item. Consequence per tier: none today (no FPGA mines); if the measured row holds, a soft-overlay FPGA at USD 4,000 to 5,000 a card (approximate) mines at an RX 9070 XT's rate per watt for 7x the price, so no home or rig tier is displaced by it. Ledger M33. + The GDDR7 system's own power at the 5090's 17.5 G reads/s is 17.5 x 2.0 nJ = 35 W plus 20 W static, 55 W: about 17 percent of the card's 326 W (approximate). The other 83 percent is the GPU: 21,760 ALUs spinning at 92.9 percent utilisation on 512 program ops per hash, their register files, schedulers, L1 and L2, and the clock trees, against a diff --git a/docs/analysis/horizon-2026-10.md b/docs/analysis/horizon-2026-10.md new file mode 100644 index 000000000..7c7ff3cad --- /dev/null +++ b/docs/analysis/horizon-2026-10.md @@ -0,0 +1,37 @@ +# Horizon, October 2026: the ranked research across every system + +Written 6 to 7 October 2026 by the Horizon coordinator (branch `horizon`, worktree `igneum-wt-horizon`) on the project lead's ask of 6 October 2026, 20:4x UK: "deep backward and forward predictive research and modelling for our algo and all of our systems: is there room for improvement, room for more coin utility, algo improvements, security improvements, anything we can do to make a 51% attack impossible, basically creating a level of polish that has not been seen before." Later the same evening: "research anything else that we can research too, predictions, forward thinking, what we can actually do that has not been done or applied, think outside the box", "be revolutionary", and "if we create a new way of hashing or a new way of proof of work to revolutionise the space then that's absolutely fine, I want you to deploy everything to create something that has not ever been done before." + +The bar main set, and the bar this document holds every claim to: "impossible" is not available to any proof-of-work chain. The bar is that a majority of hash buys nothing: it cannot reverse what finality locked, cannot forge a proof the nodes re-execute, cannot change a rule without 95 percent signalling, and loses more than it earns. Every claim here is a number with a model or a simulation behind it, priced in rented hash at the measured 6 October rate (`docs/bench-log.md`, "Rental cost of hash, 6 October 2026": USD 0.0117 per MH/s-hour, the live devnet at 1.16 GH/s), with its consequence per tier and what to build. + +## The lanes + +| Lane | File | State | +|---|---|---| +| 1 consensus-security | `docs/analysis/horizon/consensus-security.md`, and the paper `docs/analysis/51-percent.md` | running | +| 2 algorithm | `docs/analysis/horizon/algorithm.md` | running | +| 3 finality-and-weight | `docs/analysis/horizon/finality-and-weight.md` | running | +| 4 economy-and-utility | `docs/analysis/horizon/economy-and-utility.md` | running | +| 5 network | `docs/analysis/horizon/network.md` | queued (waits for the 10 bps rows of `block-rate-devnet2.md`) | +| 6 polish | `docs/analysis/horizon/polish.md` | queued | +| 7 frontier | `docs/analysis/horizon/frontier.md`, model `sim/horizon/frontier/frontier_model.py` | landed 6 Oct 2026, 21:1x UK | +| 8 new-proof-of-work | `docs/analysis/horizon/new-pow.md`, prototypes in `proto-newpow/` | running (designs tonight, measured rows tomorrow afternoon UK) | + +## 1. One page for the project lead + +(Written last, from the lanes.) + +## 2. The ranked list: top 25 across every lane + +| Rank | Item | Lane | Evidence | Model | Hours | Consequence per tier | What to build | Gate | +|---|---|---|---|---|---|---|---|---| + +## 3. What a 51 percent attacker can and cannot do + +(Summary of `docs/analysis/51-percent.md`.) + +## 4. Per lane: the three biggest findings + +## 5. What was not run, and why + +## 6. Rules and corrections for main diff --git a/docs/analysis/horizon/algorithm.md b/docs/analysis/horizon/algorithm.md new file mode 100644 index 000000000..5b2f879a4 --- /dev/null +++ b/docs/analysis/horizon/algorithm.md @@ -0,0 +1,350 @@ +# Horizon lane 2: the shipped hash and its class system, refined + +6 October 2026, evening UK. Lane 2 (algorithm) of the Horizon programme. Worktree `/Users/joshm/Projects/igneum-wt-horizon`, branch `horizon` on master 3f4f719. Scope: the shipped lottery hash and its classes (v2, v3 live, the v4 candidate `mx8+sh256x27`, the reserve R0 to R8, the era draw, the dataset schedule). No new puzzle is proposed here (lane 8 owns that). Every chip figure is arithmetic on cited figures and is approximate; every GPU figure names its bench-log entry or analysis file; the one new measurement is the verifier proxy on igneum-build-1 (section 2). + +What was read, in full unless marked: `docs/spec/01-lottery-hash.md`, `docs/spec/04-seeds-and-vdf.md`, `docs/analysis/chip-model-v3.md`, `docs/analysis/asic-resistance-history.md`, `docs/analysis/latency-shadow-2026-10-06.md`, `docs/analysis/m16-recompute-attacker-2026-10-05.md`, `docs/analysis/sram-mirror.md`, `docs/analysis/int8-matrix-family.md`, `docs/analysis/weak-program-census-2026-10-03.md` (section 1), `docs/analysis/scratch-soundness.md` (section 0), `docs/analysis/card-lifetime-2026-10-05.md`, `docs/plans/counter-asic-3-status.md`, `docs/plans/counter-asic-3-reserve.md`, `docs/plans/counter-asic-3-derivation.md`, `docs/plans/counter-asic-2.md`, `docs/plans/epoch-length.md` (sections 11 and 12), `docs/plans/era-layout.md`, `docs/plans/mixer-x4.md` (sections 6.2 to 6.5), `docs/plans/read-width.md`, `docs/fud-ledger.md` (M1 to M31 headings; M9, M16, M17, M18 in full; M28 heading), `docs/bench-log.md` (entries "Counter ASIC 2.0, the numbers", "the 9070 XT on the eGPU", the 6 October item 8, item 6 and gate-run entries, "Rental cost of hash, 6 October 2026"), `igneum-pow/src/generator.rs` (the class constants, `ShadowClass`, `LoadClass::{V2, MX4, MX8, DR736}`), `igneum-pow/src/memhard.rs` (`Shape`, the growth rule, `round_key`, `derive_items_mask`), `igneum-pow/src/main.rs` (`bench`), `docs/analysis/prover-tiers-real-cards.md` (the 11 rented cards), and `/Users/joshm/Projects/igneum-wt-gpu-fleet/docs/analysis/block-rate-devnet2.md` (RUN_A and RUN_B are still placeholders at 21:30 UK; nothing from it is used). + +## 1. The six questions and the one-line answers + +| # | Question | Answer in one line | +|---|---|---| +| 1 | Chip model on the 6 October numbers; the FPGA lane | The stored-dataset chip (f = 1, GDDR7) reads 5.7x per joule against the 5090 bench row and 1.7x against the M5 Max at class v3; at class v4 and k = 1 those fall to 2.1x and 0.9x. Per dollar it is 56x under rented hash and 5.4x under an owned 5090 per MH/s-hour. The FPGA soft overlay tightens to 0.30x to 0.47x per watt: the measured 2.4 G reads/s equals the JEDEC tFAW ceiling of a 2-stack HBM2 part, so the 1.9x bank-bound row is unreachable on any FPGA that exists. AWS F2 at USD 1.98 an hour carries the exact HBM2 subsystem and can measure it | +| 2 | Reserve R0 to R8 | Every reserve family together costs a chip about 8 to 14 adders per lane, about USD 4 of N5 silicon on a 14,000-lane array; none moves the per-joule edge by over 10 percent. The reserve's value is obsolescence of a datapath taped out against class v3, and since the order is public that value is zero against a chip that ships with every block. Recommended order: R0 derive at dr368 (dr736 fails the gate proxy), R1 shfla, R2 perm, R3 popc and clz, R4 bfe, R5 shifts, R6 sel, R7 andn, R8 mm8 at era 8 by the rule, no exception | +| 3 | A class v5 from the shadow | Option (i) is void: the v4 shadow already consumes loaded data (its registers hold the dataset words of the iteration), so a chip precomputes nothing today. Option (ii), a shuffle-heavy shadow mix, raises the attacker's k floor from about 0.32 to 0.46 (approx), not to 1. Option (iii): the one N every owned card holds within 5 percent is 130,000 counted ops (the M5 Max's point); it buys 2.1x to 1.7x against the 5090 at k = 1 for 4.8 percent of the Mac's rate; the verifier at 130,000 is 4.9 ms on the box proxy and 8.5 ms on the half-core proxy, inside the gate | +| 4 | The era draw's randomness | Forging the certified checkpoint the era VDF reads costs 20 days of 100 percent hash: USD 5,600 at 1 GH/s, USD 5.6M at 1 TH/s rented, and buys one draw of a space whose spread is 0.8 to 3.2 percent of hash rate per card and 0 percent for a chip. Re-rolling by withholding needs a 1,800x faster VDF. The draw buys nothing against a chip; the public reserve order means a chip is taped out with every block. What would cost a chip is work (N) and the honest card's own watts, not unpredictability | +| 5 | The 2019-class verifier | Measured proxy tonight: a Zen 4 core at 3.8 GHz with server DRAM reads 2.0x to 2.2x the M5 Max core (v4 4.90 ms steady, 5.06 cold; dr736 9.76 steady, 10.51 cold: FAIL); with both SMT siblings busy (the pessimistic bracket) v4 8.23 ms, dr368 8.16, dr736 15.5. The 2.5x rule holds within 15 percent. The gate protects a node at 1 to 10 percent of one core per block rate, an 18-minute IBD, and a header-flood cost of 100 bogus headers per second per core | +| 6 | Dataset growth to 2030 | Hold option (b): 2 GiB at genesis, 4 GiB at year 4, 8 GiB at year 12. The 8 GB tier (26.7 percent of Steam today, about 0 by 2030 on the trend) mines to year 12 anyway; the 12 GB tier loses mine-and-prove compressed at the year-4 step and the 8 GB tier loses core-only at genesis, and both are the prover's footprint, not the dataset's. Growth is for the SRAM reticle (1.6 GiB per reticle at N5) and GPU L2, not for the HBM chip | + +## 2. Method + +| Item | What was done | Where | +|---|---|---| +| The model | One Python script, every table in this file; inputs listed with source and label | `sim/horizon/algorithm/model.py`, `README.md` beside it | +| Verifier proxy | `igneum-pow` built on igneum-build-1 through `tools/build-remote.sh` from the crate directory (`IGNEUM_AGENT=horizon`, build slot build-0, 10 s wall, sccache miss 1, artefact 991,352 bytes, sha256 6d2867...); `igneum-pow bench --seed igneum-genesis --day 2026-10-03 --class --warps 50` for v2, mx8, mx8+sh256x27, dr368, dr736 under `nice -n 19 taskset -c 40` (one core), then the same on cores 40 and 88 at once (the two SMT siblings of one physical core: `thread_siblings_list` 40,88); load average 1.3 before, 2.3 after; `scaling_cur_freq` read 3,799,885 kHz during a run (the governor is schedutil with `scaling_max_freq` 2,750,000 but the core boosted to 3.8 GHz; `cpupower` needs root, so no fixed low clock was possible); the cache fill 361 ms on that core | section 5.5 | +| Not run | A Mac packbench ladder for v5 (the data-dependent and shuffle-heavy shadow variants do not exist as kernel text, so nothing could be measured; the plan is in 5.3); any PC job; any FPGA | section 7 | +| External figures | Steam Hardware Survey September 2026 (store.steampowered.com/hwsurvey, read 6 October 2026); ICCAD 2021 "Demystifying the Characteristics of High Bandwidth Memory for Real-Time Systems" Table I (JEDEC HBM2 timings in cycles at 2,133 MT/s, text extracted with pdftotext); Intel HBM2 IP user guide (16 AXI pseudo-channel ports per stack); AWS F2 pricing (f2.6xlarge USD 1.98 an hour on-demand, USD 0.66 spot, one VU47P with 16 GB HBM2) | section 5.1 | + +## 3. Evidence + +### 3.1 Honest cards, measured (class v3 unless said) + +| Card (tier) | MH/s | W | uJ per hash | Source | +|---|---|---|---|---| +| RTX 5090, PC 2 bench, 431 W cap, the control | 132.2 | 350 | 2.65 | `latency-shadow-2026-10-06.md` s5; bench-log item 8 | +| RTX 5090, PC 1 app, Ember run 5 | 127.4 | 310 | 2.43 | `counter-asic-3-status.md` s7 item 1 | +| RTX 5090, app 5 October | 124 | 290 | 2.34 | `miner-eff` record, cited in latency-shadow s3 | +| RTX 5090, rented Vast pod, untuned | 98.5 | 258 | 2.62 | `prover-tiers-real-cards.md` | +| RTX 4090, rented | 52.3 | 183 | 3.50 | same | +| RTX 3090, rented | 37.8 | 229 | 6.05 | same | +| RTX A5000, rented | 47.7 | 223 | 4.67 | same | +| RTX 4070, PC 1, 1,860 MHz lock, 160 W cap | 30.95 | 79.5 | 2.57 | status item 8, 4070 rows | +| RTX 4070, rented | 25.0 | 91 | 3.65 | prover-tiers | +| RTX 5070, rented | 41.9 | 137 | 3.27 | prover-tiers | +| RTX 3060, rented | 23.8 | 104 | 4.36 | prover-tiers | +| RTX 3080, rented | 40.8 | 205 | 5.02 | prover-tiers | +| RTX 4060 Ti 16 GB, rented | 17.6 | 72 | 4.11 | prover-tiers | +| RTX 4060 Ti 8 GB, rented | 19.1 | 73 | 3.81 | prover-tiers | +| RTX 4060, rented | 17.1 | no reading (0.0 W logged) | n/a | prover-tiers | +| RX 9070 XT, PC 1 | 18.9 | 199 to 203 | 10.6 | bench-log 9070 XT telemetry; status 3a | +| Apple M5 Max, GPU + DRAM channels | 27.08 | 21.0 | 0.78 | latency-shadow s3 | +| Apple M5 Max, package (approx) | 27.08 | 38 | 1.40 | `ember-tune.md`, approximate | + +At class v4 (`mx8+sh256x27`, measured): the 5090 131.95 MH/s at 431 W (3.27 uJ, the cap binds), the M5 Max 26.67 at 37.2 W (1.39), the 4070 31.08 at 109 W (3.51), the 9070 XT 19.29 at owed watts. Every other card's v4 energy below is modelled as the card's marginal ALU energy times N (NVIDIA 11 pJ per counted op measured on the 5090, Apple 6.9 measured on the M5 Max, AMD taken as NVIDIA's, approximate). + +### 3.2 Chips (model, approximate; `chip-model-v3.md` s5.4, latency-shadow s6) + +| Chip class | MH/s | W at v3 | uJ, v3 | uJ at v4, k = 0.3 / 0.5 / 1 / 1.5 | $ silicon + memory, v3 / v4 | $ per MH/s | +|---|---|---|---|---|---|---| +| f = 0 on-die recompute, 256 MiB SRAM, x8 | 41.7 | 53.7 | 1.29 | 1.62 / 1.84 / 2.39 / 2.94 | 700 / 740 | 16.8 | +| f = 1 stored dataset, GDDR7, 16 devices | 166.4 | 77.6 | 0.466 | 0.80 / 1.02 / 1.57 / 2.12 | 470 / 510 | 2.8 | +| f = 1, HBM3 one stack | 83.6 | 26.8 | 0.321 | 0.65 / 0.87 / 1.42 / 1.97 | 550 / 590 | 6.6 | +| f = 1, HBM3 eight stacks | 666 | 174 | 0.262 | 0.59 / 0.81 / 1.36 / 1.91 | 2,650 / 2,690 | 4.0 | + +`k` is the chip core's energy per counted op over the 5090's measured 11 pJ. The f = 0 chip's measured stand-in (M16 round 2, the inline kernel inside the 5090's L2) ran 33.9 MH/s at 431 W: 0.256x per chip and 5x worse per joule than honest, so the f = 0 row above is the model's ceiling for that class, not a measurement. + +### 3.3 The verifier proxy, measured tonight (igneum-build-1, EPYC 9454P, one core at 3.8 GHz, nice 19) + +| Class | M5 Max core, quiet | 2.5x rule (approx) | Box one core, steady / cold | Box over Mac | Box half-core (SMT sibling loaded) | 10 ms gate | +|---|---|---|---|---|---|---| +| v2 | 0.60 | 1.5 | 1.13 / 1.30 | 1.88x | not run | pass | +| mx8 (class v3) | 2.06 | 5.2 | 4.52 / 4.67 | 2.19x | 7.56 | pass | +| mx8+sh256x27 (class v4) | 2.33 | 5.8 | 4.90 / 5.06 | 2.10x | 8.23 | pass | +| dr368 | 2.69 | 6.7 | 4.72 / 5.32 | 1.75x | 8.16 | pass, thin on the half-core | +| dr736 | 4.88 | 12.2 | 9.76 / 10.51 | 2.00x | 15.49 | FAIL (cold run over 10 ms on one core; 15.5 on the half-core) | + +Raw lines (the Mac figures are `counter-asic-3-derivation.md` 5.1 and the gate-run entry): box one core `CPU verify: 1.128 / 4.516 / 4.901 / 4.716 / 9.763 ms per 32-lane warp, avg of 50`; cold `warp base 0: 1.305 / 4.670 / 5.061 / 5.324 / 10.509 ms`; half-core `7.562 / 8.234 / 8.162 / 15.491` (cpu 40) and `7.556 / 8.227 / 8.168 / 15.479` (cpu 88); every lane-0 and lane-31 hash equal to the Mac's vectors (`42246ba99fc58e4f`, `19b56348bc85304d`, the dr736 `e23d389f3eea0c83`). Cache fill 360.5 to 364.7 ms on the box core against 175 to 181 on the M5 Max. + +### 3.4 Installed base (Steam Hardware Survey, September 2026, cited) + +| VRAM | Share | Trend (cited: 8 GB 35.03 percent in August 2025, 33.66 in September 2025; 12 GB 19.30 in August 2025) | +|---|---|---| +| 512 MB to 4 GB | 14.06% | falling | +| 6 GB | 5.12% | falling | +| 8 GB | 26.71% | about -7 points a year | +| 10 to 11 GB | 2.74% | flat | +| 12 GB | 13.06% | about -6 points a year | +| 16 GB | 27.21% | rising; overtook 8 GB in August 2026 | +| 20 to 24 GB | 7.93% | rising slowly | +| 32 GB | 1.41% | rising slowly | +| 64 GB | 0.50% | new row | + +### 3.5 Rental and ownership cost (bench-log "Rental cost of hash, 6 October 2026", measured) + +USD 0.0117 per MH/s-hour on RunPod community pods (1,748 MH/s for USD 20.44 an hour); the 8x 4090 rig USD 0.0129; a 5090 pod USD 0.41 to 0.74 an hour for 98 to 128 MH/s. + +## 4. Model + +| Formula | Inputs (label) | +|---|---| +| Energy per hash E = W / rate | measured watts and MH/s per card; chip W from `chip-model-v3.md` 5.4 (approx) | +| Chip energy at class v4: E_v3 + N x 11 pJ x k | N = 100,000 counted ops (measured class v4), 11 pJ = the 5090's marginal per op (measured), k free | +| Edge per joule = E_card / E_chip | both sides above | +| Hourly cost per MH/s = price / (2 years x rate) + E x 3.6e9 x USD 0.10 per kWh | prices approximate (launch list from memory, labelled); chip $ from 5.4; electricity approx | +| FPGA random-read ceiling = min(banks / tRC, channels x 4 / tFAW, channels / tRRD) | 2 stacks, 16 channels, 32 pseudo-channels, 16 half-banks each (approx); tRC 48 cycles, tFAW 30, tRRD 6 at 1,066 MHz (ICCAD 2021 Table I, JEDEC HBM2); latency 137.8 ns (Shuhai, measured) | +| Reads in flight = rate x latency; per watt = rate / board W | U55C 115 to 150 W, U280 225 W (datasheets) | +| Verifier add per warp = shadow instructions / 1,000 x slope | slope 3.2 us (M5 Max, measured), 7.0 us (box one core, this lane), 12.1 us (box half-core, this lane) | +| Checkpoint forgery cost = network MH/s x 480 h x USD 0.0117 | 20 days of 100 percent hash to 2/3 weight (CLAUDE.md headline, from the finality sim) | +| Tier fit at a dataset step: miner resident = dataset + 192 MiB; prover peak beside the miner from `prover-tiers-real-cards.md` scaled by the dataset's growth | usable VRAM 75 percent (mine-only), 98 percent headless (the prover rows) | + +## 5. Results + +### 5.1 Task 1: the chip model on the 6 October numbers, and the FPGA lane + +Per joule and per dollar against every honest card (the full table with every card is the `chip` section of the model; the rows that decide things): + +| Card (tier) | uJ v3 / v4 | f = 0 chip edge, v3 / v4 at k = 1 | f = 1 GDDR7 edge, v3 / v4 at k = 0.3 / 0.5 / 1 / 1.5 | f = 1 HBM3 one stack, v3 / v4 at k = 1 | $ per MH/s (card, approx) | USD per MH/s-hour owned | +|---|---|---|---|---|---|---| +| RTX 5090 bench (32 GB) | 2.65 / 3.27 | 2.1x / 1.4x | 5.7x / 4.1x / 3.2x / 2.1x / 1.5x | 8.3x / 2.3x | 15.1 | 0.00113 | +| RTX 5090 app, Ember (32 GB) | 2.43 / 3.53* | 1.9x / 1.5x | 5.2x / 4.4x / 3.5x / 2.3x / 1.7x | 7.6x / 2.5x | 15.7 | 0.00114 | +| RTX 4090 rented (24 GB) | 3.50 / 4.60* | 2.7x / 1.9x | 7.5x / 5.8x / 4.5x / 2.9x / 2.2x | 10.9x / 3.2x | 30.6 | 0.00210 | +| RTX 3090 rented (24 GB) | 6.05 / 7.15* | 4.7x / 3.0x | 13.0x / 9.0x / 7.0x / 4.6x / 3.4x | 18.9x / 5.0x | 39.7 | 0.00287 | +| RTX 4070 PC 1 tuned (12 GB) | 2.57 / 3.51 | 2.0x / 1.5x | 5.5x / 4.4x / 3.5x / 2.2x / 1.7x | 8.0x / 2.5x | 17.7 | 0.00127 | +| RTX 5070 rented (12 GB) | 3.27 / 4.37* | 2.5x / 1.8x | 7.0x / 5.5x / 4.3x / 2.8x / 2.1x | 10.2x / 3.1x | 13.1 | 0.00108 | +| RTX 3060 rented (12 GB) | 4.36 / 5.46* | 3.4x / 2.3x | 9.4x / 6.9x / 5.4x / 3.5x / 2.6x | 13.6x / 3.8x | 13.8 | 0.00123 | +| RTX 4060 Ti 8 GB rented (8 GB) | 3.81 / 4.91* | 3.0x / 2.1x | 8.2x / 6.2x / 4.8x / 3.1x / 2.3x | 11.9x / 3.5x | 20.9 | 0.00157 | +| RTX 4060 Ti 16 GB rented (16 GB) | 4.11 / 5.21* | 3.2x / 2.2x | 8.8x / 6.5x / 5.1x / 3.3x / 2.5x | 12.8x / 3.7x | 28.4 | 0.00203 | +| RX 9070 XT (16 GB AMD) | 10.6 / 11.7* | 8.3x / 4.9x | 22.8x / 14.7x / 11.5x / 7.5x / 5.5x | 33.2x / 8.3x | 31.7 | 0.00287 | +| Apple M5 Max, GPU + DRAM | 0.78 / 1.39 | 0.6x / 0.6x | 1.7x / 1.8x / 1.4x / 0.9x / 0.7x | 2.4x / 1.0x | 129 | 0.00745 | +| Apple M5 Max, package (approx) | 1.40 / 2.02 | 1.1x / 0.9x | 3.0x / 2.5x / 2.0x / 1.3x / 1.0x | 4.4x / 1.4x | 129 | 0.00752 | + +`*` modelled v4 energy. The chip's hourly cost per MH/s (two-year amortisation plus electricity, approx): f = 1 GDDR7 USD 0.00021, HBM3 one stack 0.00041, eight stacks 0.00025, f = 0 recompute 0.00109; an owned 5090 0.00113; rented hash 0.0117. So the stored-dataset chip undercuts rented hash 56x and an owned 5090 5.4x per MH/s-hour, and the recompute chip matches the 5090 exactly, which is why nobody builds it. + +What changed against the 5 October record: the honest denominators moved (the 5090 is 2.34 to 2.65 uJ by where it is measured, not 2.40), the marginal ALU energy is measured at 11 pJ (not the model's 5.5), the M5 Max at 0.78 uJ is the honest best per joule by 3x, and the rented fleet shows the untuned mid-tier (3060, 3080, 3090, A5000, 4060 Ti) at 3.8 to 6.1 uJ, 1.5 to 2.3x worse than the 5090 bench row: against those cards the GDDR7 chip reads 8x to 13x per joule at v3 and 3.1x to 4.6x at v4 with k = 1. The per-tier reading: the Apple tier is already inside 2x of the GDDR7 chip with no shadow and crosses under 1x at v4 and k = 1; the 5090 and the tuned 4070 reach about 2.1x to 2.2x at v4 and k = 1; the untuned mid-tier and AMD stay at 3x to 7.5x, which Ember tuning (the 4070 rows: 3.65 to 2.57 uJ) closes by about 30 percent and nothing in the hash closes further. + +The FPGA lane. The brief's soft-overlay range was 0.30x to 0.39x per watt measured-basis and 0.7x to 1.9x at an unmeasured bank-bound ceiling. The reads-in-flight model with the JEDEC HBM2 timings: + +| Ceiling | Formula | G reads/s per card | Reads in flight at 137.8 ns | Per W at 115 / 150 / 225 W (M/s/W) | Against the 5090 per W (53.7 M at 326 W) | +|---|---|---|---|---|---| +| Measured, Shuhai U280 default mapping (FCCM 2020, Fig 7) | 32 pc x 75 M | 2.4 | 331 | 21 / 16 / 11 | 0.39x to 0.30x (U55C); 0.20x (U280) | +| tFAW-bound (JEDEC HBM2, ICCAD 2021 Table I: 30 cycles at 1,066 MHz, 4 ACT per channel) | 16 ch x 4 / 28.1 ns | 2.3 | 313 | 20 / 15 / 10 | 0.37x to 0.28x; 0.19x | +| tRRD-bound (6 cycles) | 16 ch / 5.6 ns | 2.8 | 392 | 25 / 19 / 13 | 0.46x to 0.35x; 0.24x | +| Bank-bound, no activate window (the epoch-length 12.2 ceiling row) | 32 pc x 16 banks / 45 ns | 11.4 | 1,567 | 99 / 76 / 51 | 1.84x to 1.41x; 0.94x | +| O'Connor's HBM2 activate figure as carried by chip-model-v3 5.3 | 16 ch x 8 / 12 ns | 10.7 | 1,470 | 93 / 71 / 47 | 1.73x to 1.32x; 0.88x | + +The reading: Shuhai's measured 2.4 G/s equals the tFAW ceiling at JEDEC timings (2.3 G/s). The measured row was read on 6 October as a mapping artefact ("the paper's point is that this mapping is the wrong one for random access"); the activate window says it is the DRAM's own limit, which a bank-interleaved mapping does not lift because tFAW is enforced per channel by the die. The 11.4 G bank-bound row needs tFAW gone; O'Connor's 12 ns figure (which the chip model carries for HBM2 and HBM3) is 2.3x shorter than the JEDEC HBM2 cycle count tabled by ICCAD 2021, and the difference is the whole 0.7x to 1.9x row. Tightened range for a 2-stack HBM2 FPGA (U55C, U280, F2's VU47P): 2.3 to 2.9 G reads/s, 0.30x to 0.47x of the 5090 per watt, in the RX 9070 XT's class (2.4 to 2.7 G/s measured). HBM2e parts (Versal HBM, Agilex 7 M) raise the pin rate, not tFAW in nanoseconds (approx), so they sit in the same band; no FPGA with HBM3 exists as a product. Approximate throughout: the 16 half-banks per pseudo-channel, the 1,066 MHz reading of the ICCAD table, the board watts under load. + +Can a rented FPGA hour measure it? Vast.ai lists no FPGAs (GPU marketplace only, checked 6 October 2026). AWS F2 (f2.6xlarge: one Virtex UltraScale+ HBM VU47P, 16 GB HBM2 in 2 stacks, 32 pseudo-channels, USD 1.98 an hour on-demand in us-east-1, USD 0.66 spot) carries the same HBM2 subsystem as the U55C and U280, so yes. The gate, written as a measurement plan: + +| Step | What | Hours (agent) | Pass line | +|---|---|---|---| +| 1 | Port the chase kernel of `docs/benchmarks/repro.md` 2.2 to a Vitis HLS AXI master over the HBM IP: 1 GiB working set across all 32 pseudo-channels, N dependent 4-byte-reads-in-flight lanes (N = 256, 1,024, 4,096), the HBM IP's address map set to bank-interleaved (RAMA or the IP's "random access" option), a second variant with 32-byte reads | 4 to 6 | the kernel reports reads per second and the chain's checksum equal to the CPU's | +| 2 | Build the AFI (the F2 shell flow; the Vivado licence rides with the instance), 2 to 4 hours of F2 time at USD 2 to 8 | 2 (mostly waiting) | an AFI that loads | +| 3 | Run the ladder; read board power through `xbutil examine --report electrical` (or the F2 shell's sensors) at 1 Hz; take the mean over each run | 1 | reads per second and watts per rung | +| 4 | Write the row into `epoch-length.md` 12.2 in place of the ceiling row | 1 | the public claim carries a measured FPGA number | +| Gate | reads per second per watt at 1 GiB | | expected 15 to 25 M/s/W (0.3x to 0.5x of the 5090); the alarm line is 27 M/s/W (0.5x); over 54 M/s/W (1.0x) the FPGA lane becomes a Counter ASIC 4.0 item | + +Consequences per tier of the FPGA finding: none today (no FPGA mines); if the measured row holds, a soft-overlay FPGA at USD 4,000 to 5,000 a card (approx) mines at an RX 9070 XT's rate per watt for 7x the price, so no home or rig tier is displaced by it; the per-program bitstream lane stays answered by layer 9. + +### 5.2 Task 2: the reserve R0 to R8 + +| Slot | Family | Chip block it adds (approx area in 32-bit adders per lane, `counter-asic-3-reserve.md` s3) | Chip datapath energy per op, N5 floor (pJ, approx) | Honest step cost, Apple / NVIDIA / AMD (measured, ratio to the add-xor-rotate chain) | Verifier cost | Chip edge per joule it moves (model) | Cost per tier | +|---|---|---|---|---|---|---|---| +| R0 | derive (per-day item program) | a sequencer: 60 KB instruction store, 16-register file, ALU with multiplier and rotator; removes the 3x fixed-function credit of the f = 0 chip | n/a (it is the f = 0 chip's item cost: 9,992 ops per item) | hash rate 0 on all three vendors; daily build +7 ms Mac, 0 on the 5090 and 9070 XT; compile +0.75 s Mac, +1.1 s NVRTC, +2.0 s AMD per day (a once-a-day module is a requirement) | dr736 +2.8 ms per warp on the Mac, +5.2 on the box core, over the gate cold; dr368 +0.6 Mac, +0.2 box, 8.16 on the half-core | f = 0 chip: 0.92x to 0.34x to 0.43x per chip; per joule from 1.86x to about 0.7x to 0.9x at the same allowance (approx); f = 1 chips: 0 | pool verifier cores x2.4 at dr736, x1.3 at dr368; every miner tier 0 | +| R1 | shfla (lane + delta) | 32-lane x 32-bit crossbar per warp, 32,768 mux bits, 3 to 6 adders per lane | 1.00 | 1.91 / 1.53 / 0.75 to 0.84 | one op per instruction, under 0.01 ms per warp at W_new = 4 | shadow floor +21 percent at 5 percent of instructions (approx); the GPU pays 1.5x the step too, so k unchanged | Apple under 1 percent of ALU time (argued), NVIDIA and AMD 0 | +| R2 | perm (byte permute) | 4x4 byte crossbar, 128 mux bits, 1 to 2 adders | 0.10 | 1.13 emulated / 1.30 / 1.73 to 1.93 emulated | negligible | under 1 percent | Apple and AMD emulate at 1.1x to 1.9x per op: under 1 percent at 4 points | +| R3 | popc and clz | popcount tree and priority encoder, 1.5 to 3 adders | 0.10 | 0.87 and 1.01 / 1.50 and 1.63 / 0.91 to 1.01 and 1.19 to 1.30 | negligible | under 1 percent | 0 | +| R4 | bfe | mask generator on the shifter, 0.3 adders | 0.06 | 0.77 / 1.54 / 1.00 to 1.09 | negligible | 0 | 0 | +| R5 | shl, shr | barrel shifter beside the rotator, 0.2 adders | 0.06 | 0.85 and 0.86 / 1.27 and 1.28 / 1.00 to 1.02 and 0.91 to 1.02 | negligible | 0 | 0 | +| R6 | sel | 32 muxes, 0.3 adders | 0.03 | 0.76 / 1.32 / 0.90 to 1.01 | negligible | 0 | 0 | +| R7 | andn | 32 inverters, under 0.1 adders | 0.02 | 0.75 / 1.26 / 0.91 to 1.01 | negligible | 0 | 0 | +| R8 | mm8 | 8x8x16 u8 MAC tile per warp, about 100 adders per lane; licensable IP at every node | 1.60 | owed (Metal 4 matmul2d) / 2.43 / 1.68 to 1.83 native, exactness unverified | 1,024 MACs per instruction per unit, about 10 us per warp at W_new = 4 | shadow floor +37 percent at 5 percent of instructions (approx); the GPU pays 2.4x the step: k unchanged or worse for the GPU | Apple pays the library path (owed); NVIDIA and AMD native | + +The ordering argument. Against the f = 1 chip, which is the chip anyone builds, every family R1 to R8 moves the per-joule edge by under 10 percent, because the chip's cost at class v4 is N x k x 11 pJ and a family changes the per-op energy of 4 points in 79 of the shadow mix. Against the f = 0 chip only R0 matters (it is the item cost). So the reserve's function is not per-joule resistance; it is to make a datapath taped out against class v3's eleven families wrong at the first unlock. A chip maker who reads this document tapes out every block from day one: R1 to R7 together are about 8 to 14 adders per lane (a lane with a 32x32 multiplier is about 35), about 11 mm^2 on a 14,000-lane N5 array, about USD 4 of silicon (sram-mirror.md's USD 0.36 per mm^2, approx); R8 is a licensed tile. The era schedule therefore buys nothing against a chip and the order can be set by honest cost alone: the largest new structure first while every vendor's measured step cost is in (shfla: AMD measured cheap at 0.75 to 0.84, which the reserve document said was the one number that could move it to R1), the emulated families next, mm8 last at era 8 by the rule (no era-4 exception: mm8 removes no adversary class, `epoch-length.md` 12.4). R0 enters at dr368, not dr736: the box proxy puts dr736 over the gate on a cold run (10.5 ms) and at 15.5 ms on the half-core; dr368 reads 4.7 and 8.2. + +Recommended text change to `counter-asic-3-reserve.md` section 5: R1 shfla, R2 perm, R3 popc and clz, R4 to R7 unchanged, R8 mm8 at era 8; R0 at `derive_len = 368` with 736 behind the O-1.14 measurement. The era schedule "family n at era n" stands; what it costs per tier at each unlock is the step-cost table above (Apple under 1 percent of ALU time per family, NVIDIA and AMD nothing measurable), and what it buys is stated honestly in the public text (section 6, proposal 4). + +### 5.3 Task 3: a class v5 from the shadow + +The three options, each priced: + +(i) Shadow ops that depend on the loaded data. The v4 shadow block runs at the end of every iteration on the eight lane registers, and those registers hold the words the iteration's 16 loads XORed in (`generator.rs`: the block is executed after instruction 63 with the iteration's `sel`; `verify.rs` runs it with the same `step`). So every shadow op already consumes loaded data, and the next iteration's load addresses depend on the shadow's outputs. A chip cannot precompute any of it; what it can do is what the GPU does: overlap one lane's shadow with another lane's reads in flight. Option (i) therefore moves k by 0. A variant that draws the shadow's immediates from loaded words is M18's one-bit select at 32 bits: a chip wires the operand, and it is not a defence. Verdict: void; no measurement needed. + +(ii) Shadow work that exercises GPU structures a chip lacks. Bank-conflict timing is not a value and cannot enter a bit-exact function. Register-file width (8 registers today) can be widened in the shadow to 16 or 32 (ProgPoW used 32): a chip's register file per lane in flight grows from 32 B to 128 B, 1.8 MB on a 14,000-lane array, trivial. Warp shuffles are the structure that costs: the xor-mask shuffle needs a 5-stage butterfly per warp (5,120 mux bits), the indexed shuffle a full crossbar (32,768). The chip datapath floor per op (N5, approx: add 0.06 pJ, mul 0.52, butterfly 0.30, crossbar 1.00, mm8 tile 1.60) against the GPU's measured step costs: + +| Shadow op mix | Chip floor per op (pJ, approx) | k floor after the 2x pipeline and 8x register and wire overhead of latency-shadow s6 (approx) | GPU cost of the same mix on the 5090 (step ratios, measured) | +|---|---|---|---| +| Today's weights (add 32, mul 22, rot 13, shfl 8 of 75) | 0.221 | 0.32 | 1.0x to 1.5x per op | +| Shuffle-heavy (shfl 14, shfla 8, the rest scaled) | 0.315 | 0.46 | the shuffles cost the 5090 1.49x to 1.53x the chain step, so its own energy per op rises about 10 percent (approx) | +| With mm8 at 8 points | about 0.45 | about 0.65 | mm8 costs the 5090 2.43x the step | + +So a shuffle-heavy shadow raises the attacker's claimed floor from about 0.3 to about 0.5 and costs the GPU about 10 percent more energy per shadow op; it does not reach k = 1. What a chip would need to add: the 32-lane crossbar per warp (R1's structure), nothing else new. The structure argument is bounded: a wide-SIMD array with a crossbar per 32 lanes is still a fixed datapath with no scheduler, and that is where the 0.3 came from. + +(iii) One N for every card. Per-card bind points at the 5 percent rule (measured): M5 Max about 130,000 counted ops (interpolated between 102,100 at -1.5 percent and 150,800 at -7.3), RTX 5090 at its 431 W cap about 210,000 (199,600 at -2.7, 330,700 at -34.7), RTX 4070 at its 160 W cap about 250,000 (199,600 at +0.4, 330,700 at -12.3, approx), RX 9070 XT over 331,000 (holds at every rung; budget about 650,000). The consensus N is the minimum: 130,000, set by the Mac. The unmeasured rented cards by ALU budget (approx, cores x clock): 3060 about 270,000, 4060 about 440,000, 3080 about 360,000; their power caps are unmeasured and on NVIDIA the cap binds before the budget, so these are not pass marks. The ladder at every N the lane can compute: + +| N counted ops | 5090 uJ (rate delta) | M5 Max uJ (delta) | 4070 uJ (delta) | f = 1 GDDR7 chip uJ at k = 0.3 / 0.5 / 1 / 1.5 | Edge over the 5090 | Edge over the M5 Max | Edge over the 4070 | Verifier add per warp: M5 Max / box core / box half-core (ms) | +|---|---|---|---|---|---|---|---|---| +| 930 (class v3) | 2.65 | 0.78 | 2.57 | 0.47 / 0.47 / 0.47 / 0.47 | 5.7x | 1.66x | 5.5x | 0 | +| 102,100 (class v4) | 3.27 (-0.2%) | 1.39 (-1.5%) | 3.51 (+0.4%) | 0.80 / 1.02 / 1.58 / 2.14 | 4.1x / 3.2x / 2.1x / 1.5x | 1.74x / 1.36x / 0.88x / 0.65x | 4.4x / 3.4x / 2.2x / 1.6x | 0.18 / 0.39 / 0.67 | +| 130,000 (the one-N candidate) | 3.27 (-0.3%) | 1.43 (-4.8%) | 3.78 (+0.4%) | 0.89 / 1.18 / 1.89 / 2.60 | 3.7x / 2.8x / 1.7x / 1.3x | 1.61x / 1.22x / 0.76x / 0.55x | 4.2x / 3.2x / 2.0x / 1.5x | 0.23 / 0.49 / 0.85 | +| 150,800 | 3.27 (-0.3%) | 1.46 (-7.3%) | 3.98 (+0.4%) | 0.96 / 1.29 / 2.11 / 2.94 | 3.4x / 2.5x / 1.5x / 1.1x | 1.52x / 1.13x / 0.69x / 0.50x | 4.1x / 3.1x / 1.9x / 1.4x | 0.26 / 0.57 / 0.99 | +| 199,600 | 3.35 (-2.7%) | 1.58 (-10.5%) | 4.45 (+0.4%) | 1.12 / 1.56 / 2.65 / 3.74 | 3.0x / 2.1x / 1.3x / 0.9x | 1.40x / 1.01x / 0.59x / 0.42x | 4.0x / 2.9x / 1.7x / 1.2x | 0.35 / 0.76 / 1.31 | +| 330,700 | 4.99 (-34.7%) | 1.87 (-21.0%) | 5.89 (-12.3%) | 1.55 / 2.28 / 4.09 / 5.91 | 3.2x / 2.2x / 1.2x / 0.8x | 1.21x / 0.82x / 0.46x / 0.32x | 3.8x / 2.6x / 1.4x / 1.0x | 0.58 / 1.26 / 2.18 | + +Per-tier watts at N = 130,000 (measured rungs interpolated): the M5 Max 37 W GPU plus DRAM (from 21), the 5090 431 W (its cap, from 350), the 4070 about 118 W (from 79.5), the 9070 XT owed; a 5090 rig pays about 23 percent more electricity for 0.3 percent less rate, an Apple miner 1.8x the GPU watts for 4.8 percent less rate, a pool user nothing, every verifier tier +0.23 to +0.85 ms per warp. The verifier at 130,000 on the half-core proxy is 8.5 ms (8.23 + 0.85 - 0.67), inside the gate with 1.5 ms spare; the gate does not bind N before the Mac does. + +#### 5.3a The reconciled N ladder (this lane's measured cards, lane 7's HBM4 inputs; `--section ladder`) + +Lane 7 (`docs/analysis/horizon/frontier.md` 2.3, `sim/horizon/frontier/frontier_model.py` model 1.4) adds HBM4: JEDEC JESD270-4 doubles channels per stack (16 to 32, cited), so its one-stack ceiling is taken as 2 x 10.7 = 21.4 G reads/s at 1.0 nJ per read (approximate, unsourced), 5 W static, 10 W controller: 167 MH/s at 0.218 uJ bare. The table below carries that chip beside the three of chip-model-v3 5.4, every chip at N = bare + (N - 930) x 11 pJ x k, and every honest card at its measured rung. + +| N counted ops | 5090 uJ, W (rate delta) | M5 Max uJ, W (delta) | 4070 uJ, W (delta) | 9070 XT rate delta (W owed) | 12 GB and 8 GB rented cards | Chip edge over the 5090 per joule at k = 0.5 / 1 / 1.5: GDDR7 | HBM3 one stack | HBM3 eight stacks | HBM4 one stack | Verifier ms per warp: M5 Max core / 2019-class by the 2.5x rule / measured half-core proxy | Card that binds first (5 percent rule) | +|---|---|---|---|---|---|---|---|---|---|---|---| +| 930 (class v3) | 2.65, 350 W (0) | 0.78, 21 W (0) | 2.57, 80 W (0) | 0 | measured at v3 only: 5070 3.27 uJ, 3060 4.36, 4070 untuned 3.65, 4060 Ti 8 GB 3.81 | 5.7x | 8.3x | 10.1x | 12.2x | 2.06 / 5.2 / 7.56 | none | +| 49,700 | 3.21, 425 W (+0.1%) | 1.16, 31 W (-1.2%) | 3.01, 94 W (+0.4%) | +2.1% | not measured at any N | 4.4x / 3.2x / 2.5x | 5.5x / 3.7x / 2.9x | 6.1x / 4.0x / 3.0x | 6.6x / 4.3x / 3.1x | 2.15 / 5.4 / 7.88 | none | +| 102,100 (class v4) | 3.27, 431 W (-0.2%) | 1.39, 37 W (-1.5%) | 3.51, 109 W (+0.4%) | +2.0% | not measured | 3.2x / 2.1x / 1.5x | 3.7x / 2.3x / 1.6x | 4.0x / 2.4x / 1.7x | 4.2x / 2.5x / 1.7x | 2.24 / 5.6 / 8.23 | none (M5 Max -1.5%) | +| 130,000 | 3.27, 431 W (-0.3%) | 1.43, 37 W (-4.8%) | 3.78, 117 W (+0.4%) | +1.7% | not measured | 2.8x / 1.7x / 1.3x | 3.2x / 1.9x / 1.3x | 3.4x / 1.9x / 1.4x | 3.5x / 2.0x / 1.4x | 2.29 / 5.7 / 8.41 | M5 Max at its 5 percent point | +| 150,800 | 3.27, 431 W (-0.3%) | 1.46, 37 W (-7.3%) | 3.98, 124 W (+0.4%) | +1.5% | not measured | 2.5x / 1.5x / 1.1x | 2.9x / 1.7x / 1.2x | 3.0x / 1.7x / 1.2x | 3.1x / 1.8x / 1.2x | 2.32 / 5.8 / 8.55 | M5 Max (-7.3%) | +| 199,600 | 3.35, 431 W (-2.7%) | 1.58, 38 W (-10.5%) | 4.45, 138 W (+0.4%) | +1.0% | not measured | 2.1x / 1.3x / 0.9x | 2.4x / 1.3x / 0.9x | 2.5x / 1.4x / 0.9x | 2.6x / 1.4x / 1.0x | 2.41 / 6.0 / 8.87 | M5 Max (-10%), 5090 (-2.7%) | +| 330,700 | 4.99, 431 W (-34.7%) | 1.87, 40 W (-21.0%) | 5.89, 160 W (-12.3%) | +3.6% | not measured | 2.2x / 1.2x / 0.8x | 2.3x / 1.3x / 0.9x | 2.4x / 1.3x / 0.9x | 2.5x / 1.3x / 0.9x | 2.64 / 6.6 / 9.74 | 5090 (-35%), M5 Max (-21%), 4070 (-12%) | + +Sources per column: 5090 and M5 Max rungs `latency-shadow-2026-10-06.md` s3 and s5; 4070 and 9070 XT rungs `counter-asic-3-status.md` item 8 (the 9070 XT's watts owed: the ADLX sampler parsed 0 samples); the rented cards `prover-tiers-real-cards.md` (class v3 only); chip bare energies chip-model-v3 5.4 and lane 7 model 1.4; the 11 pJ unit latency-shadow s5; the verifier slopes 3.2 us per 1,000 shadow instructions (Mac, measured) and 12.1 us (box half-core, this lane); the 130,000 row interpolated. Every chip cell is approximate. + +Disagreements with lane 7's model 1.4, named: (a) its honest card at N is the linear 326-to-575 W model of chip-model-v3 5.7 (2.95 uJ at N = 100,000, 3.50 at 200,000, 4.22 at 330,000); the measured 5090 under its 431 W cap reads 3.27, 3.35 and 4.99 uJ with -0.2, -2.7 and -34.7 percent of rate (the cap binds from 102,100 ops; `power.min_limit` is 400 W, so no cap below the one measured exists on a 5090). (b) Its shadow core is 150 W fixed at the 5090's 136 MH/s; on a 167 MH/s HBM4 chip that under-counts the core by 1.23x. Energy per hash is N x 11 pJ x k whatever the chip's rate, so HBM4 at N = 100,000 and k = 1 is 1.33 uJ and the edge 2.5x, not 1.11 uJ and 2.65x; at 200,000 1.4x (lane 7: 1.74x); at 330,000 1.3x (1.33x: agrees, because the 5090's own energy jumps to 4.99 at that rung). (c) Its HBM3 and HBM4 ceilings (10.7 and 21.4 G per stack) rest on the 8-activates-per-12-ns rate chip-model-v3 5.3 carried from O'Connor; the JEDEC HBM2 cycle table (ICCAD 2021 Table I) gives 4 per 28 ns per channel (section 5.1 of this file), and HBM3's own tFAW is behind the paywall. If HBM3 and HBM4 keep HBM2's window the one-stack ceilings are 2.3 and 4.6 G, HBM4's bare energy 0.55 uJ and its bare edge 4.9x, not 11x. The GDDR7 column is the one with a measured anchor (the 5090 reaches 82 percent of its ceiling) and is the column to quote in the summary; the HBM columns are the upper bound. + +Verifier headroom for N (lane 7's "10x of headroom"): on the M5 Max core 10 - 2.33 = 7.67 ms buys 2.4 M shadow instructions, N about 4.5 M ops (19x); on the 2.5x rule 4.2 ms buys 525,000 instructions, N about 1.06 M (10x, lane 7's figure); on the measured half-core proxy 1.77 ms buys 146,000 instructions, N about 370,000 (3.7x). The 10x holds on the rule and not on the pessimistic measured bracket; O-1.14 decides which. Either way the cards bind first: M5 Max 130,000, 5090 at 431 W 210,000, 4070 at 160 W about 250,000, 9070 XT over 331,000. An unconditional doubling of N per era (lane 7's candidate) would take the Apple tier out at the first step (200,000: -10.5 percent) and the 5090 and 4070 at the second (400,000: compute-bound at their caps), which is why the proposal below steps N by signal, not by schedule alone. + +The verdict on v5: the shadow lever is close to spent on the owned cards. Going from 100,000 to 130,000 buys 2.1x to 1.7x against the 5090 at k = 1 and costs the Mac its whole 5 percent allowance; a shuffle-heavy mix buys the k floor 0.3 to 0.5. Together they define one candidate, `v5 = mx8 + sh256x35 with the shuffle-heavy weight table`, worth measuring but not worth a cut on its own: the chip question is k, and no shadow design moves k past about 0.5 against a fixed-datapath array. + +What measurement decides it (not run tonight; the shuffle-heavy weight table does not exist as a knob, and the Mac's miner state was not checked, so the plan stands in for the run): (1) add a shadow weight table to `ShadowClass` (`generator.rs`, 2 hours), draw the block from it, emit it in the three dialects as today; (2) export `mx8+sh256x35` at today's weights and at the shuffle-heavy table for seed igneum-genesis; (3) Mac: `with-lock.sh measure packbench --pack --batches 60 --batch-log2 24 --group 256` with the IOReport sampler, 2 packs plus the control, about 6 minutes, the miner paused first (`curl -s http://127.0.0.1:60030/.../api/state` from the app's `app.url`, then pause through the app, never from a script); (4) the same ladder as PC jobs on the 5090, 4070 and 9070 XT through the existing `tools/ca3-shadow` playbooks with the card off through the runner's `--cards-off`; (5) `igneum-pow bench` on the Mac core and the box proxy. Pass lines: every owned card within 5 percent of its class v4 rate; bit-exact fingerprints on Metal, CUDA and AMD OpenCL; verifier under 10 ms on the half-core proxy; the 5090's marginal pJ per op on the shuffle-heavy mix read on the three rungs under its cap. + +### 5.4 Task 4: the era draw's randomness + +How it picks. Era n's seed E_n is the 1-hour class-group VDF of `Hash(chain_id || n || blue block hashes of the day before C_era(n))`, where C_era(n) is the highest certified checkpoint at least 7,200 DAA s before the era (spec 04 s4.4). One SplitMix64 stream from E_n draws, in order: the ten op weights perturbed by -2..+2 points each, the output fold rotations, an unused draw for `epoch_len` (set by signal), then under class v3 a second stream draws the load width (pinned at 4 bytes: the draw is consumed), the stride multiplier M (odd) and rotation R, and the four interleave bit positions (spec 01 s1.13.1, `era-layout.md` 1.1). Not drawn: the load count (16), the mixer round count (8) and multiplier (8), the cache and dataset sizes, the item construction. + +What an attacker can bias, priced. Two routes. (a) Forge the certified checkpoint: needs 2/3 of the 30-day blue-block weight, which is 20 days of 100 percent of the network's hash (the headline). Rented at the measured USD 0.0117 per MH/s-hour: + +| Network hash | 20 days of 100 percent, rented | What it buys in the draw | +|---|---|---| +| 1 GH/s | USD 5,616 | one era's (weights +-2, fold, M, R, pos): a per-card hash-rate spread of 0.8 to 3.2 percent (six eras measured, bench-log "Counter ASIC 2.0, the numbers"), 0 chip effect | +| 10 GH/s | USD 56,160 | the same | +| 100 GH/s | USD 561,600 | the same; the rental market could not supply 20 pods of any card at 19:00Z on 6 October (bench-log), so a TH/s is not rentable at all | +| 1 TH/s | USD 5.6M (not supplied) | the same | + +(b) Re-roll without weight: the miner of the last blue block before C_era(n)'s cut withholds or publishes to change the input set; this costs one block's reward and needs the 3,600-s VDF evaluated inside the 2-s publish window, a 1,800x faster evaluator (spec 04 s4.6: a 300x evaluator beats the epoch's 600 s, not the era's 3,600 s). Even free, one re-roll is one more sample of the same space. So the draw is unbiasable at any price that matters, and that is the honest answer to "what can be biased": nothing worth having. + +Weak corners. The op-weight perturbation can move the multiply share (mul, mad, mulhi: 22 of 75) to 16 or 28 of 75; at the N5 datapath floor that is 0.158 to 0.232 pJ per shadow op (0.195 at the base), about +-20 percent of the shadow's datapath energy, and the GPU's energy moves the same way (its IMAD is the chain's own op). The stride and interleave cost a chip two integer operations per load and an address-line permute, nothing per joule. The fold rotations are a wire mux. The measured six-era spread (1.3 percent on the 5090, 3.2 on the 9070 XT, 0.8 on the M5 Max) is the whole of what the draw moves. There is no corner that makes a chip easier, because no drawn parameter touches the memory bound, the item derivation or N. + +Predictability against the 32-month lead time. Everything a chip needs is public at genesis: the eleven live families, the reserve order R0 to R8 and its era schedule, the mixer shape and x8, the dataset and cache schedule, the class v4 shadow's size and weights. The draw hides (M, R, pos, weights +-2, fold rotations) until 2 hours before each era, and none of those needs silicon: an address decoder that permutes lines, a programmable rotator, an immediate table. So a chip taped out in month 0 against this spec runs every era for the chain's life, and the era draw buys nothing against it. What the draw does buy: the fork-fatigue lesson of the history (no human release, no vote), and a per-program hard-datapath FPGA cannot amortise a bitstream across eras (layer 9 handles the within-era case). Said plainly for the public text: the era draw and the reserve are automatic schedule changes against fixed datapaths and governance, not unpredictability against a chip. What would be unpredictable and costly to a chip is not available in a genesis-fixed rule set: a per-era draw among K reviewed item constructions (K mixers or K derive forms) is still K public blocks a chip carries; a per-era draw of the load count or the dependent-read depth changes the memory bound per era and fails the 5 percent rule on the honest cards (read-width: a per-program width mix spread 5.5 to 22.3 percent). What costs a chip is N (its k), the memory system (f = 1 is the ceiling and is a commodity controller), and the honest card's own watts (the M5 Max at 0.78 uJ is inside 2x of the GDDR7 chip with no shadow at all). + +### 5.5 Task 5: the 2019-class verifier gate + +Measured tonight (section 3.3): on igneum-build-1 one EPYC 9454P core boosted to 3.8 GHz (not a low clock: the governor's cap is 2.75 GHz but the core read 3,800 MHz under load, and `cpupower` needs root) with server DDR5 behind it reads 1.9x to 2.2x the quiet M5 Max core across five classes, and 2.0x on the cache fill. The half-core proxy (both SMT siblings busy on the same class) reads 3.4x to 3.7x the Mac. A 2019 laptop core (Skylake-class at 3.5 to 4.5 GHz with DDR4 at about 80 ns) sits between these brackets on the arithmetic (lower IPC than Zen 4, lower DRAM latency than the server), so the 2.5x rule is about right and the two proxies bracket it. Against the gate: + +| Class | One box core, cold run | Half-core | Verdict at 10 ms | Headroom left for shadow on the half-core (ms) | +|---|---|---|---|---| +| class v3 (mx8) | 4.67 | 7.56 | pass | 2.4 | +| class v4 (mx8+sh256x27) | 5.06 | 8.23 | pass | 1.8 (about 150,000 more shadow instructions at 12.1 us per 1,000) | +| dr368 | 5.32 | 8.16 | pass | 1.8 | +| dr736 | 10.51 | 15.49 | FAIL on both proxies | none | + +So dr736 is out as a genesis-live or near-term reserve length on measured evidence, not on the 2.5x rule; dr368 is in. The owed O-1.14 measurement on a real 2019 laptop (the US laptop's Windows `igneum-pow` build, main's decision 7) still closes the question; the box proxy is the stand-in until it lands, and the half-core row should be the standing pessimistic rule in place of "2.5x" (it is a measurement; 2.5x is a ratio from memory). + +How to measure it tomorrow: `tools/cross-remote.sh` from `igneum-pow/` builds the Windows exe on the box (1 min 44 s measured for the node; the pow crate is one crate, under a minute), the relay carries it to the US laptop when it appears, `igneum-pow bench --seed igneum-genesis --day 2026-10-03 --class --warps 50` for the five classes, ms per warp into `docs/bench-log.md` under O-1.14; 1 hour of agent work. A rented old CPU on Vast is the fallback (Vast lists CPU-only offers by core generation; a 2019 Xeon or i7 host at under USD 0.10 an hour, approx), same binary, same command. + +What the gate protects, and what loosening it costs: + +| | At 10 ms per warp | At 20 ms (loosened) | At 5 ms (tightened) | +|---|---|---|---| +| A node on a 2019 laptop at 1 bps | 1 percent of one core per block | 2 percent | 0.5 percent | +| At 10 bps (the Devnet 2 experiment) | 10 percent of one core | 20 percent | 5 percent | +| IBD over the 108,000-header pruning window, one core | 18 min | 36 min | 9 min | +| Header flood (M15 class): invalid headers per second that saturate one core | 100 | 50 | 200 | +| A pool core verifying shares | 100 per second | 50 | 200 | +| What the lever buys the hash | the x8 mixer, dr368, the v4 shadow all fit with 1.8 ms spare on the half-core | dr736 fits (15.5 on the half-core: no, still out), x16 mixer fits | nothing of class v4 fits on the half-core | + +Loosening to 20 ms would admit the x16 mixer (about 7 ms on the Mac, 15 on the half-core: still out) and not dr736 on the half-core, so it buys little against a chip (the f = 1 chip derives no item) and doubles the header-flood and IBD costs on the weakest node. Keep 10 ms; measure the laptop; use the half-core row until then. + +### 5.6 Task 6: the dataset schedule to 2030 + +The schedule (spec 1.13.3 option (b), decided for the cache on 5 October, recommended for the dataset): 2 GiB at genesis, 4 GiB at year 4 (day 1,460), 8 GiB at year 12, 16 GiB at year 28; the cache 256 MiB, 512 MiB, 1 GiB, 2 GiB on the same days (`memhard.rs` `growth_doublings`). The devnet packs run 1 GiB today. + +The installed base against it (Steam September 2026, cited; the trend is approximate): + +| Year (approx calendar) | 8 GB share | 12 GB share | Dataset | Who falls out of mine-only | Who falls out of mine-and-prove (the prover's measured peaks, `prover-tiers-real-cards.md`) | +|---|---|---|---|---|---| +| 2026 (devnet) | 27% | 13% | 1 GiB | nobody with 4 GB or more | 8 GB: compressed does not fit beside the miner (measured); core-only 2^25 fits with 1 GB spare | +| 2027 (genesis, year 0) | about 20% | about 10% | 2 GiB | 4 GB cards hold with 0.5 to 0.8 GB spare (card-lifetime) | 8 GB loses core-only beside the miner (the miner's resident set grows 1 GiB: 7.35 + 1.0 GB over 8.19) and becomes prove-alone; 12 GB holds compressed on headless Linux (10.2 + 1.0 of 12.3) | +| 2031 (year 4) | about 0% | about 0% | 4 GiB | 4 GB cards (5 percent of Steam today, about 0 by then) | 12 GB loses compressed (10.2 + 3.0 GB over 12.3), keeps core-only (7.2 + 3.0 of 12.3); 16 GB keeps compressed (9.2 + 3.0 of 16.4) | +| 2039 (year 12) | 0 | 0 | 8 GiB | 8 GB cards (26.7 percent of Steam today; the trend says under 1 percent by 2030) | 12 GB loses core-only; 16 GB loses compressed, keeps core-only (7.4 + 7.0 of 16.4); 24 GB keeps compressed (11.0 + 7.0 of 24.6) | +| 2055 (year 28) | 0 | 0 | 16 GiB | 12 and 16 GB | 24 GB loses compressed; 32 GB keeps everything | + +Reading per tier: the 8 GB tier, a quarter of Steam today, is never a mine-and-prove card on the measured prover footprint whatever the dataset does, and it mines until year 12, by which time its share on the trend is nil; the 12 GB tier (13 percent, falling 6 points a year) mines to year 28 and loses mine-and-prove compressed at year 4 because the prover peaks at 10.2 GB beside a 1.4 GB miner; the 16 GB tier (27 percent and rising) mines and proves compressed to year 4 and core-only to year 12; 24 and 32 GB are unconstrained to year 28. The dataset is never the binding constraint on any tier before year 12; the prover's 5.6 to 10.7 GB footprint is. On the chip side the schedule changes nothing: one HBM3 stack holds 24 GB and the 5090's own board 32 GB (chip-model-v3 5.7), so f = 1 reads every step of the schedule to year 28 without a second stack. + +What growth is for, then. Two things, both real and neither a chip: (1) the cache above every GPU's on-die cache (96 MB on the 5090, 128 MB on GB202; the spec's own rule), so the honest hash stays DRAM-latency-bound and no consumer GPU gains an L2 shortcut; (2) the dataset above one reticle of SRAM at the node of the day (1.6 GiB per reticle at N5 headline density, 1.9 at N2, sram-mirror.md s4), so an "f = 1 in SRAM" chip, which would read at SRAM latency and beat the DRAM activate ceiling by 10x, stays a multi-reticle part: at 2 GiB that is 2 dies at N2, at 4 GiB 3 dies, at 8 GiB 5 dies (approx, headline density; the lower-bound density halves these). Wafer-scale parts already hold more (a Cerebras WSE-3 carries 44 GB of on-wafer SRAM, approximate, from memory, unpriced here): the schedule does not price that device out and nothing in the hash can, but at the dependent-read pattern a wafer's cross-die hops cost latency that no one has measured for this hash (open, section 7). + +Recommendation with numbers: hold the schedule as decided (2 GiB genesis, doublings at years 4, 12, 28). Do not slow it: slowing buys the 8 GB tier nothing (it mines to year 12 either way) and loses the SRAM-reticle margin (at a flat 2 GiB one N2 reticle holds 1.9 GiB today and about 3.4 GiB by 2036 on the 6 percent a year density trend, sram-mirror s6, so a flat dataset fits one reticle within a decade). Do not grow faster: the only tier a faster schedule costs is the 8 GB tier (year 12 to year 4) and the Apple 8 GB laptop, and it buys nothing against the HBM chip. One change: write the prover footprint, not the dataset, into the public card-lifetime sentence (litepaper line 560: "12 GB or more proves full shards" becomes "12 GB mines and proves on headless Linux until the year-4 dataset step, 16 GB until year 12, 24 GB beyond; 8 GB proves alone"), since that is the number that moves users. + +## 6. Ranked proposals + +| Rank | Proposal | Evidence | Model | Hours | Consequence per tier | Gate | +|---|---|---|---|---|---|---| +| 1 | Close O-1.14 with a real 2019 laptop run and adopt the half-core proxy as the standing stand-in; dr736 out, dr368 in as R0's length | box proxy: dr736 10.5 ms cold, 15.5 half-core; v4 5.06 / 8.23 | section 5.5 | 2 (Windows cross build on the box, relay to the laptop, bench, log) | miners 0; pool verifier cores x1.3 at dr368 instead of x2.4; a 2019 node keeps 1.8 ms of headroom under v4 | ms per warp under 10 cold on the laptop for v3, v4, dr368; dr736 recorded as the figure that fails | +| 2 | Measure the FPGA lane on AWS F2 (one VU47P, HBM2, USD 1.98 an hour) and replace the 12.2 ceiling row | the measured 2.4 G/s equals the JEDEC tFAW ceiling; the 1.9x row rests on a 12 ns tFAW the JEDEC cycles do not support | section 5.1 | 8 to 10 agent hours plus USD 2 to 8 of F2 time | none today; the public FPGA claim becomes a measured 0.3x to 0.5x per watt | reads per second per watt at 1 GiB; alarm at 27 M/s/W, Counter ASIC 4.0 at 54 | +| 3 | Public-text correction: the era draw and the reserve are automatic schedule changes against fixed datapaths and against forks, not unpredictability against a chip; publish the chip's USD per MH/s-hour beside the honest cards' | section 5.4: every drawn parameter needs no silicon; the reserve is about USD 4 of N5 silicon on a chip | sections 5.1, 5.2, 5.4 | 1 | holders and miners read a claim that survives review; nothing on the devnet changes | `docs/evidence.md` row with the two numbers (USD 0.00021 chip, 0.00113 owned 5090, 0.0117 rented) and the draw sentence | +| 4 | Reserve order: R1 shfla, R2 perm, R3 popc and clz, R4 to R7 unchanged, R8 mm8 at era 8 by the rule; R0 at dr368 | AMD step cost of shfla measured 0.75 to 0.84 (the one number the reserve document said could move R3); dr736 fails the proxy | section 5.2 | 1 (spec text in `counter-asic-3-reserve.md` s5 and s6) | Apple pays shfla's 1.91x per op first, under 1 percent of ALU time at 4 points (argued, measured at the unlock rehearsal); NVIDIA and AMD 0 | the family-live 5 percent run per vendor at each unlock rehearsal | +| 5 | **N grows by the era draw at genesis, inside a verifier-bounded ladder, each step taken by 90 percent miner signal.** The shadow size N becomes a genesis ladder indexed per era, {100,000, 130,000, 200,000, 330,000, 650,000, 1,000,000} counted ops (the measured rungs, then doublings), floor 100,000 and ceiling 1,000,000 fixed at genesis (the ceiling is the 10x verifier headroom on the 2.5x rule; 370,000 on the half-core proxy until O-1.14 lands, which then sets it), the era stream consuming one draw for it as it does for `epoch_len`, and the step up or down set by 90 percent of blue blocks over 7 days at a day boundary (spec 5.7's mechanism, P2's signalling code), never unconditionally | lane 7: HBM4 doubles the f = 1 chip's rate per stack, so the bare edge rises 5.7x to 12x (upper bound) and only N answers it; this lane: the chip's edge over the 5090 at k = 1 falls 2.1x (100,000) to 1.7x (130,000) to 1.3x (200,000 and 330,000); an unconditional doubling takes the M5 Max out at the first step | section 5.3a; `--section ladder` | 6 to 8 (the ladder field in `ShadowClass` and the era stream, the signal rule shared with `epoch_len`, a fast-time run across one step, packs and vectors per rung) | At each step, measured: 100,000 to 130,000 costs the M5 Max 3.3 points of rate and 0 W more, the 5090 and 4070 nothing, the 9070 XT nothing, every verifier +0.05 ms; 130,000 to 200,000 costs the M5 Max 6 more points and the 5090 2.7 at its cap, the 4070 +21 W, every verifier +0.12 ms (Mac) to +0.5 (half-core); 200,000 to 330,000 is compute-bound on every NVIDIA card at its cap (5090 -35 percent) and is a step the signal would refuse until cards change; a pool user nothing at any step; a chip's shadow core grows with N at k x 11 pJ per op | ONE gate per step, published before the project recommends the signal: at the step's N, every card of the public benchmark set (the four owned plus the eleven rented models) within 5 percent of its rate at the previous step, bit-exact fingerprints on Metal, CUDA and AMD OpenCL, and the verifier under 10 ms per warp cold on the O-1.14 core (the half-core proxy until then) | +| 5a | A class v5 candidate `mx8 + sh256x35` with a shuffle-heavy shadow weight table (shfl 14, shfla 8 of 75), measured on the four owned cards before any cut: the first rung of proposal 5's ladder, plus the k-floor lever | the Mac's 5 percent point is 130,000; the shuffle mix raises the k floor 0.32 to 0.46 (approx) | section 5.3 | 4 to build the weight-table knob and packs, 1 Mac measure session (about 6 min under the lock, miner paused), 3 PC jobs | M5 Max -4.8 percent of rate at 37 W; 5090 -0.3 percent at its 431 W cap (a rig +23 percent electricity); 4070 0 at about 118 W; 9070 XT 0; verifier +0.23 ms Mac, +0.85 half-core | every owned card within 5 percent; bit-exact on three vendors; half-core verifier under 10 ms; the 5090's marginal pJ on the new mix read on three rungs | +| 6 | Hold the dataset schedule (2 GiB, years 4, 12, 28); write the prover footprint into the card-lifetime sentence | Steam shares and the measured prover peaks; one HBM3 stack holds every step | section 5.6 | 1 | 8 GB: mines to year 12, proves alone; 12 GB: mine-and-prove compressed to year 4, core-only to year 12, mines to year 28; 16 GB: compressed to year 4, core-only to year 12; 24 and 32 GB unconstrained to year 28 | the litepaper sentence matches the table; `docs/evidence.md` row "card lifetime" labelled designed | +| 7 | Make the Ember tune the shipped default per card model (the honest card's watts are the lever that moves every chip row) | the 4070 at 3.65 uJ untuned and 2.57 tuned (-30 percent); the 5090 2.65 bench against 2.34 app | section 5.1 | 2 (defaults table in the app from the fleet priors; already measured) | every NVIDIA tier gains 10 to 30 percent per joule; the chip's edge over the mid-tier falls from 8x to 13x toward 5x to 9x at v3 | MH per W per card model on the fleet night against the untuned baseline | +| 8 | Fund the k question: the item 3 cryptanalysis brief gains a chip-design line (a 14,000-lane SIMD array's energy per op on a random 32-lane program with shuffles, at N5 and at 28 nm) | every chip row at class v4 turns on k; nothing in the project measures it | section 5.3 | 0 agent hours; the project lead's money (part of the USD 80,000 to 160,000 brief) | none until the number lands; it decides whether 2x is reachable | a reviewed estimate of k with its range | + +Paragraphs. + +1. The verifier gate is the one place tonight produced a measurement instead of a rule. The box proxy brackets a 2019 laptop from both sides (a 2022 server core at full boost; the same core with its sibling busy), and dr736 fails both brackets while class v4 passes both with 1.8 ms to spare. The measurement is one Windows build and one bench on the laptop the project lead already owns; until it lands, the half-core row replaces the "2.5x" from memory in every status file. + +2. The FPGA lane's upper row was built on an activate rate (8 per 12 ns per channel) that the JEDEC HBM2 cycle table does not support (4 per 28 ns); the measured Shuhai rate sits exactly on the JEDEC ceiling. That reading can be wrong (the ICCAD table's clock interpretation, the half-bank count, the board watts are all approximate), which is why the F2 hour is the proposal and not the conclusion. It is cheap and it turns a public ceiling claim into a measured one. + +3. The honest statement about the draw and the reserve is owed before the public testnet. The project has said the era draw and the family reserve are "automatic anti-ASIC escalators"; against the chip that the model says anyone would build they escalate nothing, because every parameter they move is firmware or a USD 4 block. They are good design against forks and against a hard-datapath FPGA, and that is what the text should say. The chip's USD per MH/s-hour (56x under rental, 5.4x under an owned 5090) belongs beside it, because it is the number a miner will compute on the day a chip appears. + +4. The reserve order changes only where the measurements moved: shfla's AMD cost came in cheap, so the largest structure goes first; dr736 failed the proxy, so R0 is dr368. mm8 keeps no exception because `epoch-length.md` 12.4 showed it removes no adversary class. + +5. N as a genesis ladder is the one structural change this lane proposes, and it is lane 7's idea with the cards' measured bind points written into it. The memory generation it answers (HBM4, 2028) arrives on a two-to-three-year cadence; the chain must answer without a release, which the era stream and the `epoch_len` signal rule already provide the shape for. What the measured rungs add: the ladder's steps are the cards' own bind points, the step is taken by the miners who pay for it, and the ceiling is the verifier's measured core, not a 10x from a ratio. An unconditional doubling per era would retire the Apple tier at era 1 and every capped NVIDIA card at era 2, so the schedule alone is not the proposal; the schedule plus the signal is. + +5a. v5 as a class (`mx8 + sh256x35` with a shuffle-heavy mix) is measurable in an evening and is not a cut. Its honest ceiling is the Mac's 5 percent and a k floor of about 0.5; it buys 2.1x to 1.7x against the 5090 at k = 1. The design item that decides more than v5 is k itself (proposal 8). + +6. The dataset schedule is right as decided and the public sentence about cards is wrong in kind: it talks about the dataset when the prover is what ends a tier's mine-and-prove life. + +7. The one lever that moves every chip row and costs no consensus change is the honest card's watts. The fleet showed the untuned mid-tier at 1.5 to 2.3x the 5090's energy per hash; Ember's measured tune on the 4070 took 30 percent off. Shipping it as the default is a miner-app change with a measured gate. + +8. k is the whole chip question at class v4 and nobody in the project can measure it; the external brief can estimate it. + +## 7. Open questions and what could not be run + +| Item | Why not | What would close it | +|---|---|---| +| The v5 Mac packbench ladder | the shuffle-heavy shadow weight table does not exist as a knob (the block uses the program's weights), and the Mac's miner state was not checked; a run without the knob would have measured v4 again | proposal 5, 4 hours of code then the 6-minute measure session | +| A fixed low clock on the box | `cpupower` needs root; the core boosted to 3.8 GHz under schedutil | the laptop measurement (proposal 1); the half-core row is the pessimistic stand-in | +| The 9070 XT watts at class v4 and its per-joule row | the AMD watts job failed on 6 October and the re-run waits on the runner's `--cards-off` (status 6a) | the next cut's PC 1 job | +| The RTX 4060's watts (logged 0.0 W on the rented box) | the sampler read nothing on that host | one re-rent | +| HBM2 tFAW and half-bank count on the U55C and F2 parts | behind the JEDEC paywall; the ICCAD table is a simulator's configuration (DRAMSim3), not a datasheet, and its clock interpretation (1,066 MHz) is mine | the F2 hour (proposal 2) | +| A wafer-scale SRAM dataset holder (Cerebras-class, 44 GB on-wafer, approximate) | not priced anywhere in the project; its cross-die hop latency on a dependent-read chain is unmeasured | a Counter ASIC 4.0 analysis item, not a lane 2 item | +| The Steam trend to 2030 | linear extrapolation of two points per tier | the survey itself, yearly | +| The era draw's cryptanalysis (the stride bijection, the ROT weak-key draw) | out of scope here and still open in spec 1.8.4 and era-layout s8 | the item 3 brief | +| `block-rate-devnet2.md` RUN_A and RUN_B | placeholders at 21:30 UK | nothing in this lane depends on them | + +## 8. Summary for the coordinator + +Lane 2 refined the shipped hash and its classes on the 6 October numbers and one new measurement. The chip model's answer does not change in kind: the stored-dataset chip is the chip, it reads 5.7x per joule against the 5090 bench row and 1.7x against the M5 Max at class v3, 2.1x and 0.9x at class v4 and k = 1, and it undercuts rented hash 56x and an owned 5090 5.4x per MH/s-hour; the FPGA lane tightens to 0.30x to 0.47x per watt because the measured random-read rate of an HBM2 FPGA is the JEDEC activate ceiling and not a mapping artefact, and AWS F2 can measure it for USD 2 an hour. The reserve and the era draw buy nothing against a chip (every drawn parameter is firmware; every reserve block is about USD 4 of silicon) and the public text should say what they do buy. The verifier gate got its first measured proxies: class v4 passes a 2022 server core (5.06 ms cold) and the same core with its SMT sibling busy (8.23 ms); dr736 fails both (10.5 and 15.5 ms), so R0 is dr368. The dataset schedule holds; the tier constraint to 2030 is the prover's footprint, not the dataset. + +1. Class v4 verifier on the box proxy 4.90 ms steady, 5.06 cold, 8.23 on the half-core; dr736 9.76 / 10.51 / 15.49: dr736 is out on measurement, class v4 keeps 1.8 ms under the gate on the pessimistic bracket (section 5.5; `sim/horizon/algorithm/model.py --section verifier`). +2. The f = 1 GDDR7 chip's edge per joule: 5.7x (5090 bench), 1.7x (M5 Max) at v3; 2.1x and 0.9x at v4 with k = 1; 4.1x and 1.7x at k = 0.3; against the untuned rented mid-tier 8x to 13x at v3; USD 0.00021 per MH/s-hour against 0.0117 rented (section 5.1; `--section chip`). +3. The HBM2 FPGA soft overlay: 2.3 to 2.9 G reads/s per 2-stack card by tFAW and tRRD (measured 2.4), 0.30x to 0.47x of the 5090 per watt; the 1.9x ceiling needs a tFAW of 12 ns that the JEDEC HBM2 table (28 ns) does not give (section 5.1; `--section fpga`). diff --git a/docs/analysis/horizon/consensus-security.md b/docs/analysis/horizon/consensus-security.md new file mode 100644 index 000000000..d6be2eb1c --- /dev/null +++ b/docs/analysis/horizon/consensus-security.md @@ -0,0 +1,328 @@ +# Horizon lane 1: consensus security. What a hash majority buys on Igneum, attack by attack, with the bound and the price + +Date: 6 October 2026, evening UK (written 19:40 to 21:30 UTC). Lane: consensus-security. Worktree: `/Users/joshm/Projects/igneum-wt-horizon` (branch `horizon` at `3f4f719`). Companion paper: `docs/analysis/51-percent.md`. Models and runs: `sim/horizon/consensus-security/` (README at the end of this file, section 9). + +What was read before modelling: `docs/spec/02-consensus.md`, `03-finality.md`, `04-seeds-and-vdf.md`, `06-open-items.md`, `07-execution.md`, `08-client-security.md`; `docs/fud-ledger.md` F1 to F25, M14, M15, M23, M24, P7, P9, P11, P12, X18 to X20, G8, G12, G13, C4, D6, E16; `docs/analysis/difficulty-2026-10-03.md` (section 11), `difficulty-2026-10-04-oscillation.md`, `sim/difficulty/attacks/README.md` (the seven attacked ways); `sim/results_v2.md` A to M; `docs/benchmarks/finality-v3-2026-10-04/*.md`, `docs/benchmarks/round4-consensus-2026-10-04/results-final2.md`; `tools/finality-attacks/README.md` and `lib/net.mjs`, `tools/harness/README.md` and scenarios, `tools/exec-attacks/README.md`; `docs/review/redteam-2026-10-04.md`, `docs/review/round-4-reddit-2026-10-06.md`; `docs/plans/counter-asic-3-node.md` section 6 (P2); `docs/analysis/security-budget.md`; `docs/bench-log.md` "Rental cost of hash, 6 October 2026"; `vendor/igneum-node/consensus/src/processes/ghostdag/protocol.rs` (main checkout); `infra/fast-time/README.md` and `override-60x.json`; CLAUDE.md's 6 October rules. Two facts from main during the lane (19:4xZ, the first later corrected): the live devnet's finality has been paused since 18:39:40Z (lane 3 confirmed the cause at c3aa502: a 42.7 percent departure held by the frozen table, not the hub outage); and run A on igneum-devnet-2 at 10 blocks/s in a star of 41 miners through one seed gave 12.4 blocks/s, 77 percent red blocks, 321 tips, max reorg 55, with the controller lowering difficulty on the low blue rate (cite as "main, 6 Oct 2026 19:4xZ, block-rate-devnet2.md run A" until the file carries the rows). + +Price basis for every cost: USD 11.7 per GH/s-hour, measured on RunPod community pods on 6 October 2026 (`docs/bench-log.md`, "Rental cost of hash": 1,748 MH/s for USD 20.44 an hour; approximate above 2 GH/s because the market supplied no more; the live devnet was 1.16 GH/s). Costs are given per network size at 1, 10, 100 GH/s and 1 TH/s. Writing rules: no em dashes, numbers in tables, every figure labelled measured, simulated, cited or approximate. + +## 1. Summary for the coordinator + +A hash majority on Igneum buys the ordering race inside the lock latency and nothing a certificate covers, and that is measured here, not asserted. Three findings lead. + +1. **The lock does the work the k-cluster cannot.** The DAG simulator (`ghostdag_sim.py`, GHOSTDAG as `protocol.rs` runs it) shows a 45 to 51 percent withholder wins the selected-chain race over a 90-second hold 70 to 85 percent of the time, reorganising 32 to 46 chain blocks at 1 block/s; a 34 percent withholder wins only inside 30 to 60 s (40 percent of attempts) and never at 90 s; a 20 percent one only the last k = 18 blocks (5 to 15 percent of attempts). Finality's lock lands about 63 to 93 s after a checkpoint block (spec 03 C1, 3.11.3), so the window a majority can reorder is the lock latency, measured at 90 to 120 s, not a block count. Below two thirds of weight, no hash share reaches past a certificate (spec 03 3.11.2, `sim/results_v2.md` H, I, L3, M5: 0 conflicts under 1/3 in every seed). +2. **The pause is the residual, and it is cheap to buy and free to hold.** Reaching the veto (1/3 of 30-day weight) at 51 percent of blocks takes 20 days and costs USD 6k at 1 GH/s, USD 5.8M at 1 TH/s in rent (`cost_model.py`), of which the attacker earns 51 percent back as subsidy; once held, silence costs nothing (the silent key keeps mining and earning) and pauses finality for as long as it likes (`finality_horizon.py` S: at 34 to 90 percent silent, 0 locks for the whole silence, 0 conflicts). During a pause the chain is proof of work with a 12-hour depth, and a 12-hour 51 percent double spend costs USD 146 at 1 GH/s and USD 146k at 1 TH/s. Tonight's pause is the departure case, confirmed by lane 3 (`docs/analysis/horizon/finality-and-weight.md` 3.1): 20 keys holding 42.7 percent of the frozen table stopped mining in three minutes, the signing weight fell to 53.1 percent at checkpoint 6843, the frozen table (Q5) holds the pause for a window (2 h on the devnet, 30 days on mainnet) where rule v2 would have locked after 35 minutes; certificates formed while the hub was down, so the topology hypothesis is refuted. The signed departure (LEAVE, lane 3's rank 1) is the fix. +3. **The proving pool is capturable by any block producer today, in proportion to its hash and up to most of it.** Consensus checks a proof record's statement against native execution and its signature, and NOT the proof (spec 07 7.7 item 4, 7.8 item 8); the first valid record carried pays. A producer that writes a correct statement with random proof bytes into its own block is paid the shard; at 51 percent of blocks it takes at least 51 percent of the 20 percent pool (11,636 IGN an hour at full subsidy) and, because its fake lands in its next block while honest records need 9 to 11 s of proving, most of the shards outside the 10-s exclusive window. This is ledger P21 priced: the only line in the table where a hash majority earns more than it spends. The fix is proof verification in consensus (section 6, rank 1). + +The ranked proposals are in section 6. Two cost nothing in liveness and close whole classes: proof verification in consensus (rank 1) and weight-gated deep fork choice (rank 2: a chain forked deeper than D seconds is a candidate only if the keys that built it hold a third of the weight table at the fork, so rented hash cannot reorg past D even during a pause). Two cost liveness and are not recommended as asked: prover attestations as a second finality leg, and any rule that re-enables locks under the frozen table after an abrupt departure, because a view cannot tell a departure from a partition. + +## 2. Method + +| Model | File | What it does | Machine, lock, seeds | +|---|---|---|---| +| GHOSTDAG withholding | `sim/horizon/consensus-security/ghostdag_sim.py` | Abstract DAG: Poisson arrivals at 1 and 10 blocks/s, 8 equal honest miners publishing at once, one uniform one-way delay d, one attacker at share H withholding (hold T then release; or selfish: release when about to lose or at lead 6), GHOSTDAG coloring and selected parent exactly as `protocol.rs` (k-cluster with `blues_anticone_sizes`, topological mergeset, blue work), 10 parents. Reports, from honest miner 0: reorg depth in chain blocks against the chain it held at release, fork age, whether the private tip became the chain, attacker blue share, honest blocks turned red | Mac, `with-lock.sh run nice -n 19`, 20 seeds per cell; 1 bps k 18 (`ghostdag_results_1bps.md`, 11 s), 10 bps k 124 (`ghostdag_results_10bps.md`, 223 s); the star check inline (section 4.3) | +| Finality sweep | `sim/horizon/consensus-security/finality_horizon.py` | Imports `sim/finality_v2.py` unchanged (1,000 Pareto keys, 3 regions, 2-s delay, 2.2 percent outage, no DAG, perfect retarget, keys free); adds six sweeps over the adversary's share 20, 34, 51, 67, 90 percent: renter, silent set, bought keys, poisoned eclipse, partition with an equivocator under v2 and v3, abrupt departure under v2 and v3 | Mac, run lock, seeds 7 and 11; `finality_horizon_results.md` | +| Signalling game | `sim/horizon/consensus-security/signalling.py` | Arithmetic on P2 (95 percent of a one-day blue-block window, floor height): binomial noise, holdout cost, forced-flip cost, signal-then-defect | Mac, instant; `signalling_results.md` | +| Cost table | `sim/horizon/consensus-security/cost_model.py` | Every attack's rented hash A/(1 - A) x N, its duration from the spec's arithmetic, its cost at 1 to 1,000 GH/s, what it earns at the three IGN price inputs of `security-budget.md`, and the equilibrium network where rent equals subsidy | Mac, instant; `cost_results.md` | +| Node harness | `tools/finality-attacks/run.mjs s6 --fast-time` against the 0.3.14 Mac binary (`vendor/igneum-node/target-0314/release`, built 6 Oct 17:56), rule v3 forced on, SCALE 0.4, ports 29800+, suffix 980, `/tmp/igneum-horizon-fin` | The 3/3 and 4/2 partitions on a real DAG | Mac, run lock; result in section 4.5 (or the recorded runs if the node refused the file) | + +Where a number is from a recorded run and not re-run tonight it is cited by file. Nothing live was touched; no tracked file outside this lane's three paths was edited. + +## 3. Evidence: the measured and simulated numbers + +### 3.1 Ordering: what a withholder does to the selected chain (simulated, `ghostdag_results_1bps.md` section 2, 20 seeds, d = 0.67 s = the cloud devnet's p99 propagation, ledger F7) + +| attacker share H | hold 30 s | hold 60 s | hold 90 s | hold 120 s | +|---|---|---|---|---| +| 20% | won 10%, reorg med 0 / max 18, att blue 65% | 0%, 0 / 1, 38% | 0%, 0 / 1, 21% | 0%, 0 / 1, 18% | +| 34% | won 40%, 0 / 18, 77% | 40%, 0 / 36, 55% | 5%, 0 / 39, 35% | 10%, 0 / 52, 28% | +| 45% | won 70%, 10 / 17, 94% | 75%, 22 / 32, 84% | 70%, 33 / 46, 80% | 70%, 46 / 57, 80% | +| 51% | won 85%, 10 / 15, 90% | 85%, 20 / 28, 88% | 80%, 32 / 44, 86% | 80%, 42 / 53, 84% | +| 67% | won 100%, 8 / 13, 98% | 100%, 16 / 23, 98% | 100%, 26 / 31, 99% | 100%, 34 / 41, 99% | +| 90% | won 100%, 2 / 4, 98% | 100%, 4 / 9, 99% | 100%, 6 / 13, 99% | 100%, 9 / 17, 99% | + +"won" = the private tip became honest miner 0's selected chain; "reorg" = chain blocks removed from the chain it held at release (median / max over seeds); "att blue" = the attacker's blue blocks over its blocks in the honest view (its weight and subsidy kept). The fork age when it wins equals the hold (30 to 122 s). At d = 5 s (Kaspa's design bound) the same shares win more often at short holds (34% wins 100% at 30 s) and the same at long ones. Natural reorg depth with no attacker: p99 2, max 2 to 3 at d 0.35 to 0.67 s (the cloud devnet measured p99 3, max 5 over 37,113 removals, ledger F7); p99 15 at d = 5 s. + +The arithmetic behind the table: the attacker's private chain merges honest blocks as blue until its first private block has k honest blues in its anticone, then every later honest block is red in that chain. So the private tip's blue work is R + min(k, N_h) against the honest tip's N_h, with R = H lambda T and N_h = (1 - H) lambda T: it wins whenever R + k > N_h, that is for every T when H >= 1/2 and for T < k H / ((1 - 2H) lambda) below it (6 s at 20%, 56 s at 34%, 180 s at 45%, with Poisson noise around each). The honest blocks it turns red (hon red: 25 to 46 percent of honest blocks at 45 to 51 percent and 60 to 120 s holds; 4 to 14 percent at 34 percent) pay their 80 percent to the attacker when its chain wins (spec 02 2.5, the red rule), so a sustained withholder at or above 45 percent takes honest subsidy and raises its weight share; at 20 to 34 percent its own blocks go red and it loses both. + +Weight share a repeating withholder settles at, derived from the 60-s rows (the longest hold that beats the lock on every checkpoint, section 5.1), approximate: w = H x attblue / (H x attblue + (1 - H)(1 - honred)). + +| H | 20% | 34% | 45% | 51% | 67% | 90% | +|---|---|---|---|---|---|---| +| weight share under sustained 60-s withholding | 9% | 25% | 48% | 56% | 77% | 95% | +| blue rate the difficulty controller reads (share of true) | 86% | 76% | 79% | 80% | 86% | 94% | + +So 51 percent of hash reaches about 56 percent of weight by red-flooding the honest side, still 11 points under two thirds; the honest miners lose about a quarter of their subsidy for as long as it lasts, and the chain reorganises every minute, in public. + +### 3.2 Ordering at 10 blocks/s (simulated, `ghostdag_results_10bps.md`, k = 124) + +| measure | d = 0.35 s | d = 0.67 s | d = 2 s | +|---|---|---|---| +| natural reorg depth p99 / max, no attacker | 11 / 15 | 22 / 26 | 99 / 109 | +| 51% hold 30 s: won, reorg med / max | - | 100%, 50 / 58 | - | +| 51% hold 90 s | - | 100%, 146 / 163 | - | +| 34% hold 30 s / 60 s | - | 95% (59 / 64) / 0% | - | +| 20% hold 10 s / 30 s | - | 45% (10 / 33) / 0% | - | + +At 10 blocks/s the same shares reorganise ten times the chain blocks in the same seconds, and the natural reorg depth at a 2-s delay (99) is above the mainnet checkpoint depth d = 60. C1's rule that d scales with the rate (d = 60 B, ledger F7 round 2) is load-bearing; at 10 blocks/s with d = 600 the determination sits 60 s behind the checkpoint as at 1 block/s. + +### 3.3 The star: run A reproduced (simulated inline, section 4.3 code; 10 bps, k 124, 8 miners, honest only, 120 s) + +| uniform relay delay d, s | blocks in flight | honest blocks red | natural reorg p99 / max at miner 0 | reading | +|---|---|---|---|---| +| 0.67 | 7 | 0% | 19 / 23 | healthy | +| 2 | 20 | 0% | 78 / 99 | reorgs grow with d | +| 5 | 50 | 0% | 8 / 133 | still under k | +| 10 | 100 | 31% | 0 / 0 | past k/lambda: miners stop switching, each on its own chain | +| 15 | 150 | 50% | 0 / 0 | | +| 20 | 200 | 60% | 0 / 0 | | +| 30 | 300 | 67% | 0 / 0 | run A's 77% red sits beyond this row | + +Once the effective delay passes k / lambda (12.4 s at k 124 and 10 blocks/s), the DAG stops converging: every miner's own tip is heaviest in its own view, red climbs to two thirds, and the "reorg 0" rows are the absence of consensus, not its presence (run A's 321 tips). Through one hub relaying 12 blocks/s to 41 peers the effective delay is the hub's validation and relay time, which the fleet measures and this lane does not; the model says 77 percent red needs 30 s or more of it, approximate. The controller then reads the blue rate as a third of the true rate and eases, which widens the DAG further (section 4.2 attack 8). Lane 5 owns the fix; the attack bound is in 4.2. + +### 3.4 Finality weight over the adversary's share (simulated, `finality_horizon_results.md`, seeds 7 and 11; the table is inserted in section 3.5 from the run) + +### 3.5 Finality sweep results + +Condensed from `finality_horizon_results.md` (seeds 7 and 11; the full tables are there). A = the adversary's share. + +| sweep | 20% | 34% | 51% | 67% | 90% | +|---|---|---|---|---|---| +| R renter, signing: day it reaches 1/3 / 2/3 (sim; formula 10/A, 20/A) | never / never | 30.0 / never | 20.0 / never | 15.0 / 30.0 | 12.0 / 23.0 (formula 11.1 / 22.2; the dust effect of B) | +| S silent set keeps mining, 6 h: locks while silent, first lock after resume | 100%, 0 min | 0%, 0 min (720 stalled) | 0%, 0 min | 0%, 0 min | 0%, 0 min; 0 conflicts in every row | +| K bought keys worth A, buyer mines 30%: veto held (days) / stalls if silent (of 86,400) | never / 816 to 1,045 | day 1 to 6 / 36k to 42k | day 1 to 24 / 74k to 76k | day 1 to 26 / 79k to 80k | day 1 to 27 / 82k; share at day 30 is 30% in every row; 0 conflicts | +| E poisoned eclipse, 20% pool, 2 h: conflicting locks (eclipsed side holds 20% + A) | 0 (40%) | 0 (54%) | 67 to 70 from minute 2 (71%) | 30 to 32 from minute 4 (87%) | not run: the attacker alone is over 2/3 | +| P 50/50 partition with an equivocator, 150 min, v2 and v3: conflicting locks, first at | 0 | 21 to 70, minute 14 to 78 (the knife edge) | 299 to 300, minute 0 | 301, minute 0 | 293 to 300, minute 0; every pre-heal lock kept, 0 post-heal stalls, v3 = v2 in every cell | +| C abrupt departure (stops mining and signing): first lock, days, v2 / v3 (analytic v2 30(1 - 1/(3A))) | 0.00 / 0.00 | 0.8 / 30.0 (0.6) | 10.5 / 30.0 (10.4) | 15.2 / 30.0 (15.1) | 18 to 19 / 30.0 (18.9); 0 conflicts | + +Readings. R: the formula holds to 0.1 day; 51 percent never reaches two thirds. S: from one third upward the pause is exactly the silence, free to the silent set. K: bought weight is worth its blocks and decays; a silent 51 percent buyer pauses finality for 24 days then loses the veto. E: an eclipse cannot produce a conflict below the one-third equivocator bound whatever the pool; above it the conflict is the equivocator's, not the eclipse's. P: the bound is one third in every view under both rules, as 3.11.2 says; at 34 percent the model's 2.2 percent outage makes it intermittent (21 to 70 of 300 indices). C: under v2 the pause after a departure ends when the survivors fill two thirds of the sliding table; under v3 (the live rule since 135,200) on day 30 whatever the share; on the devnet's 2-hour window those days are minutes: 2 h after the last lock under v3, which for tonight's 18:39:40Z lock is about 20:40Z (approximate, if the departed boxes hold over a third of the frozen table and do not return). + +### 3.6 Signalling (arithmetic, `signalling_results.md`) + +| fact | value | +|---|---| +| noise on a one-day window share at p = 0.95 | 0.07 points; a 94.5% fleet never flips, a 95.1% fleet flips on day one (P 0.91) | +| 6% holdout rent per day at 1 / 10 / 100 / 1,000 GH/s | USD 18 / 179 / 1,792 / 17,923 (it earns 6% of the subsidy meanwhile) | +| forced flip, 95% of one day's blue blocks (19 N for 24 h) | USD 5,335 at 1 GH/s, 53k at 10, 534k at 100, 5.3M at 1 TH/s; the market could not supply a TH/s on 6 Oct | +| signal then defect | the defector's blocks fail PoW under the new program and are refused; cost falls on it alone | + +### 3.7 Cost of every attack (arithmetic, `cost_results.md`, excerpt; the full table has 12 rows x 4 network sizes) + +| attack | share, duration | rent at 1 GH/s | at 100 GH/s | at 1 TH/s | subsidy earned meanwhile (IGN) | +|---|---|---|---|---|---| +| win the lock-latency race (90 s) | 51%, 90 s | USD 0.3 | USD 30 | USD 304 | 1k | +| 12-h double spend during a pause or the first 30 days | 51%, 12 h | USD 146 | USD 15k | USD 146k | 559k | +| orphan an hour beyond merge depth during a pause | 51%, 1.5 h | USD 18 | USD 2k | USD 18k | 70k | +| the veto, 1/3 of weight | 51%, 20 d | USD 6k | USD 585k | USD 5.8M | 22M | +| lock alone, 2/3 of weight | 67%, 30 d | USD 17k | USD 1.7M | USD 17.1M | 44M | +| long-range private DAG over the window (cold start) | 51%, 30 d | USD 9k | USD 877k | USD 8.8M | 34M | +| hold a pause once the veto is held | 0 marginal | 0 | 0 | 0 | keeps earning | +| take the hands or the 8 aggregators down | 0 hash | DoS cost only | | | | +| fake proof records as a block producer | 0 extra hash | 0 | 0 | 0 | up to the whole 20% pool | + +At the rental-market equilibrium (hash joins until rent equals subsidy: 39, 156 and 780 GH/s at USD 0.005, 0.02 and 0.10) the veto nets about 48 percent of 20 days of the chain's subsidy and locking alone about 33 percent of 30 days; the 12-hour pause-time double spend costs about 12.5 hours of subsidy. + +## 4. The attacks, by layer: what each achieves, the defence, the bound, the price + +The hash shares H run 20, 34, 51, 67, 90 percent in every table; "rent" is A/(1 - A) x N x hours x USD 11.7 and the four network sizes are 1, 10, 100, 1,000 GH/s. + +### 4.1 GHOSTDAG ordering + +| attack | what it achieves (sim) | defence | bound | rent (1 GH/s to 1 TH/s) | earns | +|---|---|---|---|---|---| +| Selfish mining on the DAG (release when about to lose, lead 6) | blue share equals hash share within 0.3 points at every H (`ghostdag_results_1bps.md` section 3): honest blocks are merged, not orphaned, so there is no relative gain; max reorg 1 to 3 chain blocks | GHOSTDAG merges parallel blocks; a red block pays the merger | 0 gain; the attacker's reds are its loss | 0 extra | nothing | +| Withholding to reorder (double spend) | 20%: the last k blocks, 5 to 15% of attempts; 34%: 30 to 60 s, 40%; 45 to 51%: the whole hold, 70 to 85%, 32 to 46 chain blocks at 90 s; 67%+: every attempt | the lock: a candidate tip must pass through every certified checkpoint (spec 03 F1); the checkpoint block locks 63 to 93 s after it is mined | reorg depth = the lock latency, 90 to 120 s (spec 3.11.3), whatever H under 2/3 of weight; credit on the lock only (P17's four states) | 90 s at 51%: USD 0.3 / 3 / 30 / 304 | a deposit credited BEFORE the lock, which no conforming wallet does | +| Sustained red-flooding of honest blocks (repeat 60-s withholds) | 45 to 51%: honest blocks 25 to 28% red, honest subsidy to the attacker, weight share 48 to 56%, chain reorganising every minute | the lock bounds each hold to under 63 s (the first checkpoint inside the hold locks by then); W2 counts blues | weight ceiling about 56% at 51% of hash, 77% at 67% (approx., 3.1): a 51% miner never reaches 2/3 | the ordinary cost of 51% | about a quarter of honest subsidy while it lasts | +| Balance attack (keep two honest halves balanced) | needs network control, not hash: harness s3 and the redteam show a partition under merge depth heals to one chain (`redteam-2026-10-04.md` rows 2, 3) | merge depth 3,600 s merges the sides; beyond it, blue work and finality decide | one chain within merge depth; beyond it the 3.7 item 9 fork (section 4.3 finality) | 0 hash | nothing without a partition tool | +| k-cluster poisoning (make honest blocks red) | the same as red-flooding: only a withholder can be in an honest block's anticone without being in its past; share bound as above | k = 18 at 1 bps (Kaspa's table, delay bound 5 s) | at d = 5 s a 34% withholder turns 29% of honest blocks red in a 30-s window (sim) | as 51% | redirected subsidy at 45%+ only | +| Timestamp games on ordering | none on GHOSTDAG (order is by blue work and hash); on the clocks see 4.2 | 10-s future tolerance, parent minus 10 s (spec 02 2.3) | past-median time can run at most 10 s ahead of real time: nothing against a 30-day window | 0 | nothing | +| Merge-depth games (release a chain forked over 3,600 s ago) | honest blocks of the hour become unmergeable and are abandoned if the released chain is heavier: the 229-block shape of 6 Oct (CLAUDE.md 6 Oct rules) | F1: a chain missing a certified checkpoint is not a candidate; any lock inside the hour kills it | only during a pause or the first 30 days; depth then bounded by the finality depth, 12 h | 1.5 h at 51%: USD 18 / 183 / 2k / 18k | an hour of honest subsidy orphaned, none gained | +| Red-block flooding (publish blocks on stale parents) | the attacker's blocks are red, pay the honest merger, carry no weight; honest blues unaffected | W2, the red rule | pure loss to the attacker | | nothing | + +### 4.2 The difficulty rule: the seven recorded ways and the ones to add + +The seven of `sim/difficulty/attacks/README.md` and `results.md`, read not re-derived (Igneum rule v2 with the 4 October clock and floor): + +| # | way | recorded bound | status | +|---|---|---|---| +| 1 | pool hopping (10 to 100% of the base, 24 h) | +1.5% blocks per hash at most, 0.7 points over Kaspa's rule; a 60-s dwell makes the 50 and 100% hoppers lose 1.7 to 4.0% | PASS under 5%, open by the letter | +| 2 | pulsed rental (50x for 10 min hourly) | weight per hash 0.26 (Kaspa's rule 0.98): a pulse buys no weight; the base's blocks per hash fall 36% in the hour after | PASS (M14, F14 closed with the finality run: the renter never reaches a third) | +| 3 | timestamp stretching (30 and 50% forger, earliest, latest, alternating) | +0.4 to +1.1% drift after an hour (worst seed +2.7%), difficulty ratio 1.00, worst gap 10 s; on 3 igneumd nodes a 50% forger moved nothing (0.82 to 0.88 blocks/s, 0 rejected) | FIXED (M23); before the fix the chain ran at a fifth of its rate at 9.9x difficulty | +| 4 | short-lane oscillation (25% square wave every 120 blocks) | std 0.160 against 0.045 steady, 12% above the attacker's own square wave; the oscillator earns 1.4% less | FAIL by the letter, no past-only controller can pass, no change | +| 5 | epoch games (hold dodger, hold flooders) | 0.0%, +0.7%, +0.3% (worst +2.4%) | PASS | +| 6 | polluted window (10x joins and leaves at the lane switch) | settles 292 to 334 s, worst gap 17 s | PASS (Kaspa's rule 2,910 to 3,540 s) | +| 7 | block flood (85 blocks/s of PoW-less input) | the target stops at 2^128 after about 2,630 blocks, no panic | FIXED (floor) | + +Ways not in the seven, with the bound this lane gives: + +| # | way | model | bound | who gains | +|---|---|---|---|---| +| 8 | Red-share gaming: a withholder turns honest blocks red, the estimator counts blue work only (spec 02 2.3 "what this section does not do"), the controller eases | the 60-s rows of 3.1: the blue rate read is 0.86 of true at 20%, 0.76 at 34%, 0.79 at 45%, 0.80 at 51%, 0.86 at 67% | the ease is at most 1/(blue share) - 1: 16 to 32% more blocks per real second for everyone (emission above schedule by the same factor, spec 02 2.5); no relative gain to the attacker beyond 4.1's redirected subsidy; the attacker's own reds cap it | nobody relatively; everyone's emission runs 16 to 32% fast while it lasts | +| 9 | The star collapse (run A): effective delay past k / lambda, red to 67 to 77%, the controller reads a third of the rate and eases, the DAG widens | 3.3's table | a positive feedback with no attacker: the controller must read total work or the fleet must not be a star; lane 5 owns the rule, the fleet lib the topology | an attacker who can slow the hub (DoS) gets the collapse for free | +| 10 | Clock trust after a pruning-proof sync: a header whose selected parent has no stored clock starts from the raw stamp (difficulty-2026-10-03.md section 11, Limits) | not measured | at most one window of bias after a sync; a forger needs to be the first blocks a syncing node sees | a stretcher against fresh nodes only | +| 11 | Partition retarget: each side retargets to its share within 657 s (the 50x step-down figure), so each side keeps 1 block/s; at the heal the heavier side's targets rule and the lighter side's blocks carry less work | spec 02 2.3 measured steps; `finality_v2.py` +daa | consistent by construction; the minority's blocks merge red under merge depth | nobody | + +### 4.3 The finality weight + +| attack | what it achieves | defence | bound (sim) | rent | earns | +|---|---|---|---|---|---| +| Sybil (many keys) | nothing: weight is blue blocks, every draw is by weight (W6; harness s2: dust keys zero weight, sortition by weight PASS, F17 fixed) | W2, W3, F17 | 0 | 0 | 0 | +| Weight capture by mining (the renter) | share (t/30) A: 1/3 on day 10/A, 2/3 on day 20/A, never under A = 2/3 (`results_v2.md` B to 0.04 points; sweep R) | the 30-day flat window | 51%: veto day 20, 2/3 never while honest miners stay; 67%: day 15 and 30; 90%: 11.1 and 22.2 | 20 d at 51%: USD 6k / 58k / 585k / 5.8M | 22M IGN of subsidy | +| Weight capture by buying or renting keys | a bought key is worth its blocks and decays as the window slides: share = A (1 - t/30) + r t/30 (3.11.5; `results_v2.md` K; sweep K); keys worth 40% hold the veto from day 1 to 20, worth 20% never | W2 decay, W5 succession, equivocation strips a sold key the seller still holds | max(A, r) for a day, r after 30 days; a silent 40% buyer stalls 63k of 86k checkpoints then loses the veto on day 19 to 20 | the price of pools' keys, not hash | a pause of up to 20 days | +| Long-range (private DAG from an old point) | a cold node with no certificate follows the heavier DAG (F5) | F5's trusted certificate (designed, not implemented); the client-shipped checkpoint (proposal 11) | needs more blue work than the public DAG over the window: 30 days of >50% | USD 9k / 88k / 877k / 8.8M | 34M IGN | +| Eclipse (poisoned pool) | 0 conflicting locks, 0 locks on the eclipsed side at 1, 2, 4 h for a 34% attacker and a 20% pool (`results_v2.md` L3, F2); sweep E extends it to 51 and 67% | the 2/3-of-total floor binds whatever the presence window says (3.3.2) | the eclipsed side must hold 2/3 of total: a 47%+ attacker plus a 20% pool (sweep E, see 3.5) | the eclipse plus the weight | nothing under the bound | +| Partition with an equivocator | 0 conflicts to 33%, conflicts from 34% (`results_v2.md` H at 2/3; M5 under v3); sweep P at 51, 67, 90 | two certificates need 4/3 of weight in signatures (3.11.2) | 1/3 of weight, every view, any partition length under one window since the last lock (v3) | the 20-day veto | two finalised histories across a partition, each side's deposits | +| Equivocation alone | strips the key for 30 days, no coin penalty (F6); detection by any carrier block, agreed by every node (F23 fixed) | 3.6 | costs the attacker its weight, nothing else | | nothing | +| The 30-day window edges | (a) the frozen table expires at exactly day 30.00 after the last lock: both sides of a long split lock alone at once (M3); (b) a departed set leaves the sliding table over 30 days and the frozen one at the cliff (M4); (c) the first 30 days have no lock at all (3.8, `min_daa` = window); (d) new honest cohorts are under-weighted t/60 for 30 days (G) | stated in 3.7 items 2, 7, 9 | a partition or departure longer than one window ends with the fork of 3.7 item 9 and a manual F5 | | | +| The pause as a liveness attack | a silent set at or above 1/3 pauses every lock for as long as it stays silent (J, L1; sweep S) at zero marginal cost since it keeps earning | none in the rule; the node reports the pause; exchange guidance treats the chain as PoW with a 12-h depth | the 1/3 veto: 20 days at 51% | 0 once held | nothing directly; enables the 12-h PoW double spend below | +| What an attacker can do during a pause | plain proof of work: reorg up to the finality depth 43,200 DAA (12 h) with a heavier chain; beyond merge depth the honest blocks are abandoned (the 229-block shape); every certified checkpoint before the pause still binds | finality depth; the exchange guidance of 3.9 | 12 h of >50% hash | USD 146 / 1.5k / 15k / 146k | a deposit credited at the PoW depth; 559k IGN of subsidy as a miner | +| Tonight's departure (confirmed, lane 3 `finality-and-weight.md` 3.1 and 4.1) | 20 keys holding 42.7% of the frozen table stopped mining 18:27 to 18:30Z (the rehearsal job); the last lock 6842 at 18:39:40Z; 6843 determined with 53.1% of total signing and never locked; under v2 the stayers' sliding share crossed two thirds at 6912 (19:14:53Z, a 35-min pause) but Q5 held them at 57.3% of the frozen table; expected first lock when that table expires at DAA 216,402, about 20:40Z, or when 9.4 points of departed keys return. Sweep C agrees: 51% leaving pauses 10.5 days (v2) or 30.0 days (v3) at mainnet scale; at tonight's 46.9% (observer's view) 7.7 days under v2, 30 under v3 (lane 3, 4.1) | by design (F21: the project lead chose the pause over the fork); a view cannot tell a departure from a partition | anything over 1/3 of the table leaving at once pauses finality for a window | 0 | 0; what an attacker can do during it is the row above | + +### 4.4 Miner signalling (P2) + +| game | model | bound | price | +|---|---|---|---| +| 6% holdout blocks a change for ever | the window share has 0.07 points of noise: 94.9% flips with P 0.09, 94.5% never | the floor N6 ends it; nothing else does | USD 18 a day at 1 GH/s, 17.9k at 1 TH/s; the holdout earns 6% of subsidy meanwhile, so net about zero at equilibrium | +| What the floor does | converts the signal into a fixed height at N6: the hazard of 6 October (DAA 198,000 crossed while boxes were still updating: two-sided chain, 229-block reorg) returns for every node not on the object at N6 | the floor should sit no nearer than a week past the publish on a network miners run, and the stale-box list (P1 pass rule) must be empty before it | | +| Signal then defect | a defector's blocks fail PoW under the new program and are refused (`check_header_version` then PoW); a pool with stale workers loses their blocks | the defector pays, nobody else | | +| The one-day window | a renter at 19 N for 24 h with a patched byte forces the flip; for v4 it hurts nobody (the signalling binary is the v4 binary), for a later object it forks every node still on the old one | the share of the fleet not yet on the object at the forced flip | USD 5.3k at 1 GH/s to 5.3M at 1 TH/s, and the market could not supply a TH/s | +| Proposed | require 95% on each of 7 consecutive daily windows (7x the renter's bill, a week of visible share), keep the one-day tally for display | | 3 hours | + +### 4.5 Proof records + +| attack | today's rule | bound | who gains | +|---|---|---|---| +| Forgery of state | the native-execution veto: a record whose statement differs from the node's own execution of that segment along the carrying block's chain is ignored (7.2 item 5, P11 fixed) | state is never moved by a record; a soundness bug is a light-client problem (P7), a job-output problem for the precompile (D6, contained by R12) | nobody | +| Forgery of the proof (correct statement, random bytes) | NOT checked in consensus (7.7 item 4, 7.8 item 8); the first valid record per shard or segment carried pays | a producer at share H takes at least H of the 20% pool and, since its fake rides its next block while an honest proof takes 9 to 11 s on a 5090 (P9 table), most shards outside the 10-s exclusive window; inside it only the H of slots it is assigned | any block producer: 11,636 IGN/h at 51% of a pool paying 22,815 IGN/h | +| Withholding (an assignee sits on its window) | after 10 DAA s anyone may prove and be paid; a segment unproven after 600 DAA pays nothing (7.8 item 7); mandatory proofs off | one window of latency per absent assignee; nothing waits | nobody | +| Grief (flood the pool with invalid records) | 6,000 invalid records: 0 accepted, 0.31 to 0.68 ms each, node up (redteam row 10) | CPU per record | nobody | +| The aggregator naming itself as every prover | provers committed in the proof's public values and checked (P12 fixed) | 0 | nobody | +| Record ordering race | the first valid record carried wins: a producer can front-run honest provers' records in its own block (the forgery line) | fixed by consensus verification (rank 1), then by aggregator sortition (O-7.3) | | + +### 4.6 The execution layer + +| attack | today's rule | bound | note | +|---|---|---|---| +| Snapshot poisoning over p2p | `p2p_snapshot_gate` refuses tip 0, below the restart, at or below the own tip, and anything while the executor runs unblocked; a snapshot whose state at the restart block differs from `exec_restart_state_root` is refused (release-0.3.14.md) | a wrong state ABOVE the restart block is not detectable by the node: headers commit to no execution root (spec 02 2.6: blocks carry transactions only), certificates sign (chain id, index, block hash) only (C2) | the poisoned node's native statement then disagrees with every carried record, it pays nothing and sees every honest record as invalid; the signal exists but nothing reads it as an alarm | +| The pin | `exec_restart_number / hash / state_root / trust_daa` arrive by the signed manifest on the devnet (the reddit review's admin-key finding, 1.6 item 3); on mainnet no manifest exists, so the pin is genesis-only or absent | a release-key holder sets execution state on the devnet; on mainnet the same power would need the 95% signal | disclose (the review's key-powers table) | +| Deep reorg never resets execution | a reorg reloads the newest persisted generation at or below the fork (ring 2,048) else blocks loudly and asks a peer; never a genesis replay on a pruned node (0.3.14) | under active finality a reorg is bounded by the lock (90 to 120 s), far inside 2,048; during a pause the 12-h depth is 43,200 blocks, 21x the ring, so a pause-time deep reorg blocks every pruned executor until a peer's snapshot arrives, which is the poisoning path above | the ring should reach the finality depth (proposal 12) | +| Duplicate and nonce games, pgas bombs, malformed bodies | exec-attacks suite 96 of 97 checks, every executed block under B_p, an over-budget transaction refused at the mempool with the pgas metered (redteam row 28) | per block B_p of proving gas and B_e of execution gas; an aborted transaction pays | | + +### 4.7 Peer to peer + +| attack | what it achieves | defence | bound | price | +|---|---|---|---|---| +| Eclipse of one node | feed it a private chain: its difficulty eases to the attacker's hash within about 11 min (the 50x step-down takes 657 s), so 1% of the network's hash produces a plausible 1 block/s chain for the victim within 20 min; it sees no certificates and reports `finality_active` false | the exchange guidance (treat a pause as PoW with a 12-h depth); a node that holds locks will not follow a chain missing them (F1) | a victim that follows its node's finality flag loses nothing credited under a lock; one that credits at a PoW depth is Kaspa's or Monero's eclipse victim | a few IPs | +| Eclipse or outage of the hands | tonight's pause was NOT this (lane 3, 3.1: locks 6824 to 6842 formed with the hub down, the zero-aggregator fallback carried 64 of 251 certificates); the attack stands in general: a fleet that peers only through two hosts is a star, and a star with its centre down is a partition into n islands, each under 2/3, finality paused until the heal; longer than merge depth (60 min) it is the 3.7 item 9 fork | aggregator fallback (any node aggregates after 15 DAA s); votes ride in blocks (Q2); neither crosses a dead hub | pause for the outage; proposal 4 (peer floor) removes the star | 0 hash: the DoS of two hosts | +| Crash a pruned node from any peer (main, 19:57Z: the hub, a pruned 0.3.14 node, panicked on an `unwrap` over `KeyNotFound` at the devnet genesis when a re-joining peer synced below its retention; `consensus/src/processes/sync/mod.rs:87`, fix in 0.3.15) | any peer takes any pruned node down by asking for history it does not hold | none today; the rule: no `unwrap` or `expect` on a path a peer's request reaches, a `SyncManagerError` instead, and a fuzz of the sync request space (locator low/high, antipast low/high, missing-bodies high, pruning-point anticone) against a pruned node as the CI gate | zero hash; one request per node; repeated, a liveness attack on every pruned node (every mainnet node prunes) | 0 | +| Eclipse of the seeds (3 Hetzner DNS seeds) | a fresh node bootstraps into attacker peers and, with no trusted certificate, follows their DAG (F5 cold start) | none implemented; F5 designed | the long-range attack's price (4.3) for the DAG, zero for the eclipse | USD 9k to 8.8M for the DAG | +| Handshake refusal (params digest) | a peer with another digest is refused before any flow (X18); an attacker cannot make honest peers refuse each other | it is a defence; the only cost is the digest-less allowance still open on devnet and simnet | 0 | | +| The p2p snapshot path | 4.6 | | | | +| Memory under flood | 269 to 780 MB per minute of flood on 0.3.4 (M30), bounded since 0.3.5 to the record window plus pruning depth | | | | + +Siblings of the 19:57Z crash class, read-only grep of the fork (main checkout `vendor/igneum-node`, 6 Oct) for `unwrap` and `expect` on paths a peer's request reaches. The sync manager's entry points are called from the request flows (`protocol/flows/src/v10/request_headers.rs`, `request_antipast.rs`, `request_block_locator.rs`, `request_ibd_chain_block_locator.rs`, `request_pruning_point_and_anticone.rs`, `request_block_bodies.rs`) through `consensus/src/consensus/mod.rs:1341` (`get_hashes_between`), `:1624` (`get_missing_block_body_hashes`), `:1647` (`create_block_locator_from_pruning_point`): + +| file:line | what panics | reached by | +|---|---|---| +| `consensus/src/processes/sync/mod.rs:87, 88` | `ghostdag_store.get_blue_score(low/high).unwrap()`: the hub's crash when `low` is below retention | `antipast_hashes_between` from a peer's antipast or headers request | +| `sync/mod.rs:94` | `ghostdag_store.get_data(current).unwrap()` on the forward chain walk | the same | +| `sync/mod.rs:117` | `find_highest_common_chain_block(...).expect("because of the pruning rules such block has to exist")`: false once the peer's `low` is pruned | the same | +| `sync/mod.rs:123, 125, 130, 135, 148` | pruning point, selected-chain tip and index lookups `.unwrap()` | `create_virtual_selected_chain_block_locator` from a peer's locator request | +| `sync/mod.rs:162, 172, 182, 194, 196` | status lookups `.unwrap()` along a peer-named `high` | `get_missing_block_body_hashes` from a peer's IBD blocks request | +| `sync/mod.rs:211, 221` | `get_blue_score(low)`, `get_compact_data(current)` `.unwrap()` | `create_block_locator_from_pruning_point` from a peer's IBD chain locator request | +| `protocol/flows/src/v10/request_headers.rs:98` | `hashes.last().expect("caller ensured ...")` | the headers request flow, after `get_hashes_between` | +| `protocol/flows/src/ibd/negotiate.rs:40, 47, 112, 166, 172` | `locator_hashes.last().unwrap()` on a locator the PEER sent | the IBD negotiation (the syncee side, a hostile syncer) | +| `protocol/flows/src/ibd/flow.rs:307, 361, 436, 440, 700, 717` | `async_get_header(...).unwrap()`, `async_validate_pruning_points(...).unwrap()`, `pruning_points.last()/first().unwrap()` on peer-sent pruning points | IBD against a hostile syncer | + +The rest of the hits in those files are test code (`request_headers.rs:199 to 222`, `request_pruning_point_and_anticone.rs:197 to 280`, `trusted_data.rs:81 to 149`, `proof.rs:144 to 230`) or channel sends. Bound of the class: zero hash per crash; every pruned node on the network can be taken down by one request each, repeatedly, which during a pause or the first month is a liveness attack on the chain itself and at any time on the hands. Proposal (lane 1, 4 hours): convert the sync manager's unwraps to `SyncManagerError` variants, make the negotiation and IBD paths return `ProtocolError` on a missing block, and add `tools/ci` fuzz `sync-request-fuzz` that drives the six request flows with random and below-retention hashes against a pruned fast-time node and fails on any exit; gate: 10,000 requests, node alive, 0 panics. + +### 4.8 The harness run (real DAG, 0.3.14 binary, rule v3, fast time) + +`tools/finality-attacks/run.mjs s6 --fast-time`, SCALE 0.4, rule v3 forced on (`finality_v3_activation_daa` 0), the 0.3.14 Mac binary (`vendor/igneum-node/target-0314/release/igneumd`, built 6 Oct 17:56) and its `igneum-miner` (`vmine`), ports 29800 to 29812, suffix 980, `/tmp/igneum-horizon-fin`, run lock held 19:53 to 20:03Z. The 0.3.14 node refuses the master copy of `infra/fast-time/override-60x.json` (unknown fields `program_class_v4_activation_daa` and `program_class_v4_signal_window_daa`, which only the `ca3-v4-node` binary knows), so the harness ran from a scratch copy of `tools/finality-attacks` and `infra/fast-time` with those two fields removed; nothing tracked was edited. Six vmine voters at 6 blocks/s in all (3 per side), window 120 DAA, warm 168 s, split 60 s, heal 60 s. + +| scenario | measured | reading | +|---|---|---| +| A, 3/3 split | window DAA ~1,019 at the cut, 6 voters, max locked 34 on both sides; new locks during the 60-s split 12, the first on each side at 30 s; locks resumed after the heal; conflicting certificates 9 / 11 after the heal | the recorded F21 shape at this scale: a side at 3 blocks/s advances its own DAA 3 a second, so the frozen table (one window of 120 DAA after the last common lock) expires 30 to 40 s into the split and the sliding table then locks each side alone, exactly as the redteam's row 18 (36 and 49 s) and the simulator's M3; the harness criterion (`zero new locks`) asserts more than the rule promises past one window | +| B, 4/2 split | window DAA ~900, max locked 30; the 4 side locked 30 to 38 (first at 33 s), the 2 side stayed at 30 for the split; conflicting certificates 1 / 12 after the heal | the 4 side holds 4/6 = two thirds of the frozen table and locks as Q3 allows (inclusive); the 2 side locks nothing while the table stands; the post-heal conflicts are the 2 side's late solo locks after its own table expired (redteam row 18 saw the same 4 late locks), the F21 residual | + +What it adds to the sim: the real DAG at fast time reproduces the frozen-table bound within its own DAA clock and the v2 control's shape (`split50-v2.md`: 3 solo locks at 126 s, 4 conflicts); nothing contradicts the simulator. What it does not test: a withholding attacker (vmine has no withhold flag) and any run longer than the window. + +## 5. Model: the formulas and what holds + +### 5.1 The ordering race against the lock + +Inputs: lambda blocks/s (measured 1 on the devnet), k = 18 (cited, Kaspa's table), d (measured 0.34 to 2.3 s), checkpoint interval I = 30 blue score and depth d_cp = 60 (designed), lock latency after determination median 2.5 s, p99 4.6 s (simulated, `results_v2.md` A), 0.8 to 1.08 s on the test network (measured). A deposit at time 0 lies under the checkpoint block mined at most 30 s later, which locks at most 30 + 60 + 3 = 93 s later. An attacker forking before the deposit must win the race before that lock (after it, F1 excludes its chain). From 3.1: wins need H >= 1/2 for any T, or T < k H / ((1 - 2H) lambda) below it; at T = 90 s that is H >= 0.45 with Poisson noise (70 to 85 percent at 45 to 51 percent, 5 to 10 percent at 34 percent). Hence: a majority reorders at most the lock latency; a 34 percent miner at most about 60 s; a 20 percent miner at most the last k blocks. The honest guidance (credit on the lock) makes every case a zero. + +### 5.2 Weight + +share_renter(t) = (t/30) A (verified, B, sweep R); share_buyer(t) = A (1 - t/30) + r t/30 (verified, K, sweep K); two certificates need 4/3 of total in signatures, so the equivocator bound is 1/3 in every view (3.11.2, H at 2/3, M5 under v3); a partition side's own table reaches 2/3 on day 30 (2/3 - s)/(1 - s) under v2 (L4) and never before day 30 under v3 (M2, M3); a departed share x pauses 30 (1 - 1/(3x)) days under v2 and 30 days under v3 (L2, M4, sweep C). The weight ceiling of a withholder is 3.1's w(H) with the 60-s rows. + +### 5.3 Rent + +cost = A/(1 - A) x N x hours x 11.7 USD (measured price); earned = 0.8 x A x 31.688 x 3600 x hours IGN (spec 02 2.5); N_eq = 0.8 x 31.688 x 3600 x P / 11.7 GH/s at IGN price P (assumption inputs). At N_eq the veto nets about 0.48 x 480 h of subsidy and locking alone 0.33 x 720 h. + +### 5.4 What holds, what breaks + +| claim | holds | evidence | +|---|---|---| +| No hash share under 2/3 of weight reverses a certified checkpoint | yes | 3.11.2, H and M5 (0 conflicts under 1/3 in every seed), the DAG sim (the race ends at the lock) | +| 51% of hash never reaches 2/3 of weight while honest miners stay | yes, with margin: 56% ceiling under red-flooding (approx.), 51% honest | B, sweep R, 3.1 | +| A majority cannot forge a proof the nodes re-execute | yes for state; NO for payment: the proof itself is not checked and the pool is capturable | spec 07 7.7 item 4, 7.8 item 8 | +| A rule changes only at 95% signalling | yes for the signal path; the floor is a fixed height that can cross with stale nodes | P2, signalling.py | +| A majority loses more than it earns | for the veto and the lock-alone, yes (net 48% and 33% of the period's subsidy at equilibrium); for the pause-time 12-h double spend and the fake records, NO | cost_model.py | +| The pause is safe | safe for history, costly for liveness, and buyable at zero hash by taking the hub down | tonight; sweep S and C | + +## 6. Ranked proposals: the defences we do not have + +| rank | proposal | evidence | model | hours | consequence per tier | gate | +|---|---|---|---|---|---|---| +| 1 | Verify the aggregated segment proof in consensus (a record whose proof does not verify against the pinned aggregator key is invalid; the per-shard v0 record stays payout-only until then and is capped at the exclusive window) | 4.5: a producer captures H to most of the 20% pool with fake records; P21 "stated, not fixed" | capture = pool x (H inside the window + most outside); verification cost per record = SP1 light verifier (P3: 1.3 to 2.1 s setup, then per-proof ms, to measure) x 2 records per block | 8 to 12 | home miner (8/12/16 GB): its honest shard records are paid, not front-run; rig and pool: proving income real; prover: the market is honest; holder: 20% of emission is not a miner's bonus; rollup customer: a paid proof is a verified proof; node: +verify CPU per block | fast-time: a correct-statement fake record is refused, an honest one paid, p95 block validation under 50 ms with 2 records | +| 2 | Weight-gated deep fork choice: among candidate tips, a tip whose fork point is older than D (say 10 min of past-median time) is a candidate only if the blocks on it since the fork were produced by keys holding at least 1/3 of the weight table at the fork point (a function of the block's past, deterministic) | 4.3 "during a pause": a renter with fresh keys double-spends at the 12-h depth for USD 146 at 1 GH/s; the DAG sim's 90-s race | rented hash has zero weight for 10 days (W2), so its deep chain is never a candidate; honest partition sides over 1/3 keep today's behaviour; a side under 1/3 cannot reorg the other past D, which is the desired outcome | 10 to 16 (virtual processor candidate filter + weight-at-fork from the finality tables) | home miner and rig: nothing changes; pool: nothing; holder and exchange: a pause-time or first-month deep reorg needs 1/3 of weight, 20 days in public, not 12 h of rent; node: one table lookup per deep candidate; rollup customer: PoW-depth credits become weight-backed | fast-time: a fresh-key renter at 3x the hash forking 2 min back is refused for ever; a 40%-weight honest side forking 2 min back is adopted | +| 3 | Vote-or-burn: a block whose producer key has participation under 0.5 over the presence window in the block's own past burns 20% of its producer share | 4.3 "the pause as a liveness attack": zero marginal cost | the attacker's pause then costs 0.2 x A x 0.8 x 114,077 IGN/h: 7,757 IGN/h at 34% (USD 155/h at 0.02); partition-safe because the test is the block's own past (a side's keys vote their own checkpoints); honest outages (2.2%) leave participation above 0.9 | 6 to 8 (coinbase rule + the finality manager's participation count at the block) | home miner under dust: not a voter, counts 1, unaffected; a miner whose node never revealed a vote key: loses 20% until it does (an incentive); pool: votes or pays; holder: silent weight stops being free | fast-time: a 40% silent set's coinbases shrink 20%, honest ones do not, both sides of a 3/3 split unaffected | +| 4 | Peer floor and mesh for the fleet and the node: the fleet lib dials at least 3 other boxes beside the hands; the node logs an alarm and the app shows it when outbound peers fall under 3 or when no vote has been received for 2 checkpoints | run A's star (321 tips, 77% red); the hands as the fleet's only peers (lane 3 refuted this as tonight's cause; the shape stands) | a star with its hub down is n islands; with 3 extra peers per box the graph stays connected under any single failure | 2 to 4 (fleet lib) + 3 (node alarm) | every tier: finality stays up when a hand dies; home miner: sees "no peers" instead of a silent pause | Devnet 2: kill the hub for 10 min, locks continue; the alarm fires on the known-bad case and not on the known-good | +| 5 | Vote over the execution root too: the vote signs (chain id, index, block hash, post_root of the checkpoint's segment); a certificate then pins the state, snapshots are checked against the last certificate, and the poisoned-snapshot node cannot join the quorum | 4.6 snapshot poisoning: a wrong state above the pin is undetectable | every voter is a full node that executes natively (spec 07); the cost is exec lag added to lock latency (the executor runs seconds behind the tip) | 8 to 12 | holder and exchange: a certified checkpoint carries its state; rollup customer and light client: one object says ordered and executed; node: a divergent executor is visible at once; miner: a vote waits for its executor (lock latency + exec lag) | fast-time: three nodes agree; a fourth with a tampered snapshot votes a different root and is outvoted, alarm raised; lock latency rises by the measured exec lag only | +| 6 | Signalling over 7 consecutive daily windows, floor no nearer than 7 days past the publish, the stale-box list empty before the floor | 4.4 | the renter's bill x7; a week of visible share | 3 | pool and rig: a week more before a class change; home miner: a week to update | fast-time gate: 6 of 7 days at 95% does not flip; 7 does | +| 7 | Detector-driven alarms: the share-pattern detector (counter-asic-3-status, Detector row) and the finality flag feed one node-side `security_alert` (correlated group over 1/3 of a day's blue blocks; pause; conflict) that wallets and the explorer show as "confirm at 12 h" | 4.3, the exchange guidance exists only as text | an alarm when any single party crosses the veto line in public, which the rule says takes 10 to 20 days | 4 to 6 | holder and exchange: a number to act on; home miner: the app shows the chain's state | fast-time: a 34% silent set raises the alarm within 5 min; the honest run never does | +| 8 | The signed departure (LEAVE: lane 3's rank 1, `finality-and-weight.md` section 6; a `leave` item carried in blocks, the key out of every denominator one hour after inclusion, sent by the app and the fleet library on a clean stop) and F5's trusted certificate implemented | tonight's departure (lane 3, 3.1): 42.7% left in three minutes and the frozen table held finality for a window; a view cannot tell a departure from a partition, so no automatic rule re-enables locks without reopening L4/M3 | stripping lowers total; an attacker stripping stolen honest keys is K's bound (needs keys worth 1 - a/(2/3)); lane 3's sim T: first lock 1 h after a 34 to 50% departure, 0 conflicts in every partition row | 6 (lane 3) + 4 | pool and rig: an orderly stop keeps finality up for everyone; holder: no 30-day pause after a planned fleet move; node: the operator's certificate for the disorderly case | fast-time: 45% of weight stops with exits, locks continue; without, the pause | +| 9 | Client-shipped checkpoint: each release carries the latest certified checkpoint (index, hash) and voter-table digest; a cold node refuses a DAG missing it (assumevalid's shape) | 4.3 long-range, 4.7 seeds | the long-range attack must then out-work the public DAG since the release, not since the window | 3 | every tier: a fresh install cannot be bootstrapped onto a private DAG; trust is the release key already trusted for the binary | a cold node offered only a private heavier DAG refuses it | +| 10 | Exec generations spaced geometrically to the finality depth (1, 2, 4 ... 43,200 blocks: about 16 generations) so a pause-time deep reorg never needs a peer's snapshot | 4.6 | 16 x state size on disk (about 1.8 GB today, measured 114.8 MB per snapshot) | 3 | node operator: disk; every tier: no blocked executor after a deep reorg | fast-time: a 5,000-block reorg re-executes from a generation, no snapshot request | +| 11 | Checkpoint anchoring to proof records (the certified checkpoint's hash as a public value of the next aggregated proof; the verifier checks the certificate natively) | asked by the brief | buys light clients and bridges one object (certified and proven); changes nothing a full node does, since the proof chain already commits to block hashes and a reorg already needs new proofs; in-circuit BLS is 40+ hours and not worth it | 6 (public-value commit) | rollup customer and light client: one verification; others: nothing | a light client verifies a proof carrying a certificate hash and the certificate | +| 12 | Prover attestations as a second finality leg (a lock also needs proof records from a quorum over the checkpoint) | asked by the brief | NOT recommended: provers are the miners (same vote keys), so no new party; proving covers 2.4% of blocks today and the pool is "not active" (reddit review 1.4), so every lock would wait on proofs and finality would pause constantly; what it would add (execution validity) rank 5 gives without the liveness cost | 8 if ever | every tier: lock latency becomes proof latency (20 to 60 s target, minutes today) | only once coverage is 100% and rank 1 is in | +| 13 | Time-locked (vesting) weight | asked by the brief | NOT recommended: a bought key transfers vested weight, so K's bound is unchanged; honest new cohorts wait N days longer than G's 20 | 3 if ever | new home miners: later vote; attacker: unchanged | none | +| 14 | Any rule that keeps finality on after a large honest set leaves abruptly without a signed exit | asked by the brief | NOT possible safely: departure and partition are the same observation in one view; re-enabling locks under the frozen table reopens the double lock of L4 and M3 at the same day; the honest options are rank 8 (exit) and a shorter frozen expiry, which trades the partition bound one for one | 0 | | | + +One paragraph each on the two that matter most. + +Rank 1, proof verification in consensus. Today a record is paid on a signature and a statement match; the statement is computable by every node, so a producer writes the right statement, random proof bytes and its own payout address into its own coinbase and is paid the shard or the aggregator share. The exclusive window limits it to the slots it is assigned (by weight, so H of them) for 10 DAA s; after that the first record carried wins, and the producer's block is first. The only thing that stops it is a verified proof as a condition of payment. SP1's light verifier exists (`igneum-prove-host --mode verify-segment`); the cost to measure is the per-proof verification time on the validation path, and if it is over a few tens of milliseconds the aggregated record (2 per block) is the one to verify in consensus while the per-shard record stays payout-only inside the window. Consequence per tier: an 8 GB home miner that proves on the patched prover is paid for what it proves; a pool's proving income is real; a holder's 20 percent of emission goes to proofs. + +Rank 2, weight-gated deep fork choice. Finality's whole argument is that weight cannot be rented; fork choice today ignores weight, so during a pause or the first month a renter's heavier chain reorganises up to 12 hours. The rule: a candidate tip whose fork point is more than D of past-median time behind the node's selected tip is a candidate only if the keys that produced its chain blocks since the fork hold at least a third of the weight table at the fork block (the same `voters_at` the finality manager computes). It is deterministic (a function of the DAG), it leaves every reorg under D to GHOSTDAG as now, it leaves honest partition sides over a third exactly as now, and it makes the pause-time double spend cost the veto (20 days in public) instead of 12 hours of rent. What it costs: a side of a partition under a third of weight that is heavier by work cannot reorganise the other side past D at the heal, which is the outcome the certificate would have produced anyway; and a cold node with no table yet follows F5. Gate: the fast-time run in the table. + +## 7. Open questions and what could not be run + +| item | why | +|---|---| +| The star's effective relay delay | the model needs the hub's measured relay time at 12 blocks/s to 41 peers; main's run A rows give the outcome (77% red, reorg 55) and this lane gives the curve (3.3); the fleet measures the delay | +| The finality sweep's R row at 90% | the renter's 9x hash makes 905 honest keys fall under dust in the model (B's dust effect), so the simulated share overshoots the formula by 1 to 2 points, as B recorded | +| Proof verification time on the validation path | not measured; P3 gives setup only; rank 1's hours depend on it | +| Weight-gated fork choice against the C4 certificate-driven reorg | a certificate over a deep block must still force the reorg (3.5); the gate must exempt certified tips; not modelled | +| The DAG simulator has equal work per block, no difficulty, no bodies | a withholder also controls its blocks' timestamps and the attack-side difficulty; the 10-s rules bound the clocks, the DAA lane bounds the rest | +| igneumd harness | one s6 run on the 0.3.14 Mac binary (4.8); the node-side numbers for the other scenarios are the recorded runs cited | +| The live pause's end | lane 3's arithmetic (4.1): the frozen table of lock 6842 expires at DAA 216,402, about 20:40Z, unless departed keys holding 9.4 points of it return first; main reads the chain | + +## 8. Summary paragraph + +The ordering layer and the lock together bound a hash majority to the lock latency: the DAG simulator shows 45 to 51 percent winning the 90-second race 70 to 85 percent of the time and nothing beyond it, 34 percent winning only inside 60 s, 20 percent only the last k blocks; weight cannot be rented faster than 10 days per third, bought keys decay as the window slides, no equivocator under a third splits finality in any view, and the costs in rented hash are USD 6k to 5.8M for the veto and 17k to 17M to lock alone across 1 GH/s to 1 TH/s, of which the attacker earns back half as subsidy. Three things a hash majority does buy today: the proving pool, by writing fake records into its own blocks (the one line that earns more than it costs); a 12-hour proof-of-work double spend during a pause or the first month for USD 146 to 146k; and a pause needs no attacker at all, since a planned 43 percent departure caused tonight's and the frozen table holds it for a window (lane 3, 3.1). The three findings as numbered lines: + +1. A 51 percent withholder reorganises at most the lock latency (90 to 120 s; 32 to 46 chain blocks at 1 block/s, 80 percent success), reaches a weight ceiling of about 56 percent by red-flooding (never two thirds), and costs the honest side a quarter of its subsidy while it lasts (`ghostdag_sim.py`). +2. The veto costs 20 days of 51 percent in public (USD 6k at 1 GH/s, 5.8M at 1 TH/s, half earned back) and then holds a pause for free; a pause-time 12-hour double spend costs USD 146 to 146k (`cost_model.py`, `finality_horizon.py` S and C); weight-gated deep fork choice (rank 2) makes it cost the veto instead. +3. Any block producer captures from H to most of the 20 percent proving pool today with correct-statement fake records (11,636 IGN an hour at 51 percent), because consensus does not verify the proof (spec 07 7.7 item 4); proof verification in consensus is rank 1. + +## 9. Files and how to run them + +| file | run | +|---|---| +| `sim/horizon/consensus-security/ghostdag_sim.py` | `with-lock.sh run nice -n 19 python3 sim/horizon/consensus-security/ghostdag_sim.py --seeds 20 --out ghostdag_results_1bps.md`; `--bps 10 --k 124 --delays 0.35,0.67,2 --holds 10,30,60,90 --warm 60 --post 15` for the 10 bps grid | +| `sim/horizon/consensus-security/finality_horizon.py` | `with-lock.sh run nice -n 19 python3 sim/horizon/consensus-security/finality_horizon.py --out finality_horizon_results.md` (imports `sim/finality_v2.py`) | +| `sim/horizon/consensus-security/signalling.py` | `python3 sim/horizon/consensus-security/signalling.py --out signalling_results.md` | +| `sim/horizon/consensus-security/cost_model.py` | `python3 sim/horizon/consensus-security/cost_model.py --out cost_results.md` | +| results | `ghostdag_results_1bps.md` and `.json`, `ghostdag_results_10bps.md` and `.json`, `finality_horizon_results.md`, `signalling_results.md`, `cost_results.md` in the same directory | diff --git a/docs/analysis/horizon/economy-and-utility.md b/docs/analysis/horizon/economy-and-utility.md new file mode 100644 index 000000000..2796106f7 --- /dev/null +++ b/docs/analysis/horizon/economy-and-utility.md @@ -0,0 +1,356 @@ +# Horizon lane 4: economy and utility. What IGN is for beyond gas, the 80/20 under stress, ten years without a treasury, the dev fee, miner signalling, and what the other chains got wrong + +6 October 2026, evening UK. Lane 4 of the Horizon programme. Worktree `/Users/joshm/Projects/igneum-wt-horizon` (branch `horizon`). Every model is in `sim/horizon/economy-and-utility/` with a README line per script; every dollar figure names its inputs and its label. Nothing here is a price prediction, an offer to sell anything, or a change to any consensus parameter. + +**Read:** `docs/spec/05-fees-and-economics.md` (whole, 5.10 and 5.11 included), `02-consensus.md` 2.5, `07-execution.md` (7.2 to 7.8); `docs/design/payment-routes.md`, `developer-adoption.md` (2a to 2c), `execution-layer.md` (4.3 to 6), `miner-dev-fee.md`; `docs/plans/funding.md` 1 to 5; `docs/analysis/security-budget.md`, `economy-2026-10-04.md`, `base-fee-floor.md`, `prover-floor.md`, `prover-tiers-real-cards.md`; `sim/economy/` (README, sim.py, security_budget.py, results.md, levers.md); `docs/commercial/prover-customer-brief.md`; `docs/fud-ledger.md` E1 to E8 (E9 to E18 are cross-referenced from the spec and the status updates, the file carries E1 to E8 as sections), P6, P8, P9, P10, P14, P22, D1 to D6, C9, C10, G8, L6, L7; `site/litepaper.html` Building, Economics, Governance; `docs/bench-log.md` lines 1226 (the dev fee measured), 1910 (proving v1), 2349 (aggregation cost), 2582 (rental cost of hash); `docs/plans/counter-asic-3-node.md` section 6 (the P2 rule) and `counter-asic-3-status.md` P2; `docs/analysis/horizon/frontier.md` section 0 (the ranking) and 3.1, 3.2, 3.5, 3.6, 3.11 to 3.13; lane 3's `sim/horizon/consensus-security/cost_results.md` and `signalling_results.md`; `vendor/rusty-kaspa` (main checkout) `consensus/core/src/config/params.rs` and `consensus/src/processes/coinbase.rs`. `block-rate-devnet2.md` was still a template (RUN_A, RUN_B empty) at 21:50 UK; nothing here depends on it. + +--- + +## 1. Method + +| Question | What was run | Where | +|---|---|---| +| Task 1, utility beyond gas | Arithmetic: the measured eleven-card table turned into a cost per v1 shard and per billion cycles (alone, beside the miner, rented), against the published prices; five demand curves on a low/base/high grid at three IGN prices | `utility.py`, output `utility_out.md` | +| Task 2, the 80/20 and the burn under stress | `sim/economy/sim.py` copied and changed in six named places (the measured cards, the renter farm, the 25-s window and 120-s timeout, a FIFO backlog with the 600-s record window, burn per day, the new scenarios), 8 scenarios x 3 seeds, 30 days, plus two sensitivity runs; under the main checkout's run lock at nice 19 on the M5 Max, about 18 s a run | `stress.py`, outputs `results/stress_main.md`, `stress_busy.md`, `stress_elecfarm.md` | +| Task 3, ten years without a treasury | Arithmetic: `sim/economy/security_budget.py` extended with the lane's fee grid, the pool line, the sustained hash at the measured card economics and the rented 34% weight attack at USD 281 per GH/s-day | `security_budget_10y.py` | +| Task 4, the dev fee | Arithmetic from `miner-dev-fee.md` and the bench-log measurement | `devfee.py` | +| Task 5, signalling | Arithmetic on the three thresholds; lane 3's `signalling.py` covers the 95-percent rule and is cross-referenced, not re-run | `signal_game.py` | +| Task 6, the other chains | Reading: `vendor/rusty-kaspa` for Kaspa; everything else named and marked approximate where no clone exists | this file, section 5.6 | + +No node harness was started and no measurement was taken: the fleet, the PCs and the devnet were on the class v4 rehearsal and the Devnet 2 block-rate runs. Every hardware number is the fleet's from 6 October (`prover-tiers-real-cards.md`) or the bench-log's. + +--- + +## 2. Evidence + +### 2.1 Measured inputs + +| Input | Value | Source | +|---|---|---| +| v1 shard | 4,717,439 cycles; the adopted `S_p` is 30,000 pgas = 30 M cycles, so the fixture is 16% of a full shard | `prover-tiers-real-cards.md`; spec 5.11 | +| Shard alone, compressed, patched server 2^26 | 3060 14.4 s, 3080 7.1, 3090 14.9, 4060 Ti 16 GB 11.6, 4060 Ti 8 GB 9.6, 4060 18.4, 4070 12.1, 4090 6.3, 5070 4.8, 5090 6.3, A5000 8.3 | `prover-tiers-real-cards.md` table | +| Shard beside the running miner (compressed) | 3060 37.5 s, 3080 25.6, 3090 19.9, 4060 Ti 16 GB 34.6, 4070 27.3, 4090 26.1, 5070 37.2, 5090 10.7, A5000 34.6; the 8 GB cards core-only 22.1 to 26.3 | same | +| Hash and watts mining (rented boxes) | 3060 23.78 MH/s at 103.7 W ... 5090 98.48 at 258.2 (the table) | same; the 4060's 0.0 W reading replaced by its 115 W rating, approximate | +| The miner's loss while its card proves | 5090: 124.72 to 119.74 MH/s, 4.0%, on empty shards; 8 GB cards 17.1 to 16.0 MH/s, about 6%, on v1 shards | bench-log, proving v1 step 1; `prover-tiers-real-cards.md` 8 GB row | +| Watts mining and proving at once | 5090: 328.6 W max against 258 W mining (about 70 W more) | bench-log proving v1 step 1; the fleet row | +| Rental price of hash | USD 0.0117 per MH/s-hour (1,748 MH/s for USD 20.44 an hour, 38 pods); USD 11.7 per GH/s-hour, USD 281 per GH/s-day; the market gave 0 of 20 pods asked at the TH/s scale | bench-log line 2582 | +| Aggregation per block on a mining 5090 | 9.6 to 9.7 s (2.1 s with the card to itself) | bench-log line 2349 | +| Dev fee on a test network | 9 fee blocks in 785 (1.15%; the template rule is exact at 1 in 100) | bench-log line 1226 | +| Proof record sizes | 274 bytes per shard record, 586 per segment record, 1,272,897 bytes per compressed proof | spec 7.7, 7.8; bench-log proving v1 | + +### 2.2 Published prices (all approximate or secondary; none cloned) + +| Supplier | USD per billion cycles | Label | +|---|---|---| +| Boundless (RISC Zero), Base | about 0.21 median lock price, trailing day 4 Oct 2026 | `developer-adoption.md` 2b, secondary summary; approximate | +| Succinct Prover Network | 0.046 base plus up to 0.46 per billion PGU in the quickstart's EXAMPLE request at USD 0.23 per PROVE | `developer-adoption.md` 2b; example parameters, not a market price | +| RISC Zero Bonsai | never published a per-cycle list price; paid proving moved to Boundless in 2025 | not cloned, approximate | +| Ethereum L1 block at the ethproofs cluster cost, Sep 2026 | sub-half-cent a block; at 0.2 to 1.3 B cycles a block (14 to 44 SP1 cycles per gas, measured on Igneum) about 0.004 to 0.025 | `frontier.md` 2.6 (secondary); `base-fee-floor.md` | +| A Taiko-class rollup per batch | taiko-mono not cloned; Taiko Alethia proves batches through its own prover market with SGX and ZK tiers (SP1 and RISC0 accepted); the ZK proof's cost per batch is of the order of the ethproofs figure times the batch's cycles: cents to tens of cents | approximate | + +### 2.3 What the earlier models said that this lane re-tests + +| Claim | Source | What changed tonight | +|---|---|---| +| Hybrid loses the whole hash for the proof's duration plus a 5-s swap | `sim/economy/sim.py` TPROVE + 2 x swap | Measured: the miner loses 4 to 6% while the card proves; the lottery wins the card's arbitration and the proof is 3 to 4x slower instead | +| A 3060 proves a shard in 20 s (target) | ledger P1 | Measured: 14.4 s alone, 37.5 s beside the miner, on the 4.7 M-cycle fixture; a full 30 M-cycle shard is unmeasured on it (linear scaling would say 92 s alone, approximate) | +| 10-s window, 300-s claim timeout | spec 7.2 as designed | 25 s and 120 s decided 6 Oct 2026 (ledger P9) | +| The farm pays electricity at USD 0.05 | `sim/economy/sim.py` | The farm is a renter at the measured USD 0.0117 per MH/s-hour | + +--- + +## 3. Model + +### 3.1 The supply side of proving + +For a card with hash `h` (MH/s), network hash `N` (MH/s), shard time `t` (s), watts `w` and price `P` (USD per IGN): + +``` +cost_alone = w t / 3.6e6 x 0.10 electricity + + (h / N) x 0.8 x 31.688 x t x P the subsidy the card forgoes while it proves +cost_beside = 70 t / 3.6e6 x 0.10 + (h / N) x 0.8 x 31.688 x t x 0.04 x P (4% measured on the 5090, approximate elsewhere) +cost_rented = h x 0.0117 / 3600 x t the renter's cost; no subsidy, no electricity +per billion cycles: x 1e9 / 4,717,439 +``` + +### 3.2 Demand curves at the adopted floors (spec 5.11; design 6 for jobs) + +``` +transfer = 21,000 x 100 gwei + 300 x 10,000 gwei = 0.0051 IGN, burned; tip 21,000 x 1 gwei, 80% miners+provers, 20% burned (no registered frame) +batch post 100 KB = (21,000 + 16 x 100,000) x 100 gwei + 300 x 10,000 gwei = 0.1651 IGN, burned +job of C cycles = C / 1000 x 10,000 gwei x 1.5 = 15 IGN per billion cycles; 90% provers, 10% burned once IGN-settled +payments cap = B_p / 300 = 400 transfers a block = 34.6 M a day; EIP-1559 target half of that, 17.3 M a day +records = 274 x shards + 586 / 8 bytes a block in the coinbase; 1,272,897 bytes per proof on p2p +``` + +### 3.3 Sustainability + +``` +sustained hash (GH/s) = miners' USD per day / (electricity + capital per GH/s-day) + electricity = 258.2 W / 98.48 MH/s x 24 / 1000 x USD 0.10 = USD 6.29 per GH/s-day (measured card, the brief's price) + capital = USD 2,000 / 98.48 MH/s / 1,095.75 days = USD 18.53 per GH/s-day (approximate) + total USD 24.8 per GH/s-day; the rental price is USD 281, 11.3x +34% weight attack = rent 1.04 N for 20 days (lane 3's rule, spec 3 headline) = 1.04 x N x 281 x 20; the attacker earns 51% of the producer subsidy meanwhile +``` + +### 3.4 The stress simulator + +`sim/economy/sim.py` with: eleven card classes (`HASH`, `PMINE`, `TPROVE` alone, `TBESIDE`, `CANHYB` from the measured table; `MIX` an approximate installed-base shape), hybrid capacity `cards x T / TBESIDE` and hybrid hash `1 - 0.04 x duty`, operator 0 a renter (`cost = cards x MH/s x 0.0117 x hours`), window 25 s, timeout 120 s, a FIFO of open shards with a 600-s expiry (expired credit stranded), burn per day = 10% of IGN-settled external jobs plus `blocks x content_shards x 0.51 IGN` (paid content 0.03 shards a block at launch traffic), one proving shard a block (measured on the devnet). The thresholds T1 to T5 are the 4 October definitions (hash under 50% of the pre-event mean for an hour; backlog over 600 s; a growing backlog; a day under 90% within 60 s; a 10-point proving-share swing). + +--- + +## 4. Results, task by task + +### 4.1 Task 1: what IGN is for beyond gas + +#### (a) Proving as a sellable service + +| Card | Alone, 1 GH/s | Alone, 100 GH/s | Alone, 1 TH/s | Beside its miner, 100 GH/s | Rented (no subsidy) | Electricity only | +|---|---|---|---|---|---|---| +| 3060 12 GB | 36.81 | 0.377 | 0.046 | 0.054 | 0.236 | 0.0088 | +| 4070 12 GB | 32.50 | 0.331 | 0.039 | 0.041 | 0.208 | 0.0065 | +| 4060 Ti 16 GB | 21.92 | 0.224 | 0.027 | 0.040 | 0.140 | 0.0049 | +| 4090 24 GB | 35.38 | 0.361 | 0.042 | 0.069 | 0.227 | 0.0068 | +| 5090 32 GB | 66.69 | 0.676 | 0.076 | 0.050 | 0.427 | 0.0096 | +| Boundless median (approximate) | 0.21 | 0.21 | 0.21 | 0.21 | 0.21 | | +| ethproofs L1 cluster (approximate) | 0.004 to 0.025 | | | | | | + +USD per billion cycles at USD 0.02 per IGN (`utility_out.md` 1.3; the IGN price moves only the opportunity term). + +What it says. Electricity is under a cent per billion cycles on every card; "marginal cost close to power" (ledger C10's wording) is true of the electricity and false of the price, because the price a prover must charge is the subsidy it forgoes, and that scales as 1 / network hash. At today's devnet scale (1.16 GH/s) a prover that stops mining to prove must charge 100 to 300x Boundless's median. At 100 GH/s a card proving alone is at 1 to 3x Boundless; a hybrid card beside its miner is at 0.2 to 0.4x (USD 0.04 to 0.08), which is the only row where Igneum undercuts the market, and it rests on the 4% figure measured on one card. The renter's row, USD 0.13 to 0.43, is the floor below which no rented prover ever sells. The floor-priced job (15 IGN per billion cycles) is USD 0.075, 0.30 and 1.50 at the three prices: a third of Boundless at 0.005, 1.4x at 0.02, 7x at 0.10. The floor is denominated in IGN and the market in dollars, and the floor moves by a two-week 60% vote (spec 5.11): it cannot follow a price. Frontier 3.11 (rank 15) already shows the market is three to four orders under year-1 emission; this lane adds that at the adopted floor Igneum overprices the market at any IGN price above about USD 0.014. + +| Tier | Consequence | +|---|---| +| Home 8 GB | proves alone only (compressed does not fit beside the miner); its price is the alone row: competitive only above about 300 GH/s of network hash | +| Home 12 GB | mines and proves on headless Linux (37.5 s beside on the 3060, 27.3 s on the 4070); competitive beside its miner at 100 GH/s; a full 30 M-cycle shard beside the miner is unmeasured (about 3 min by linear scaling, approximate, outside the 120-s claim timeout) | +| Home 16 GB | the cheapest beside-row (USD 0.040 per billion at 100 GH/s) | +| Home 24 or 32 GB | the 5090 is the cheapest prover per billion beside its miner above 100 GH/s and the dearest alone (its subsidy is the largest) | +| Rig | eight 4090s beside their miners: USD 0.07 per billion at 100 GH/s; 8 x 26.1 s per shard, so a rig delivers a 30 M-cycle shard in about 21 s with all eight on one shard (approximate; SP1 proves one shard per server) | +| Pool user | nothing: the pool's provers carry the proofs | +| Prover | its quote is a function of network hash it does not control; publish the price as `h/N x subsidy x t`, never as a number | +| Holder | job demand buys IGN only after the proof bridge (phase two); at launch customers pay on their own chain, so (a) is zero IGN demand at launch | +| Rollup customer | the customer brief should carry the band above and the condition (network hash) rather than any price | + +#### (b) Rollup settlement, (c) bridges, (d) payments, (e) storage + +Dollars per day to miners and provers (`utility_out.md` 3.3) and burn (3.4), base scenario, USD 0.02 per IGN: + +| Period | External jobs to provers, USD (own chain) | Rollups settling here, IGN to provers | Bridges, IGN to provers | Payment tips, IGN | IGN flows in USD | Burn, IGN | Burn, % of daily emission | +|---|---|---|---|---|---|---|---| +| launch | 450 | 19,440 (1 rollup) | 3,038 (1 bridge) | 1.68 (100 k transfers) | 450 | 5,748 | 0.21% | +| year 2 | 1,800 | 58,320 (3) | 9,112 (3) | 16.8 (1 M) | 1,349 | 23,316 | 0.85% | +| year 5 | 9,000 | 194,400 (10) | 15,188 (5) | 168 (10 M) | 4,195 | 126,716 | 4.6% | +| year 5 high | 90,000 | 972,000 (50) | 30,375 (10) | 290 (17.3 M, the target) | 20,058 | 711,481 | 26% | + +Low scenarios are a tenth to a fifth of these; the full grid at the three prices is in `utility_out.md`. Reading each curve: + +- **Rollups** are the only line that pays provers in IGN at scale: one rollup posting a batch a minute with a 1 B-cycle proof job pays 19,440 IGN a day at the floor, 3.6% of the daily pool. Ten of them in year 5 pay 194,400 IGN a day, 36% of the pool before the second halving and 142% of the pool after it. The condition is the floor price staying under the market's (above). The burn it causes: 10% of the job plus the batch's base fee, 2,398 IGN a day per rollup. +- **Bridges** at 225 updates a day pay 3,038 IGN a day each; a tenth of a rollup. No bridge is official (spec 7.3), so the count is anyone's. +- **Payments** cost USD 0.000026 to 0.00051 a transfer (the three prices). A transfer undercuts a 1 bps rail on any payment above USD 0.26 to 5.10 and a 10 bps rail above USD 0.03 to 0.51; a USD 100 payment pays 0.003 to 0.05 bps. The fee is flat in IGN, so payments give the coin burn and almost no income: 10 M transfers a day burn 51,042 IGN (1.9% of emission) and tip 168 IGN at the 1 gwei default. The proving dimension caps the chain at 34.6 M transfers a day and the fee leaves the floor above 17.3 M; above that the burn is set by willingness to pay and no model here knows it, so the year-5 high row is clamped at the target and says so. +- **Storage.** Records are 347 bytes a block at one shard (1,025 at 3.5): 11 to 32 GB a year, USD 0.17 to 0.50 of disk per node per year (approximate HDD price), paid by whoever runs a node and by nobody else. Proof bytes (1.27 MB each) never enter a block; a node keeps the 600-block pool (about 3 GB at four shards a block) and a light client one proof. An archive of every proof would be 80 to 180 TB a year (USD 1,200 to 2,700 of HDD, approximate): a service someone sells, not a protocol cost. Frontier 3.16 (rank 9) is the research-dataset version of the same bytes. + +The honest total. In the base scenario all five uses together put USD 450 a day to miners and provers at launch and USD 4,200 in year 5 at 0.02, against USD 54,800 of daily emission in year 1 and 13,700 in year 5. Fees are 1.6% of security spend in year 1 and 48% in year 5 (`security_budget_10y_out.md`, base at 0.02), and most of the year-5 share is the external USD line, which is in dollars and does not move with the coin. Burn is 0.2% to 4.6% of daily emission in base scenarios. The Economics section's "part of every payment on Igneum is burned" is true and small: with the ramp's 37 M never minted, burn under 1% of emission a day leaves the cap's approach unchanged to the second decimal for years. + +### 4.2 Task 2: the 80/20 split and the burn under stress + +`results/stress_main.md`: 8 scenarios x 3 seeds, 30 days, the eleven measured cards, the farm (20% of hash, 925 to 1,016 5090s) a renter at USD 0.0117 per MH/s-hour, window 25 s, timeout 120 s, one proving shard a block, USD 0.012 at t = 0. The model's network is about 700 GH/s of potential hash (15,000 cards), so every number below is at that scale; the renter's rent against the subsidy is the N_eq of lane 3 (`cost_results.md` section 3): 94 GH/s at USD 0.012. + +| Metric | a: baseline | p10: price x10 day 7 | pd10: price /10 day 7 | c: no external | x100: external x100 | cartel: top 10% of weight never proves | refuse: nobody proves days 10 to 20 | halving: 15.844 IGN a block | +|---|---|---|---|---|---|---|---|---| +| Hash min / pre-event (seed min) | 0.99 | 0.99 | 0.55 (0.49) | 0.99 | 0.91 | 0.99 | 0.99 | 0.98 | +| Hash day 30 / pre-event | 1.00 | 1.25 | 0.74 | 1.00 | 0.97 | 1.01 | 0.99 | 1.00 | +| T1 hours under 50% | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| Cards off, day 30 | 9% | 0% | 31% | 9% | 8% | 0% | 9% | 9% | +| Cards proving / hybrid, day 30 | 6% / 58% | 6% / 66% | 14% / 44% | 6% / 48% | 10% / 55% | 6% / 57% | 6% / 76% | 4% / 58% | +| Backlog max, shards; T2 age max, s | 0; 0 | 0; 0 | 0; 0 | 0; 0 | 0; 0 | 0; 0 | 766; 565 (capped by the 600-s expiry) | 0; 0 | +| Blocks within 60 s, mean / T4 worst day | 1.00 / 1.00 | 1.00 / 1.00 | 1.00 / 1.00 | 1.00 / 1.00 | 1.00 / 1.00 | 1.00 / 1.00 | 0.67 / 0.00 | 1.00 / 1.00 | +| T5 proving-share swing, points | 1.6 | 0.1 | 2.0 | 0.6 | 2.9 | 2.2 | 0.0 | 4.4 | +| Burn, IGN a day (of which external) | 19,928 (18,606) | 6,758 (5,437) | 146,737 (145,415) | 1,322 (0) | 1,576,947 (1,575,623) | 16,954 (15,632) | 13,366 (12,044) | 17,247 (15,926) | +| Burn, USD a day at the run's mean price | 214 | 578 | 506 | 15 | 15,535 | 218 | 148 | 224 | +| Share of the 20% pool paid / stranded | 1.00 / 0 | 1.00 / 0 | 1.00 / 0 | 1.00 / 0 | 1.00 / 0 | 1.00 / 0 | 0.67 / 0.33 (182,387 IGN a day averaged; 547,570 a day during the refusal) | 1.00 / 0 | +| Renter farm cards on at day 30; margin over rent | 0; -77% | 984; +114% | 0; -77% | 0; -76% | 54 (0 to 162); -6% | 984 (forced on); -79% | 0; -77% | 0; -88% | +| Flags tripped (of 3 seeds) | none | none | none (T1 min 0.49 in one seed, under an hour) | none | none | none | T4 3/3 | none | + +Per card class, USD per card-day (every mode, off included) and the share of shards proven, baseline: 3060 1.30 (0%), 3080 3.09 (5%), 3090 2.69 (11%), 4060 Ti 16 GB 1.63 (4%), 4060 Ti 8 GB 2.03 (16%), 4060 0.85 (1%), 4070 1.96 (12%), 4090 3.86 (11%), 5070 3.36 (12%), 5090 3.95 (24%), A5000 3.30 (4%). The full tables are in `results/stress_main.md`. + +What holds and what breaks: + +1. **The 80/20 holds under every price and demand shock; the price is what moves hash.** T1 never trips. The /10 price shock is the closest: hash troughs at 55% of pre-event (49% in one seed for under an hour), 31% of cards go off (the 3060 and 4060 classes at median electricity and above), and the chain is at the T1 line with no backlog and every block proven inside 60 s. A x10 shock brings the renter farm on (margin +114%) and hash ends 25% up: rented hash arrives exactly when the subsidy per GH/s-day clears USD 281, which is lane 3's N_eq. The first halving at a flat price changes nothing at this price level (the same 9% off), because the cards that remain are above break-even at 0.013; a halving is a /2 price shock and the /10 row says where /2 would land between the two. +2. **External demand x100 is the burn story and the renter story.** USD 200,000 a day of jobs at 10% burn is 1.58 M IGN a day burned, 58% of daily emission, at the run's price of about USD 0.01; and it brings 0 to 162 rented 5090s on at a -6% margin. Hash troughs at 91%: cards leave the lottery for jobs (the 4 October finding, scenario b), and the renter's cards arriving for jobs do not hash. The burn in that row is a transfer from customers to holders of 15,500 dollars a day; it is the only row where burn is material, and it needs IGN settlement, which is phase two. +3. **A cartel of the top 10% of weight that never proves costs the chain nothing.** In this population the top 10% of weight is one operator, the 20% farm, so the row is a 20% cartel: with 8 draws by weight the chance that every assignee is the cartel's is 0.2^8, under three in a million, so almost every shard still finds an assignee and the rest go open after 25 s; every block is proven inside 60 s, the backlog is zero, and the cartel loses USD 6.77 per card-day (forced on, as a renter, to hold its weight). Sortition with 8 draws is why: the 4 October result (scenario e, 30%) stands with the measured cards. +4. **A refusal by every prover is the one scenario that breaks a threshold, and what breaks is the pool, not the chain.** For ten days no block is proven (T4 0 on every refusal day), execution and finality do not wait (spec 5.3, ledger P9), and the backlog never passes 600 s because the record window expires the shards: 547,570 IGN a day of pool credit is stranded in the escrow, 5.5 M IGN over the ten days, and no rule returns it. When provers come back the queue is at most 600 s deep and clears in minutes; 76% of cards end in hybrid. The refusal's whole cost is the refusers' own income plus a silent supply reduction nobody voted for (proposal 2). +5. **The window excludes the slow hybrids.** At 25 s a 3060 beside its miner (37.5 s on the small fixture), a 4060 Ti 16 GB (34.6), a 5070 (37.2) and an A5000 (34.6) cannot land an assignment and win only open races or prove alone; the 3060 class proves 0% of shards in every scenario, the 4060 1%. The 4060 Ti 8 GB proves 16% by proving alone at 9.6 s. The 4 October proposal (window = the fleet's 90th-percentile shard time plus a swap) would set it near 38 s on this fixture; on a full 30 M-cycle shard the number is unmeasured (proposal 8). +6. **Burn at launch traffic is USD 15 to 220 a day**, 0.05% to 0.7% of emission; the base fee part is 1,322 IGN a day at 0.03 content shards a block. Everything above that is the external 10%, which does not exist until jobs settle in IGN. + +Sensitivities (`results/stress_busy.md`, `stress_elecfarm.md`, 2 seeds each). At 3 proving shards a block (the 4 October busy value, 3x the load) nothing changes in a, cartel or x100: backlog 0, every block inside 60 s, hash min 0.95 to 1.00; the refusal strands the same 33% of the pool with a queue of 2,265 shards at its deepest, and the renter farm comes on in x100 at 213 cards (181 to 244). With the farm on electricity at USD 0.05 instead of rent (the 4 October assumption) the baseline has 0% of cards off (the farm's 968 cards stay on) and the /10 shock takes 25% of cards off with hash troughing at 63% of pre-event and ending at 77%: the rent is what decides whether the 20% farm is on at all, and with it 20 points of hash at every price; the `renter farm margin` column of that file is undefined at zero rent and should be read as blank. + +| Tier | Consequence of the stress runs | +|---|---| +| Home 8 GB | proves alone and wins open races (16% of shards on the 4060 Ti 8 GB); the first class off in a /10 shock on expensive power | +| Home 12 GB | the 3060 proves 0% at the 25-s window; the 4070 12% (27.3 s beside, loses the window, wins open races alone); first off in a price fall | +| Home 16 GB | 4% of shards; stays on in every row but pd10 | +| Home 24 or 32 GB | 11 to 24% of shards; hybrid is the dominant mode (58% of all cards); the last class off | +| Rig | as the 24 GB card per card; a rented rig is off below N_eq and on above it (p10 row) | +| Pool user | the pool's provers' share; unchanged by any row | +| Prover | income is 20% of emission in every row but refuse, where the refusers strand it; the x100 row is the one where jobs pay more than the pool | +| Holder | burn is 0.05 to 0.7% of emission a day at launch; 58% in the x100 row, phase two only | +| Rollup customer | every job delivered in every row but refuse (67%) | +| Node operator | the backlog never passes the 600-s record window because the window expires it | + +### 4.3 Task 3: no-treasury sustainability over ten years + +`security_budget_10y_out.md`. The brief's formula gives a sustained hash proportional to the miners' dollars and an attack cost proportional to that hash, so the ratio is a constant: a 20-day 34% weight attack rents 1.04 N at USD 281 per GH/s-day against an honest fleet that costs USD 24.8 per GH/s-day, 11.8x the honest fleet's 20-day cost, minus the 51% of subsidy the attacker earns back. The subsidy never falls under the attack cost in ratio terms; the halvings shrink both until the absolute number is small. The honest statement is the absolute net cost by year: + +| Year | Net cost of the 20-day veto, USD, at 0.005 | at 0.02 | at 0.10 | Sustained hash at 0.02, GH/s | Fees as % of total security spend, base at 0.02 | +|---|---|---|---|---|---| +| 1 | 2,375,000 | 9,501,000 | 47,506,000 | 1,699 | 1.6% | +| 3 | 1,233,000 | 4,933,000 | 24,666,000 | 882 | 18.6% | +| 5 | 617,000 | 2,467,000 | 12,334,000 | 441 | 48.3% | +| 7 | 308,000 | 1,234,000 | 6,168,000 | 221 | 65.1% | +| 9 | 154,000 | 617,000 | 3,085,000 | 110 | 78.9% | + +The veto's net cost drops under USD 1 M in year 5 at 0.005, year 9 at 0.02, and not within ten years at 0.10; under USD 100 k only after year 10 at 0.005. The rental market's supply, not its price, is the other bound (0 of 20 pods at the TH/s scale on 6 October), and it is not modelled. What the fees change: in the base scenario the proving-pool and job lines reach provers, not miners, and the brief's security line is miners' hash; of the 48% fee share in year 5, under 1% reaches miners (tips at 1 gwei). The chain's security budget after year 5 is the subsidy to miners, and nothing else in the design pays for hash. Frontier 3.1 (rank 7) redirects part of the subsidy to the pool during rental spikes and would lower the miners' line further; this lane's number for it is in 5.1. + +The audits. `funding.md` prices the first cryptanalysis at USD 80,000 to 160,000 and nothing prices the second, which a class or era change in year 3 would need. What the entity's own lines earn (every price an input): + +| Year | Price | Dev fee, 50% of hash on Ember | Entity's provers at 5% of the pool | Second cryptanalysis (USD 160 k) as % of the dev fee | +|---|---|---|---|---| +| 3 | 0.005 | 10,000 | 25,000 | 1,600% | +| 3 | 0.02 | 40,000 | 100,000 | 400% | +| 3 | 0.10 | 200,000 | 500,000 | 80% | + +The dev-fee row here uses 1% of the producer share (80% of emission), because the fee template moves only the `IGNA` payout and the pool is paid per record; `funding.md` section 4 took 1% of all rewards and overstates the ceiling by a quarter (48,000, 193,000 and 963,000 should read 38,520, 154,080 and 770,400). The honest options for the second audit, ranked: + +| Rank | Option | What it pays in year 3 at 0.02 | Why this rank | +|---|---|---|---| +| 1 | The entity's own provers (5% of the pool and a share of jobs) | USD 100,000 a year at 5% of the pool, more with jobs | Open-market income the design already names (spec 5.5); scales with the chain, no rule, no switch; the cost is running cards | +| 2 | The Ember dev fee | USD 40,000 a year at 50% of hash on Ember | Exists and is measured; falls with every halving and with every miner who flips the switch; alone it funds a review every four years at 0.02 | +| 3 | A user-paid review market: customers (rollups) co-fund the audit that protects their settlement, as a condition of their integration | unknown; a Taiko-class customer's whole annual proving spend is of the order of USD 100 k (frontier 3.11) | Honest and voluntary; the customer has the motive; it depends on having a customer | +| 4 | Founders' mined coins (the litepaper's own answer for grants) | depends on hash share | Visible addresses; finite; the ledger's E2 and E8 live here | +| 5 | A burn-funded bounty or review escrow | the base-fee burn at launch traffic is 51 to 20,578 IGN a day: USD 1 to 412 at 0.02 | Frontier 3.6 (rank 11, "watch") and its Monero attack: a burn redirect is a payee by rule, which is the switch spec 5.5 removed. The protocol cannot have it because it has no treasury, and that is the contradiction stated plainly: the no-treasury rule means the SECOND audit is paid by whoever earns in the open or it is not paid, and `funding.md` should say so in a row of its own | + +### 4.4 Task 4: the dev fee + +What it is (`miner-dev-fee.md`): one block template in 100, chosen by an exact counter (templates 99, 199, ...), is requested with the project's payout address in the coinbase extra data; the vote key and the UTXO address stay the user's, so a fee block still votes for the user and only the execution-layer payout moves. Default on; `--dev-fee 0`, the app's Settings switch or HiveOS `DEV_FEE=0` turns it off; the start line prints the state; `igneum-miner payouts` tags the dev address on the chain. Measured: 9 fee blocks in 785 on a test network, the miners' counters and both nodes agreeing (bench-log line 1226). + +What it pays (`devfee_out.md`): 1% of the producer share of emission times the share of hash on Ember with the fee on. + +| Year | Price | 20% keep it on | 50% | 100% | Home 4070 at 100 GH/s network, a month | Rig 8x 4090, a month | +|---|---|---|---|---|---|---| +| 1 | 0.005 | 7,704 | 19,260 | 38,520 | | | +| 1 | 0.02 | 30,816 | 77,040 | 154,080 | USD 3.33 (6.6 blocks) | USD 55.74 (110 blocks) | +| 1 | 0.10 | 154,080 | 385,200 | 770,400 | | | +| 5 | 0.02 | 8,000 | 20,000 | 40,000 | | | + +What share would turn it off. Precedent (approximate, from memory): T-Rex 1%, lolMiner 0.7 to 1.5%, PhoenixMiner 0.65%, TeamRedMiner 0.75 to 2.5% and NBMiner 1 to 2% were not switchable, and together they held the large majority of Ethereum's GPU hash over the fee-free ethminer because they were faster; NiceHash is a marketplace that takes about 2% of the buyer's payment, not a dev fee; nobody measured an opt-out share because none offered one. Igneum's switch is one flag and the miner is open source, so the rational solo miner with any time at all turns it off; the pool operator decides for its members; the one-click app user keeps the default. A working estimate for planning: 20 to 50% of hash keeps it on, which is the devfee table's first two columns and USD 7,700 to 77,000 a year in year 1 at 0.005 to 0.02. This is a planning input, not a measurement, and the first month of the public testnet measures it from the chain (`payouts`). + +Is "optional" honest? Ledger E18's charge is "a protocol fee with better PR". Three facts answer it. It is not in the protocol: the chain pays whatever `IGNA` address the template names, and a block with the dev address is indistinguishable in consensus from a block paying any other address. It is switchable in one flag and the chain shows who paid (`payouts`). It is default-on, and defaults are what most users run, so "optional" describes the mechanism and "default-on, switchable" describes the behaviour. The public line should be the second: "1 block in 100 pays the project unless you turn it off". Two things to add to E18: the ceiling correction above, and the fact that the fee buys the project a visible address holding 1% of mined coins, which is the E5 critic's point restated as a holder consequence. + +| Tier | Consequence | +|---|---| +| Home 8 to 32 GB on Ember | 1% of blocks unless switched off; USD 2.34 to 13.13 a month at 0.02 and 100 GH/s network | +| Rig | the same per card; a rig operator on HiveOS sets `DEV_FEE=0` once | +| Pool user | the pool's choice: a pool on its own template software pays 0%; a pool on Ember pays 1% of its templates and passes it on or not | +| Prover | untouched: the pool share is paid per record, never through a template | +| Holder | one address accumulates up to 1% of producer emission; the project's incentive to keep Ember the fastest client is the fee | +| Rollup customer | nothing | + +### 4.5 Task 5: miner-signalled parameters + +What genesis leaves to miners (spec 5.5, 5.9, 5.11): the base-fee floors `f_e` and `f_p`, the proving budget `B_p` (and with it `S_p`), set by a proposal at 60% of blue blocks over 1,209,600 DAA s (two weeks), the BIP 9 model. Upgrades (new code) need 90% (spec 5.7, window open, O-5.3). The P2 rule for a PoW class change needs 95% of blue blocks over a one-day window ending at each epoch's seed block, monotone, with a floor height as the backstop (`counter-asic-3-node.md` section 6: `CLASS_SIGNAL_THRESHOLD_BPS` 9,500, window 86,400 DAA, the fast-time gate green on three cases and its failed case). The documents disagree about the number: spec 5.7, CLAUDE.md's design paragraph and the litepaper's Governance section say 90% for upgrades; the P2 design and the Horizon preamble say 95% for class changes; the litepaper's Mining section says "a 90% miner signal turns one on". One sentence should carry all three (60 parameter, 90 upgrade, 95 class with a floor) or the three should become two. + +The game (`signal_game_out.md`; lane 3's `signalling_results.md` for the 95% rule): + +| Rule | Who can block | A 30% pool | Renter's cost to force at 100 GH/s | What ends a block | +|---|---|---|---|---| +| 60% over 14 days | over 40% of blue blocks | cannot block alone; needs 11 more points | USD 590,000 (1.5 N for 14 days) | the proposal fails; re-register | +| 90% over 14 days | over 10% | blocks it | USD 3.5 M (9 N) | the proposal fails; re-register | +| 95% over 1 day, floor | over 5% | blocks it | USD 534,000 (19 N for a day) | the floor height | + +A 6% holdout costs USD 18 a day at 1 GH/s and USD 1,800 at 100 GH/s on top of the subsidy it earns like anyone, so near zero (lane 3 section 2); it buys delay to the floor and nothing else. A 30% pool holds a permanent veto over upgrades at 90% and over class changes until the floor at 95%; the devnet's top three vote keys held 34.5% of blocks on 4 October (litepaper, Governance). Signal then defect is bounded by what is signalled: a PoW class defector loses its own blocks (its PoW fails, `check_header_version` then the PoW check); a consensus-rule defector forks itself and whoever trusts it; an execution-parameter defector produces VALID blocks with a different state (blocks carry no state claim, design 1.1), which is a silent state fork for that node unless the parameter is in the consensus digest that the handshake refuses (G12, X18): `Params.fees` is in the digest (spec 5.11), so today it is isolated rather than split, and any future miner-signalled execution parameter must enter the digest the same day or the defector is a quiet fork. + +What Bitcoin and Kaspa did. BIP 9: version bits, a 95% threshold of 2,016-block retarget periods, states DEFINED, STARTED, LOCKED_IN, ACTIVE, FAILED, a timeout; BIP 8 added a lock-in-on-timeout flag so a flag day ends a holdout (bips repository, bip-0009.mediawiki and bip-0008.mediawiki; not cloned, approximate). Kaspa's Crescendo (1 to 10 BPS) was a fixed DAA score, not a signal: `crescendo_activation: ForkActivation::new(110_165_000)` for mainnet and `88_657_000` for testnet, with `ForkActivation::is_active(daa)` as `current_daa_score >= self.0` (`vendor/rusty-kaspa/consensus/core/src/config/params.rs` lines 28 to 60, 648, 704, main checkout), and the coinbase keeps the activation score for ever to compute the subsidy month across it (`consensus/src/processes/coinbase.rs` lines 40 to 43, 238 to 253); `docs/crescendo-guide.md` tells miners to upgrade before the activation. The P2 rule is BIP 8 in shape: a signal path plus a flag day. Igneum's 6 October incident (DAA 198,000 crossed by a half-updated fleet) is the flag-day hazard, and P2's floor keeps it. + +What SHOULD be miner-signalled and is not, with the risk of each: + +| Parameter | Today | Should be | Risk if signalled | Risk if not | +|---|---|---|---|---| +| The block rate step (1 to 4 to 10 BPS) | a planned fork with its own test campaign, "as Kaspa's Crescendo" (spec 2.1) | a 90% upgrade signal with a floor, like P2: it is a consensus change crossed by a whole fleet | a 10% pool vetoes the step; a renter forces it a day early for USD 5.3 M at 1 TH/s | a fixed height on a half-updated fleet: the 229-block reorg of 6 October at mainnet scale | +| The dataset growth step | automatic, genesis schedule (spec 1, 2 GiB doubling at years 4, 12, 28) | NOT signalled, by design: it is an anti-ASIC escalator and a chip-holding cartel would vote growth down. Allow a 60% signal to ACCELERATE only (monotone), never to delay | a 40% holdout blocks acceleration: no worse than today | none: the schedule runs | +| The 80/20 lottery/proving split | fixed (spec 2.5) | a 60% parameter inside a hard band [10%, 30%] | 80% of the voters are the lottery; without the band they vote the pool to 0 and the provers go; with the band the worst case is 10% | the simulator says 20% is not load-bearing at launch traffic and 30% helps at 100 shards a block (economy-2026-10-04 5.3); fixed means a 90% upgrade to move it | +| The base-fee floors and `B_p` | 60% over 14 days (spec 5.11) | a bounded per-block dial, Ethereum's gas-limit mechanism (frontier 3.5, rank 8): the dollar market moves faster than two weeks (4.1) | a 51% majority walks the dial to the bound in days; the bound and a cost curve are the defence | the job price is pinned in IGN while the market is in dollars; at 0.10 the floor is 7x Boundless and a two-week vote cannot follow it | +| The job premium 1.5 and the external claim timeout 120 s (O-5.6) | design 6 constants | the same bounded dial | as above | a constant calibrated once on the phase 4 devnet | +| The exclusive window 25 s | a consensus constant (P9) | a function of the fleet's measured shard-time distribution, published per era (economy-2026-10-04 proposal 1; frontier I3) | none: it reads a measurement | a 12 GB fleet whose shard time drifts past the window loses every assignment to the open race (the 4 October finding at 10 s) | + +### 4.6 Task 6: what Kaspa, Monero, Ethereum and the zk rollups did and got wrong + +| Area | Chain | What it did | Where | What went wrong, or what it costs | Igneum's rule | Avoids or repeats | +|---|---|---|---|---|---|---| +| Emission | Kaspa | A pre-deflationary phase at 500 KAS a block (`pre_deflationary_phase_base_subsidy: 50000000000`, `deflationary_phase_daa_score: 15778800 - 259200`), then the chromatic schedule: 426 monthly steps, each month's subsidy the previous times 2^(-1/12), from 440 KAS a block (`SUBSIDY_BY_MONTH_TABLE[0] = 44000000000`), halving every twelve months smoothly | `vendor/rusty-kaspa/consensus/core/src/config/params.rs` 631 to 638, 687 to 694; `consensus/src/processes/coinbase.rs` 22 to 25, 222 to 253, 280 | Steep and smooth: no halving-day cliff, but the subsidy fell 50% a year and the chain leaned on price appreciation it could not promise; the table is divided by BPS at Crescendo so the per-second rate is unchanged | 1 B a year halving every two years, in DAA seconds; a 30-day ramp; no tail (spec 2.5, 5.10) | Avoids the yearly rate (slower), repeats the cliff (a step, not a glide); E6 concedes it | +| Emission | Monero | A tail emission of 0.6 XMR a block for ever after the main curve | monero repository `src/cryptonote_basic/cryptonote_basic_impl.cpp`, `get_block_reward` (not cloned, approximate) | Security paid for ever at about 0.9% a year inflation falling toward zero; the cost is a soft supply cap critics name | No tail; a review trigger that puts a tail to a 90% vote if proving revenue is under a fifth of the subsidy after year 5 (spec 5.10.3) | Repeats Bitcoin's bet, keeps Monero's door ajar by vote | +| Emission and burn | Ethereum | EIP-1559: the base fee burned, the tip to the proposer; issuance by stake since the Merge, about 0.5 to 1% a year gross, net near zero when burn is high | ethereum/EIPs `EIPS/eip-1559.md`; ethereum/execution-specs `src/ethereum/london/fork.py` (`calculate_base_fee_per_gas`); not cloned, approximate | The burn removes the proposer's incentive to stuff blocks, at the cost that usage pays security nothing; proposers' income moved to tips and MEV | Both base fees burned, tip 80/20 to miners-provers and apps; the same trade-off, stated (security-budget.md section 5) | Repeats on purpose (E3 is the reason); the EIP-1559 step is copied (`next_base_fee`, denominator 8) | +| Fee market | Ethereum | A base fee that cannot fall below 7 wei in practice and has no floor; the gas limit voted per block by proposers within 1/1,024 | execution-specs `fork.py`; geth `core/block_validator.go` VerifyGaslimit; approximate | A near-zero base fee when idle makes spam cheap; the gas-limit vote is the one continuous miner dial that worked for a decade | A floor per dimension (spec 5.11) calibrated for spam; `B_p` and the floors by a two-week 60% vote | Avoids the idle-spam gap; does not take the per-block dial (frontier 3.5 asks for it) | +| Proving market | Aleo | Proof-of-succinct-work: provers compete on proofs for coinbase rewards; the fastest prover (GPUs, then FPGAs and ASICs) took the reward share | AleoNet/snarkOS and snarkVM (not cloned, approximate; CLAUDE.md "the Aleo lesson", ledger C9) | The proving reward centralised to the fastest hardware; small provers earned nothing | The lottery and the proving are separate; shards by sortition on 30-day weight, 8 assignees, 25 s, then open (spec 7.2) | Avoids the race for assigned shards; the open race after the window is where fast cards win beyond their weight (economy-2026-10-04 3.1 item 5) | +| Proving market | Boundless (RISC Zero) | A reverse auction per request; provers post ZKC collateral; PoVW pays ZKC per cycle proven | docs.boundless.network/zkc/mining/overview and provers/performance-optimization (read, not cloned) | A token gate on supply and a stake that scales with work; the median price USD 0.21 per billion (approximate) | No bond for shards; a coin bond only on external jobs (O-5.6); frontier 3.2 (rank 2) replaces even that with work-stake | Avoids the token gate for internal proving; repeats a bond for jobs | +| Proving market | Succinct | A real-time auction settled in PROVE; provers stake PROVE to bid | docs.succinct.xyz/docs/provers (read, not cloned; ledger C10) | The same gate; example prices, no public market price | As above; prices in dollars settled in the token (spec 5.4) | Avoids the gate; repeats "settled in our token" once IGN settlement starts | +| Governance | Monero | Scheduled hard forks (six-monthly, now 9 to 12 monthly), decided by the core team and the community off-chain | getmonero.org and the monero repository's release history (approximate) | Works because the community trusts a small team; the schedule itself is a central clock | No scheduled human releases; automatic escalators at genesis; 90% (or 95%) miner signalling for anything else (spec 5.7) | Avoids the clock; the price is that pools hold the vote (G8) | +| Governance | Kaspa | KIPs discussed off-chain, activated at fixed DAA scores; Crescendo at 110,165,000 after a testnet campaign | `params.rs` 648; `docs/crescendo-guide.md` | A flag day; a node not upgraded forks off; it worked because the community upgraded in time | P2: a signal plus a floor height; Devnet 2 as the staging chain for every cut (CLAUDE.md 6 Oct rules) | Avoids the bare flag day, keeps it as the floor | +| Governance | Ethereum | All Core Devs calls decide; clients ship; activation by timestamp; no on-chain vote | ethereum/pm repository (approximate) | Works by rough consensus among client teams; a single client bug is a chain-wide event (the 2016 Shanghai attacks, the 2020 Geth split, approximate) | One client today; a second independent client is the first priority after launch (litepaper, Governance) | Repeats the single-client risk until the second client exists | +| Rollups | Taiko and the zk rollups | Pay their own prover networks per batch; based sequencing; multi-proof tiers | taiko-mono (approximate) | Proving cost is a line item that falls 3 to 30x a year (frontier 2.6); settlement and proving are bought from two suppliers | Settlement and proving from the same miners in one flow (litepaper, Building) | New; the price condition is 4.1 (a) | + +--- + +## 5. Ranked proposals + +| Rank | Proposal | Evidence | Model | Hours | Consequence per tier | Gate | +|---|---|---|---|---|---|---| +| 1 | Decouple the job price from `f_p`: a job's reserve is the measured proving electricity per pgas (USD 4.4e-9 at 0.15 per kWh, base-fee-floor.md 3) converted at a published settlement rate, and the requester bids above it; the 1.5 premium becomes a bid, not a floor | At the adopted floor a billion-cycle job is 15 IGN = USD 0.075 / 0.30 / 1.50 at the three prices against Boundless's 0.21 (4.1 a); a two-week 60% vote cannot follow a dollar market | `utility.py` section 2 | 16: the reserve rule in `Prover.request` (6), the rate oracle as the review-trigger's published reading (spec 5.10.3 already defines it) (4), spec 5.4 and design 6 text (6) | Prover: sells at the market, not at a vote; Rollup customer: a quote it can compare; Holder: job demand for IGN survives a price rise; Miner: nothing; Pool user: nothing | A simulated job book at the three prices clears within 20% of Boundless's median at every price | +| 2 | Define the stranded pool: an unproven shard's credit rolls forward into the next proven segment's pool instead of sitting in the escrow for ever | The spec is silent on credit nobody claims; a 10-day refusal strands 5.5 M IGN (4.2); the devnet already burns the coinbase 20% output (litepaper, Economics) | `stress.py` refuse scenario, `stranded_share` | 8: the roll-forward in `split_pool_credit` (4), spec 5.3 and 7.8 item 7 text (2), a unit test with a 10-segment gap (2) | Prover: a refusal costs the refusers and pays the returners; Holder: no silent burn; Miner: nothing | On the fast-time harness, 100 unproven segments then 10 proven: the escrow returns to zero within the 10 | +| 3 | Publish the prover's price as a formula, never a number: `price per billion = (h / N) x 0.8 x 31.688 x t x P x 212 / cycles`, with N the live network hash | The same card is 100 to 300x Boundless at 1 GH/s and 0.2 to 0.4x at 100 GH/s (4.1 a); the customer brief says "priced in dollars" with no condition | `utility.py` 1.3 | 3: a paragraph in the customer brief and the litepaper's Proving section, with the table | Rollup customer: no promise it cannot hold the project to; Prover: knows when to sell; everyone else: nothing | The brief and the litepaper carry the condition before any customer conversation | +| 4 | Make the 80/20 split a 60% parameter inside a hard band [10%, 30%], and record the three signalling numbers (60 parameter, 90 upgrade, 95 class with floor) in one sentence in spec 5.7, CLAUDE.md and the litepaper | The split is not load-bearing at launch traffic and 30% buys backlog relief at 100 shards a block (economy-2026-10-04 5.3); the documents carry two upgrade thresholds (4.5) | `stress.py` `--set pool=` | 10: the band in `Params` (4), the proposal kind (3), text (3) | Prover: a floor of 10% of emission by rule; Miner: a vote on its own share, bounded; Holder: nothing | The fast-time harness: a 60% vote moves the pool to 30%; a 100% vote cannot pass 30% or go under 10% | +| 5 | Every miner-signalled execution parameter enters the consensus digest the same release, with a CI check that fails a `Params` field marked signalled and absent from the digest | A signal-then-defect on an execution parameter is a silent state fork unless the handshake refuses the defector; `Params.fees` is in the digest, nothing guarantees the next one is (4.5) | `signal_game.py` section 3 | 6: the check in `tools/ci` (4), a test (2) | Node operator: a defector is isolated, never quietly wrong; everyone else: nothing | The check fails on a planted field and passes on the live set | +| 6 | The block-rate steps become P2-shaped activations (signal plus floor), not fixed heights | Crescendo was a fixed DAA score (`params.rs` 648); the 6 October incident was a fixed height; spec 2.1 still says "a planned fork" (4.5) | lane 3 `cost_results.md` forced-flip row | 4: spec 2.1 text and a line in the Devnet 2 gate | Miner and rig: no flag day crossed while updating; Pool user: nothing | Spec text; the first step's rehearsal on Devnet 2 passes the same gate as the class v4 cut | +| 7 | Correct `funding.md` section 4's dev-fee ceiling (1% of the producer share, not of all rewards) and add a row that names who pays the SECOND cryptanalysis | 48,000 / 193,000 / 963,000 overstate by a quarter (4.4); no row prices a second review (4.3) | `devfee.py`, `security_budget_10y.py` section 3 | 1 | Holder and critic: a number that matches the mechanism | The file's git history | +| 8 | Measure the two numbers every price here rests on: the miner's hash loss while each card proves (4% is one card), and a full 30 M-cycle shard beside the miner on the 12 GB and 16 GB tiers | The hybrid row is the only one that undercuts the market and it rests on one measurement (4.1 a); the 4.7 M fixture is 16% of `S_p` (2.1) | `utility.py` `hybrid_hash_loss` | 6 on the fleet: eleven boxes, two fixtures, `tools/fleet/lib` | Home 12 and 16 GB: whether they are provers at all beside their miner; Rig: the same per card | Eleven rows with both numbers in `prover-tiers-real-cards.md` | + +**1. Decouple the job price from `f_p`.** `f_p`'s floor exists to price spam above the electricity it imposes (base-fee-floor.md section 3: 230x the electricity at USD 0.10 per IGN). Design 6 then prices every external job at `maxPgas x f_p x 1.5`, so the same floor that is 230x electricity for spam is the job market's minimum: 15 IGN per billion cycles, which is a third of Boundless at USD 0.005 and 7x at 0.10. A rollup compares in dollars every week; a 60% vote takes two weeks and a quorum. Lane 7 (frontier 3.5, rank 8) proposes the continuous dial for the floors themselves and it would help; this proposal is narrower and independent of it: the job reserve is the electricity, published as a rate the review trigger of spec 5.10.3 already needs ("converted at the window's settlement rate and published with the reading"), and the price above the reserve is the requester's bid against the sortition's assignees. Cost 16 hours. Gate: a simulated job book clearing within 20% of Boundless at all three prices. Per tier: the prover sells at a market price; the rollup customer gets a comparable quote; the holder keeps job demand for IGN through a price rise (at 0.10 and the floor, every rollup leaves); miners, pools and home cards see nothing. + +**2. Define the stranded pool.** Spec 5.3 pays "the first valid proof included in a block"; 7.7 item 3 refuses a record older than 600 chain blocks; 7.8 item 7 says an unproven segment's aggregator share "stays in the escrow". Nothing says what happens to the shard credit nobody claimed. In the refusal scenario (4.2) the whole 20% is stranded for ten days: 5.5 M IGN that reach nobody and that nobody decided to burn. A roll-forward (the next proven segment's pool is larger by what was stranded) makes a refusal a transfer from refusers to returners, which is the incentive the design wants, and makes the pool's total over any month equal to 20% of emission as the litepaper's table promises. 8 hours. Gate on the fast-time harness. + +**3. The prover's price as a formula.** The whole of 4.1 (a) is one line: price per billion cycles = the subsidy the card forgoes per shard, which is `h/N`. At the devnet's 1.16 GH/s every quote is 100x the market; at 100 GH/s hybrids undercut it. The customer brief's "priced in dollars per proof" and the litepaper's "proofs at the cost of power" need the condition beside them, or the first customer conversation ends with the number. 3 hours of text. + +**4. The 80/20 as a bounded parameter, and one sentence for the thresholds.** The 4 October lever study found the pool share not load-bearing at launch traffic and useful at 30% under heavy traffic; tonight's runs (4.2) agree. A band of 10 to 30% lets miners trade lottery for proving capacity when the traffic says so, and the band stops the lottery's 80% from voting the provers out. The same change should carry the three signalling numbers in one place; today a reader finds 90 in spec 5.7 and CLAUDE.md, 95 in P2 and the preamble, 60 in 5.5, and "a 90% miner signal turns one on" in the litepaper's Mining section about a class change the P2 rule sets at 95. + +**5. Signalled execution parameters enter the digest, by CI.** Blocks carry transactions only. A node that signalled a fee change and runs the old rule accepts every block and computes a different state; its proof records fail everyone else's statement and everyone else's fail its own, which is loud for provers and silent for a wallet. `Params.fees` is in the digest and the handshake refuses a different digest, so today the defector is cut off. The next signalled parameter has no such guarantee until a check fails without it. 6 hours. + +**6. Block-rate steps as signal-plus-floor.** Spec 2.1 names the steps "a planned fork with its own test campaign, as Kaspa's Crescendo". Crescendo was a fixed DAA score (`params.rs` line 648) and Igneum's own fixed height cost it a 229-block reorg on 6 October. P2 exists; the steps should use it. 4 hours of text and a gate line. + +**7. The funding corrections.** One number and one row. 1 hour. + +**8. Measure the two numbers.** The hybrid row is the only competitive one and it rests on the 5090's 4% and a fixture a sixth of a full shard. Six hours on the fleet, through `tools/fleet/lib`, eleven boxes. + +Cross-references to lane 7 by name and rank: 3.1 (rank 7, the rental tax) would move 25 to 75% of a spiking block's subsidy to the pool; against 4.3's constant 11.8x ratio it doubles the renter's break-even and does not change the year the absolute cost gets small. 3.2 (rank 2, work-stake) removes the coin bond this lane's job model carries; the numbers here do not depend on the bond's form. 3.5 (rank 8, continuous dials) is the general form of proposals 1 and 4 here. 3.6 (rank 11, burn bounties) is option 5 of 4.3 and is rejected on the same ground. 3.11 (rank 15) and 3.12 to 3.14 are the market-size and verifiable-compute ceilings this lane's demand grid sits under. I7 (equivocation bounty in sortition slots) is the one treasury-less incentive in lane 7 that this lane's stranded-pool rule could fund without coins: stranded credit to the evidence carrier is a variant worth one line in the ledger, not a proposal here. + +--- + +## 6. Open questions and what I could not run + +- **The full-shard beside-the-miner times** on every tier (proposal 8). Linear scaling from the 4.7 M fixture says 92 s alone on a 3060 and 240 s beside the miner; if that holds, no 12 GB card meets the 120-s claim timeout beside its miner and the 25-s window is for 24 GB cards and up. The fleet was on the class v4 rehearsal tonight. +- **The hash loss while proving on Ampere and Ada**: the 5090's 4% is Blackwell with 32 GB; the 8 GB cards showed 6%; the 12 to 24 GB tiers are unmeasured and the hybrid row of 4.1 (a) moves with them. +- **Price elasticity of job demand**: every demand count is an assumption. The customer brief's "low millions a year" is the only market figure and it is approximate. +- **The rental market's supply curve**: 0 of 20 pods at the TH/s scale on 6 October; the attack costs assume the hash can be had at the measured price, which the bench entry says it cannot above about 2 GH/s. +- **The Devnet 2 block-rate runs** (RUN_A, RUN_B) were empty at writing; a 10 BPS chain changes shards per segment, records per block and the per-block fee step, and 4.1 (e) should be re-read when they land. +- **The economy simulator's price process** is exogenous; burns do not move it (4.2's burn is a number, not a feedback). +- **BIP 8 and BIP 9 texts, the Ethereum specs, Monero's reward code, Aleo, Boundless and Succinct** are cited by repository and path from memory or from the project's earlier readings and are marked approximate throughout; no clone exists in `vendor/`. + +--- + +## 7. Summary for the coordinator + +Lane 4 turned the eleven measured cards into a price per proof, built five demand curves with dollars and burn, re-ran the economy simulator with the measured table and the measured rental price under eight stresses, extended the security budget ten years with those fees, priced the dev fee and the signalling game, and tabulated what the other chains did. Three findings: + +1. **The proving price is `h/N`, not "the cost of power".** Electricity is under a cent per billion cycles on every card; the price a prover must charge is the subsidy it forgoes, which is 100 to 300x Boundless's USD 0.21 at today's 1.16 GH/s and 0.2 to 0.4x at 100 GH/s for a card proving beside its miner (`utility.py` 1.3). And the adopted floor prices a job at 15 IGN per billion cycles, USD 0.075 / 0.30 / 1.50 at the three prices: above USD 0.014 per IGN the chain overprices the market by rule, and a two-week vote cannot follow a dollar market (proposal 1). +2. **Fees are not a security budget for a decade.** All five uses together put USD 450 a day to miners and provers at launch and USD 4,200 in year 5 in the base scenario at 0.02 (`utility.py` 3.3) against USD 54,800 and 13,700 of daily emission; of the 48% fee share in year 5 under 1% reaches miners. The 20-day 34% weight attack costs 11.8x the honest fleet's 20 days at every price and year (`security_budget_10y.py`); its absolute net cost drops under USD 1 M in year 5 at 0.005 and year 9 at 0.02. The second audit has no payer by rule: the entity's own provers (USD 100 k a year at 5% of the pool, year 3, 0.02) are the only line that scales. +3. **The 80/20 survives every stress but one, and that one strands the pool.** With the eleven measured cards, the 25-s window and a renter farm at the measured rent, T1 to T5 hold under price x10 and /10, external zero and x100, a 20% proving cartel and the first halving (`stress.py`, 8 scenarios x 3 seeds; hash troughs at 55% of pre-event under the /10 shock with 31% of cards off, the one row at the T1 line). A ten-day refusal by every prover breaks T4 only, and what it costs is 547,570 IGN a day of pool credit stranded in the escrow with no rule to return it (5.5 M IGN over the ten days): a silent supply cut nobody voted for (proposal 2). The renter farm is off in every row but the x10 price shock (margin +114%) and partly on under x100 external demand (-6%), which is lane 3's N_eq in an agent model. + +Rules for main: the customer brief and the litepaper's "proofs at the cost of power" need the `h/N` condition before any customer conversation (proposal 3); `funding.md` section 4's dev-fee ceiling is a quarter too high (the fee moves the producer payout only); the three signalling thresholds are stated inconsistently across spec 5.7, CLAUDE.md, the P2 design and the litepaper's Mining section; and the spec is silent on pool credit nobody claims (proposal 2). diff --git a/docs/analysis/horizon/finality-and-weight.md b/docs/analysis/horizon/finality-and-weight.md new file mode 100644 index 000000000..ec6a1c76e --- /dev/null +++ b/docs/analysis/horizon/finality-and-weight.md @@ -0,0 +1,389 @@ +# Horizon lane 3: finality and weight + +Date: 6 October 2026, evening UK (written 19:30Z to 21:00Z, while the live devnet's finality was paused). Lane: finality-and-weight (the measured behaviour of the weight rule and the designs that extend it; lane 1 holds the attack catalogue and the 51 percent paper, cross-referenced by name). Worktree: `/Users/joshm/Projects/igneum-wt-horizon` (branch `horizon`). Models: `sim/horizon/finality-and-weight/` (README there says how to run every number). + +What was read: `docs/spec/03-finality.md` (whole, 3.11 included), `04-seeds-and-vdf.md`, `10-light-client.md`, `06-open-items.md` (O-3.1 to O-3.19), the fud-close worktree's `docs/spec/03-finality.md` 3.4.2 (the proposed vote and bitmap bounds, decided 6 Oct 2026 per `docs/plans/ledger-decisions.md` line 57); `docs/fud-ledger.md` F1 to F25 (F9, F14, F16, F18, F19, F20, F21 via its status lines, F22, F23, F24), P3, P4, P22, X20; `sim/README.md`, `sim/results_v2.md` (A to M), `sim/finality_v2.py` (this worktree's and fud-close `1544c63` with the block reading and scenario O); `docs/benchmarks/finality-v3-2026-10-04/` (fold-v2, fold-v3, split50-v2, split50-v3, split70-v3), `docs/benchmarks/round4-consensus-2026-10-04/results-final2.md`; `tools/finality-attacks/README.md`; `docs/plans/finality-v3-rollout-devnet.md`, `finality-v3-devnet-publish.md`; `docs/bench-log.md` entries of 4 to 6 October mentioning finality (floor 2/3, first live lock, rule v3, the C4 fix, round-4 items, the finality route, the rental cost of hash at line 2582); the gpu-fleet worktree's `docs/bench-log.md`, `docs/plans/`, `tools/fleet/` (grep for finality, lock, pause, voters, weight: the fleet has written no lock-delay or voter-count row yet; `docs/analysis/block-rate-devnet2.md` is still the template with RUN_A and RUN_B empty at 19:45Z), `docs/analysis/prover-tiers-real-cards.md`; the observer database (read-only SELECTs over `live_checkpoints`, `live_certificates`, `live_blocks`, `live_events`, `live_state`), node 1's log `/tmp/igneum-devnet/node1.out` on the Mac; `vendor/igneum-node` `Cargo.toml` and `consensus/core/src/finality.rs` for the BLS crate; the SP1 6.8.1 crates in the cargo registry (no SP1 clone exists under `vendor/`). + +## 1. The three findings first + +1. **Tonight's pause was the rule, not the aggregation path, and it was the frozen table that held it past 19:14Z.** The 20 keys that left the live chain between 17:20Z and 18:30Z held 3,026 of 7,083 blue blocks of the table frozen at the last lock (42.7 percent; the 13 that left with the 18:27 to 18:30Z rehearsal job alone 36.5 percent). The first unlocked checkpoint, 6843 at DAA 209,233 (about 18:40Z), had 75 of 93 voters' votes and 53.1 percent of total weight on the observer's node, under the two-thirds floor; certificates had kept forming for 18 checkpoints while node 1 and the observer were down (6824 to 6842, 18:30 to 18:39Z, 83 signers, 78.5 to 79.7 percent of total). From 19:14:53Z (checkpoint 6912) the stayers held 74.9 percent of the sliding table and still did not lock, because they hold 57.3 percent of the frozen table of lock 6842, which stands until DAA 216,402 (about 20:40Z). Under rule v2 the first lock would have come at 6912, 35 minutes after the last; under v3 the pause is one window, 2 hours on the devnet and 30 days on mainnet (spec 3.7 item 2, the price the project lead took on 4 October). +2. **Of the four candidate rules, only the departure announcement keeps the one-third bound.** In the simulator (3 seeds, mainnet scale) the decaying denominator and the hysteresis floor both restore liveness after tonight's departure in under an hour and both reopen the partition double lock (fast decay: both sides of every 360-minute partition lock alone from minute 120, 467 to 473 conflicting locks in the 50/50 honest split and 17 to 264 in the poisoned eclipse; slow decay: both sides of the 12-day splits lock alone at day 0.5 to 0.9, 31,545 to 32,246 conflicts; hysteresis: a 20 percent equivocator conflicts from minute 60, 565 to 597 locks, the 13.3 percent bound of 3 October back). The leave rule locks 1 hour after the departure (0.04 days; under 4 devnet minutes) with 0 conflicting locks in every partition, eclipse and equivocator row, and an attacker who buys keys to make them leave gains nothing it would not get by signing with them (w + L must still reach 2/3). The two-tier report never conflicts in its final tier by construction and shows 516 to 1,062 conflicting PROVISIONAL locks in every 360-minute partition and about 34,000 in the 12-day splits, so it is a reporting layer with a health warning, not a rule. +3. **Weight costs USD 8,424 x N x W / (1 - W) to rent for the full window** at the measured USD 11.7 per GH/s-hour: a veto (34 percent) against a 1 GH/s network is USD 4,300 over 30 days (0.52 x N of hash, a +52 percent step on the chart from day 1), against 1 TH/s USD 4.3 M; locking alone (67 percent) is 2.03 x N for 30 days (USD 17,100 per GH/s of network, USD 17 M at 1 TH/s), and faster is dearer (22 days: 10.6 x N). Buying old keys costs the seller's own rental equivalent, decays to nothing in 30 days (sim K), and nothing in the protocol makes weight unbuyable; what keeps the price at the rental cost is that the seller keeps a copy and one equivocation strips the key. + +## 2. Method + +Measured: the observer's Neon database (tables written by `tools/observer/observer.mjs`: `live_checkpoints` per index with state, signed and total weight, votes seen and voter count; `live_certificates` with the voter table and bitmap per certificate; `live_blocks` with `vote_key_hash` per block; `live_events`), read with SELECTs only through a scratchpad script (`fetch` to the Neon SQL endpoint, refusing any statement that is not SELECT; the queries are quoted inline). Node 1's log on the Mac for determination-to-lock delays (the `determined` and `LOCKED` lines per index; the log ends at 18:46:32Z when node 1 stopped). The departed keys were matched from certificate voter tables (48-byte public keys) to block producers (`vote_key_hash`) with BLAKE2b-256 keyed by `IgneumVoteKeyHash` (the fork's domain, `consensus/core/src/finality.rs`), 93 of 93 keys matched. + +Simulated: `sim/horizon/finality-and-weight/finality_horizon.py`, a copy of `sim/finality_v2.py` (fud-close `1544c63`) with four candidate rules and three scenarios (T, P, Q), run on igneum-build-1 (`/srv/builds/horizon-finality-and-weight/sim/`, Python 3.12, numpy 1.26.4, `nice -n 19`, one process per candidate, seeds 7, 11 and 13, about 25 minutes wall while the box carried other agents' builds at load 20 to 60); the smoke run on the Mac under `tools/lock/with-lock.sh run`. The model is the one `sim/results_v2.md` describes (1,000 Pareto keys, three regions, 2-s inter-region delay, 97 and 99.5 percent uptime, no DAG) at mainnet scale (30-day window); the devnet's window is 7,200 DAA s, so a mainnet day is four devnet minutes. Arithmetic scripts: `weight_capture.py`, `lightclient_cost.py`. + +Not run: the fast-time node harness (`tools/finality-attacks`) for the leave message (no such message exists in the node); any BLS timing on this machine (the figures are approximate from the crate's published benchmarks, anchored to the one measured pure-JavaScript verifier); the fleet's block-rate run (its file was still a template at 19:45Z). + +## 3. Evidence + +### 3.1 Tonight's pause, from the observer rows and node 1's log + +Times UTC. DAA scores advance about 1 per second on the live devnet. The observer's node is the view throughout; "votes" are the votes that node had seen for the index. + +| When | What | Source | +|---|---|---| +| 17:20 to 17:55Z | Four keys mine their last blocks on the live chain (92376b1a 105 blocks of the later frozen table, d1ee753c 22, 25dbfb0b 155, c4eb3431 131: 413 blocks, 5.8 percent) | `live_blocks`, max(received_at) per key before 18:43Z | +| 18:27 to 18:30Z | Thirteen fleet keys mine their last blocks (d5996917 248, 39d2dafc 246, 52d9d8c8 236, 3ca93140 227, 8debbb2d 219, 92dabf9d 216, f155fac3 215, 6cd0935e 212, 0cf69e5c 208, 11047080 200, b42641ab 144, cf860e4d 121, 2aaa021b 91: 2,583 blocks, 36.5 percent of the frozen table): the class v4 rehearsal job stopping their miners | `live_blocks`; CLAUDE.md 6 Oct rules | +| 18:30:02Z | Node 1's last own lock, 6823 (DAA 208,631), 78 signers, 68.7 percent of total; node 1 and the observer go down with the desktop app until 18:42:08Z (`Observer reconnected to the node`) | node1.out; `live_events` | +| 18:30 to about 18:39Z | Locks 6824 to 6842 form without the hub (DAA 208,660 to 209,202): 83 signers, 78.5 to 79.7 percent of total; aggregators 3ca93140, 8debbb2d, 69570532 and the zero fallback | `live_checkpoints` (ingested at 18:42:09Z), `live_certificates` bitmaps | +| about 18:39:40Z | The last lock, 6842 at DAA 209,202, 79 of 91 signers. Its frozen table (the voter table at 6850 the observer stored with it): 93 keys, 7,083 blocks; the 20 departed keys hold 3,026 (42.7 percent), the stayers 4,057 (57.3 percent) | `live_certificates` 6842 voters, matched to `live_blocks` | +| about 18:40Z | 6843 at DAA 209,233 determined and never locked: 75 votes, 3,757 of 7,080 = 53.1 percent of total. The departed boxes' nodes have left the live chain (their blocks had already stopped), the signing weight is under two thirds: the rule pauses | `live_checkpoints` | +| 18:42:08Z | The observer reconnects and the pause becomes visible on the hub; node 1 ingests 6828's certificate by gossip (`70.3% of the table frozen at lock 6827`) | `live_events`, node1.out | +| about 18:50Z | Twenty indices without a lock (6862, DAA 209,800): `finality_active` false, reason `paused` (spec 3.9) | `live_checkpoints` | +| 18:58 to 19:03Z | Votes seen fall to 49 (48.5 percent): five more keys quiet for five minutes (the hands' own restarts, approximate) | `live_checkpoints` 6876 to 6885 | +| 19:14:53Z | 6912 at DAA 211,301: 79 votes, 5,355 of 7,152 = 74.9 percent of the SLIDING table, over two thirds; no lock. The stayers hold 57.3 percent of the table frozen at 6842 (Q5), under two thirds: "held by the frozen table" | `live_checkpoints`; spec Q5 | +| 19:29Z (write-up) | Still paused: 6938 proposed at 79.2 percent with 78 votes. Expected first lock when the frozen table expires at DAA 216,402 (209,202 + 7,200), about 20:40Z, or when departed keys holding 9.4 points of the frozen table return | `live_checkpoints`; arithmetic | + +Under rule v2 (sliding table only) the stayers' share rises as the departed blocks age out: from 53.1 percent at 6843 to two thirds after 7,200 x (1 - 1/(3 x 0.469)) = 2,082 DAA (spec 3.3.1's churn formula at the devnet window), which is checkpoint 6912 at 19:14:53Z: a 35-minute pause. Under v3 it is one window: 2 hours here, 30 days on mainnet (spec 3.7 item 2; `sim/results_v2.md` M4). The coordinator's working hypothesis of 19:3xZ (topology: the hub was down and the fleet's votes could not reach the VRF-picked aggregators) is refuted by three rows above: certificates formed while the hub was down (6824 to 6842), the zero-aggregator fallback of Q4 is in routine use (64 of the 251 certificates stored between 16:30 and 19:00Z name aggregator `00000000`, the next most frequent key 34), and the pause began at the checkpoint where the signing weight fell to 53.1 percent, which is the rule's threshold and not a routing failure. The observer's node itself held 74.9 percent of the sliding weight in votes from 19:14Z and did not certify, which only Q5 explains. + +Per tier: a home miner, rig or pool user on the live devnet saw `finality_active` false for 2 hours and lost nothing (blocks, execution and payouts continued; the exchange guidance of 3.9 applies); a prover's records were still paid; the fleet operator learned that a standing box never leaves the live chain for an experiment (CLAUDE.md, the standing-fleet rule). On mainnet the same event, 43 percent of weight leaving in three minutes, is a 30-day pause under v3 and a 7.7-day one under v2. + +### 3.2 Lock delay against voter count (measured) + +Determination-to-lock on node 1 (the `determined` and `LOCKED` lines per index, 6 October 2026, per UTC hour; voter counts from the observer's `live_checkpoints` for the same hour). + +| Voters above dust | UTC hours | Locks | Delay p50 | p90 | p99 | Max | Source | +|---|---|---|---|---|---|---|---| +| 4 to 9 | 01 to 06 | 119 to 120 per hour | 0.86 to 0.97 s | 1.17 to 1.31 s | 1.53 to 1.80 s | 1.59 to 2.29 s | node1.out | +| 17 to 24 | 07 to 11 | 118 to 120 | 0.82 to 0.97 s | 1.09 to 1.29 s | 1.53 to 1.83 s | 2.18 s (the 111-s p90 of 08Z is a restart) | node1.out | +| 24 to 30 | 12 to 14 | 104 to 122 | 0.94 to 1.32 s | 1.36 s (quiet hours) | 48 s (restarts) | | node1.out | +| 43 | 16 | 54 (hour cut by a restart) | 0.92 s | 1.17 s | | | node1.out | +| 63 | 17 | 124 | 1.13 s | 1.44 s | 1.47 s | 8.8 s | node1.out | +| 92 to 93 | 18 | 125 (to 18:30Z) | 1.26 s | 1.50 s | 1.82 s | 1.82 s | node1.out | +| 6 (fast time, 300-ms proxied links) | 4 Oct | 11 to 12 per node | 1.008 s | | | | `docs/benchmarks/finality-v3-2026-10-04/fold-v3.md` | +| 12 (cloud devnet, 5 locations) | 4 Oct | 212 indices | 1.24 s to the first certificate (p99 1.71 s), the last vote 1.45 s (p90 2.36 s) | | | | ledger F22, `infra/cloud-devnet/results/2026-10-04/f22-vote-timing.md` | +| 1,000 (simulator, 2-s inter-region delay) | | 172,883 | 2.5 s | | 4.6 s | 6.1 s | `sim/results_v2.md` A | + +The devnet's delay is the miner's 1-s template poll plus one gossip round (the 250-ms gossip pump per hop, ledger F22): 0.9 s at a handful of voters, 1.26 s at 93. A straight line through the devnet rows is 0.9 s + 4 ms per voter (approximate; 93 points on one topology), which puts 1,000 voters near 5 s and 8,192 near 34 s, past the 30-s interval. Section 4.3 says why that line does not hold and what does. + +### 3.3 Sizes and crates (from the fork) + +| Item | Value | Source | +|---|---|---| +| BLS crate | `blst = "0.3.17"` (workspace), min-pubkey variant: 48-byte G1 keys, 96-byte G2 signatures | `vendor/igneum-node/Cargo.toml` line 238, `consensus/core/Cargo.toml` line 20, `consensus/core/src/finality.rs` line 17 (`blst::min_pk`) | +| Aggregation and verification | `AggregateSignature::aggregate` over the votes' signatures (line 230); `fast_aggregate_verify` over the summed public keys and one vote message (line 239 to 253) | `consensus/core/src/finality.rs` | +| Vote item | 281 B (tag 1, index 8, checkpoint 32, key 48, signature 96, sortition proof 96) | spec 3.4.2 item 1 (fud-close), the fork's `Vote::LEN` | +| Certificate | 273 B plus ceil(V/8) B of bitmap: 285 B at 93 voters, 398 at 1,000, 1,297 at 8,192, 8,465 at 65,536 | same | +| Bitmap wire bound | 1 MiB today (`Certificate::read`, `bitmap_len > 1 << 20`, line 429); 8,192 B proposed and decided (65,536 voters, 8x the S2 switch) | finality.rs; spec 3.4.2 item 3; ledger-decisions line 57 | +| Per-block vote bound | 48 on the devnet; 384 on mainnet proposed and decided (107,904 B, 21.6 percent of the compute mass; a checkpoint's 8,192 votes drain in 21.3 blocks) | spec 3.10 Q1/Q2 row; 3.4.2 item 2 | +| Votes per checkpoint, single-vote carriage | 93 voters: 26,133 B; 1,000: 281,000 B; 8,192: 2,301,952 B (4.6x one block's mass); 65,536: 18.4 MB | 281 x V | +| Votes per checkpoint, aggregated carriage (Q2 allows one BLS signature plus a bitmap per (index, hash)) | about 0.4 KB at 93 voters, 1.2 KB at 8,192, 8.6 KB at 65,536 | spec 3.4.2 item 2 | + +### 3.4 What the simulator already measured (cited, `sim/results_v2.md`) + +| Fact | Value | Section | +|---|---|---| +| Churn under v2: first lock after a set holding x stops mining and signing | 35 percent: 1.7 days (analytic 1.4); 50 percent: 10.1 to 10.3 days (analytic 10.0) | L2, D | +| Churn under v3 | 30.00 days at 35 and 50 percent (the frozen table's expiry) | M4 | +| Silent set that keeps mining | 34 percent and above: no lock for as long as it is silent; first lock 0 min after it returns | J, L1 | +| Equivocator across a 50/50 split | 33 percent: 0 conflicts; 34 percent: 2 to 54 conflicts from minute 2 to 77 (the one-third bound) | H, M5 | +| Long honest partition, view-local weight, v2 against v3 | 50/50: both sides lock alone from day 10.1 to 10.3 under v2, never in 12 days under v3, both at day 30.00 of a 31-day split | L4, M2, M3 | +| Acquired keys worth 40 percent, attacker at 30 percent of hash | veto from day 1 to day 19 or 20, 30 percent on day 30; silent, 63,307 to 68,716 of 86,400 checkpoints stalled | K | + +## 4. Model + +### 4.1 The pause arithmetic (spec 3.3.1 and 3.7, restated with tonight's inputs) + +Let x be the share of the window weight that stops mining and signing at once, W the window (2,592,000 DAA s on mainnet, 7,200 on the devnet). + +| Rule | First lock after the departure | Tonight (x = 0.469 on the observer's node at 6843, W = 7,200) | Mainnet, same x | +|---|---|---|---| +| v2, sliding table | W x (1 - 1/(3x)) (never for x at or under 1/3) | 2,082 DAA, 35 min: measured as the moment the sliding share crossed two thirds (6912) | 7.7 days | +| v3, frozen table (live) | W after the last lock, whatever x over 1/3 | 7,200 DAA, 2 h (expected 20:40Z) | 30 days | +| (iv) leave, delay D | D after the signed leave (0 if sent D before the stop) | 1 h, or 0 with notice | 1 h | +| (i) decay, grace T, rate r per hour | at most T + (1/r) x (1 - (1 - x)/(2x)) hours: the departed weight decays until the stayers hold two thirds of what is left | T 1 h, r 0.5: 1 h 17 min (x 0.469); T 6 h, r 1/24: 20 h | the same hours | +| (iii) hysteresis, H hours, low floor f | H hours, then only if the stayers hold f x 2/3 of total | f = 0.85: 56.7 percent needed, the stayers held 53.1 then 57.3 percent: after H plus the ageing to 56.7 percent, 1 to 1.5 h | about 1 day | +| (ii) two-tier | provisional at once (2/3 of the active denominator); final as v3 | provisional 0 min, final 2 h | provisional minutes, final 30 days | + +### 4.2 Why the view-dependent candidates fail (and the sim's confirmation) + +Spec 3.11.2's bound comes from counting: two certificates at one index need 2/3 of the denominator each, 4/3 in all, so a third signed both and that third is equivocating. The denominator has to be the same number on both sides of a partition for that sum to mean anything. A rule that removes weight on what a view has not seen (a vote missing for T hours, blocks missing) gives each side a different denominator: side A removes side B's keys, side B removes A's, and both sides' own share rises toward 1 at the same rate. For a 50/50 split under decay(T, r) each side's own share reaches 2/3 when the other side's factor is 0.5, at T + 1/(2r) hours (2 hours at T 1 h, r 0.5; 18 hours at T 6 h, r 1/24), and every checkpoint after that is a conflicting lock, the hazard of `sim/results_v2.md` E in a new coat. The frozen table does not save it when the decay is applied to the frozen table too (which is the only way decay helps tonight). The hysteresis floor is view-dependent in the same way (each side measures its own connected share), so after H hours both sides run the 0.85 rule and the 13.3 percent equivocator bound of 3 October returns (the sim's 33 percent row under `hyst` shows one side locking at minute 59). A rule that removes weight on what a view has seen, a signed leave carried in the DAG or equivocation evidence, is seen by both sides at the heal and by at most one side during the split; during the split the side that saw the leave removes L from its denominator and needs 2/3 (1 - L) of signers while the other side still needs 2/3 of the full table; both locking needs s_A + s_B at least 2/3 (2 - L), more than the 1 - L available without an equivocator, so the one-third bound survives (with an equivocator a, the bound is a at least (1 - L)/3 of the remaining weight, the same statement over the reduced table). + +Why leaving bought keys buys nothing (Q2 in the sim and arithmetic): an attacker holding w of the window who buys L and makes it leave holds w / (1 - L) of what remains; to lock alone it needs w at least 2/3 (1 - L), so w + L at least 2/3 + L/3, never under two thirds of the window, and signing with the bought keys (w + L at least 2/3) is the cheaper use of the same purchase. In the model the attacker's share after leaving its bought 40 percent was 4.8 percent on day 3, the position of its own hash alone. + +### 4.3 Lock delay as a function of voters and message delay + +delay = template poll (1 s on the devnet; the node's own determination on mainnet, 0) + hop_1 (block to voter) + hop_2 (vote to aggregator) + processing + certificate gossip (one hop). The simulator's two hops at Delta give median 0.7 s at 0.5 s, 2.5 s at 2 s, 6.2 s at 5 s (A); the devnet's 0.9 s is the poll plus a 250-ms pump. The per-voter term is the aggregator's verification of each vote as it arrives: one BLS verify is a pairing, about 1.6 ms (approximate, blst 0.3.17 published figures; the fork verifies each vote on ingest, `verify_vote_signature`, finality.rs line 192), which is 150 ms per checkpoint at 93 voters, 1.6 s at 1,000, 13 s at 8,192 and 105 s at 65,536 on one core: past 1,000 voters the single-vote path is a CPU bound before it is a bandwidth bound, and at 8,192 it is more than a quarter of every core's time on every node (every node verifies every vote it relays). The fix is already in the spec's text (Q2 aggregated carriage) and in the crate (`AggregateSignature::aggregate` then one `fast_aggregate_verify`): aggregate first, verify once per (index, hash), which costs V G1 additions (about 1 us each) plus one pairing: 1.7 ms at 93, 2.6 ms at 1,000, 10 ms at 8,192, 67 ms at 65,536. Its price is the batch-poisoning vector (one invalid vote fails the batch and forces bisection); S2's sub-user sortition at 8,192 bounds the signer count at about 4,000 expected either way. + +| Voters | Vote bytes per checkpoint (single) | Verify per checkpoint, single votes (approximate) | Aggregate-first (approximate) | Lock delay, model (Delta 2 s) | Bitmap | +|---|---|---|---|---|---| +| 12 | 3.4 KB | 19 ms | 1.6 ms | 2.5 s (sim A, 1,000 keys) ; 1.24 s measured | 2 B | +| 40 | 11 KB | 64 ms | 1.6 ms | about 2.5 s | 5 B | +| 100 | 28 KB | 160 ms | 1.7 ms | about 2.6 s; 1.26 s measured at 93 on the devnet | 13 B | +| 1,000 | 281 KB | 1.6 s | 2.6 ms | about 4 s single, 2.5 s aggregated | 125 B | +| 8,192 | 2.3 MB (4.6x block mass) | 13 s per node per checkpoint: breaks the 30-s cadence on a shared core | 10 ms | 2.5 s aggregated; S2 switches to about 4,000 sub-users here | 1,024 B | +| 65,536 | 18.4 MB | 105 s: impossible single | 67 ms (3.9 s of key decompression once) | 2.5 s aggregated | 8,192 B, the proposed wire bound | + +Where the aggregator path breaks down: not at the 8 VRF-picked aggregators (anyone MAY aggregate, Q4's fallback at 15 DAA is in routine use tonight: 26 percent of certificates) but at per-vote verification above about 1,000 voters and at the per-block vote carriage above 8,192 (spec 3.4.2 item 2's 384-per-block bound drains a checkpoint in 21 blocks; participation accounting lags, locks do not, because certificates form from gossiped votes). The message-delay term scales the two hops and nothing else; at 5 s inter-region delay the slowest region already loses participation to the 15-s grace (A). + +### 4.4 Weight capture cost (task 3; `weight_capture.py`) + +share(t) = (t/30) x A/(N + A) for A rented against N for t days (spec 3.1, sim B within 0.04 points). To hold W at day t: A = N q/(1 - q), q = 30W/t (needs t over 30W). Cost = A x t x 24 x USD 11.7 per GH/s-hour (measured 6 Oct 2026, bench-log "Rental cost of hash": 1,748 MH/s for USD 20.44/h on RunPod community pods; the 8x 4090 rig USD 5.92/h for 459 MH/s). Cost falls with t, so the cheapest attack takes the full window: A = N W/(1 - W), cost = 8,424 x N x W/(1 - W) USD per GH/s of network. + +| Target | Hash to rent | Day noticed (the chart step) | N = 1 GH/s | N = 10 GH/s | N = 100 GH/s | N = 1 TH/s | +|---|---|---|---|---|---|---| +| 34 percent in 30 days (veto) | 0.52 x N | day 1: +52 percent | USD 4,300 | USD 43 k | USD 434 k | USD 4.3 M | +| 34 percent in 21 days | 0.94 x N | day 1: +94 percent | USD 6 k | USD 56 k | USD 557 k | USD 5.6 M | +| 51 percent in 30 days | 1.04 x N | +104 percent | USD 8.8 k | USD 88 k | USD 877 k | USD 8.8 M | +| 67 percent in 30 days (locks alone) | 2.03 x N | +203 percent | USD 17 k | USD 171 k | USD 1.71 M | USD 17.1 M | +| 67 percent in 25 days | 4.10 x N | +410 percent | USD 29 k | USD 288 k | USD 2.9 M | USD 28.8 M | +| 67 percent in 22 days | 10.6 x N | +1,058 percent | USD 65 k | USD 654 k | USD 6.5 M | USD 65 M | + +What the market supplies: RunPod gave 0 of 20 pods asked at 18:59Z to 19:15Z (bench-log); 38 pods were 1.75 GH/s. So at tonight's 1.16 GH/s devnet every row of the first column is a dinner; at 100 GH/s the 52 GH/s for a veto did not exist on the one market asked (approximate). The alarm that sees the step is lane 1's detector. + +Buying old keys (F19): a key is a 32-byte scalar named in headers by `vote_key_hash`; it can be handed over, W5 succession moves its history once (not implemented, O-3.11), and the seller can keep a copy. Its worth is its blocks: keys worth b of the window are the position of having rented b/(1 - b) x N for 30 days (USD 2,100 per GH/s of network at b 20 percent, 4,300 at 34, 5,600 at 40), and that position decays as b (1 - t/30) + r t/30 (sim K, within 0.6 points). What makes weight unbuyable: nothing in the protocol. What makes bought weight a bad buy: it ages out in 30 days whatever the buyer does, a seller's copy can equivocate it away (3.6), and a pool's key is its payout identity, so the price is the pool. What the header does not do: it does not tell anyone the key changed hands until its blocks stop matching its old profile (the detector's job). A rule that would make it harder, decaying a key whose block profile breaks, is view-dependent in a partition (section 4.2) and is not recommended. + +Per tier: a home miner's or rig's key (one per machine under 3.4.2 item 4) is worth its 30 days of blocks and nothing a buyer would pay for; a pool's key is the only one worth buying and the only one whose sale is visible; a holder's finality rests on the 2/3 of weight no one can rent cheaply past a few GH/s; a rollup customer's bridge inherits the same bound. + +### 4.5 Long-range and checkpoint sync for light clients (task 4; `lightclient_cost.py`) + +What a node joining after 60 days trusts (spec 10.1 and 10.3): the trusted checkpoint shipped in its release, refreshed from N of M seed nodes (M 5, N 3, O-10.5), and from there every certificate it fetches is verified against the voter set, which in checkpoint mode it takes from nodes (N of M agreement) and in full-header mode recomputes from 30 days of headers (W2). The cold-sync node of X20 selects the heaviest DAG then follows certificates found in it (F5), so its first 30 days of history are proof of work in the sense of 3.9. The weak-subjectivity window Igneum has in fact is one weight window: a certificate older than 30 days can be checked only against a voter table the client cannot recompute from less than 30 days of headers, and under v3 the frozen table expires 30 days after a lock, so a node offline longer than 30 days cannot tell a certified chain from a chain certified by keys that have since left the window; the same class of assumption as Ethereum's weak-subjectivity period for a sync-committee checkpoint (not cloned here; approximate), with the window the parameter. + +| Mode, per year of chain | 93 voters | 1,000 | 8,192 | 65,536 | Source | +|---|---|---|---|---|---| +| Every certificate (1,051,200) plus its header, bytes | 720 MB | 839 MB | 1.78 GB | 9.3 GB | 285 to 8,465 B per certificate plus 400 B header | +| Verify time, one laptop core (approximate: V G1 adds plus hash-to-G2 plus two pairings, 1.8 to 67 ms each) | 32 min | 48 min | 2.9 h | 20 h | `lightclient_cost.py` | +| On a phone core (3x, approximate) | 1.6 h | 2.4 h | 8.7 h | 59 h | | +| One certificate per presence window (4,380 a year, spec 10.3 item 3) | 3.0 MB, 8 s | 3.5 MB, 12 s | 7.4 MB, 44 s | 39 MB, 4.9 min | the voter set at each stop is not paid for | +| Full-header mode, headers alone | 12.6 GB a year at 400 B per header | | | | | + +The measured anchor: the pure-JavaScript verifier of a 16-signer certificate took 58 to 68 ms warm on the M5 Max (bench-log, sweep round 6, P3), about 30x the native estimate here; a phone has not been measured (O-10.3). + +The ZK light client (phase two, O-10.8), designed: one recursive proof per checkpoint whose step statement is "certificate i verifies under voter table T_i; T_i follows from T_(i-1) by the interval's 30 blue headers and the window's ageing; the signers hold at least two thirds of T_i and of the frozen table; C_i's selected chain passes through C_(i-1)", with the previous step's proof verified inside (SP1's deferred-proof path, `VERIFY_SP1_PROOF` in `sp1-core-executor-6.8.1/src/syscall_code.rs`; the recursion crates are `sp1-recursion-{circuit,compiler,executor,machine,gnark-ffi}-6.8.1` in the cargo registry, no SP1 clone under `vendor/`). What the circuit costs, approximate: key aggregation V x BLS12381_ADD (about 500 cycles each: 46,500 cycles at 93 voters, 0.5 M at 1,000, 4.1 M at 8,192); hash-to-G2 about 0.3 M (SHA-256 is precompiled, the Fp2 arithmetic is BLS12381_FP2_*); the two pairings 10 to 30 M cycles, the dominant term, because 6.8.1 has Fp and Fp2 precompiles for BLS12-381 (ADD, DOUBLE, FP_ADD/SUB/MUL, FP2_ADD/SUB/MUL) and no pairing precompile; 30 BLAKE2b header hashes and the table transition 1 to 2 M (no BLAKE2b precompile). Against the measured shard curve (`docs/analysis/prover-tiers-real-cards.md`: 4.7 M cycles compressed in 4.8 to 14.4 s alone, 10.7 to 37.5 s beside the miner) a 15 to 35 M cycle step is 15 to 100 s alone and 40 to 260 s beside a miner, plus the recursion step measured at 2.2 to 2.5 s idle and 7.9 to 9.7 s beside the miner on the 5090 (bench-log, agg-cost and `chain-pc2-pv1c`). One checkpoint every 30 s therefore needs 1 to 4 proving-only cards (or 2 to 9 mining ones) at it continuously. A Groth16 wrap for the phone is the unbuilt R4 (P3). + +What it buys each tier: a phone wallet verifies one wrapped proof per open (about 400 B, milliseconds once the wrapper exists) instead of a certificate chain and a trusted voter set, and the "voter set: from nodes" status disappears (spec 10.4); a bridge verifies one proof per checkpoint it settles on and never a BLS certificate on-chain (an on-chain BLS12-381 aggregate verify at 1,000 voters is about 1,000 G1 additions and one pairing, which on Ethereum is the point-evaluation and pairing precompile budget, approximate); a rollup customer gets a finality statement its own verifier can check without Igneum's voter list; a node operator pays nothing (full nodes keep the native rule); a prover tier gains a steady job (one proof per 30 s) at the cycle counts above; a home miner with one 12 GB card beside its miner (27 to 37 s per 4.7 M-cycle shard) cannot keep up with a 30-s cadence alone and joins as one of several; a 24 or 32 GB card alone does it in the interval. + +### 4.6 Prover attestations as a second finality leg (task 5) + +Design: a checkpoint locks when (a) its certificate carries two thirds of weight (Q3, Q5) AND (b) proof records covering every chain block in (C_(i-1), C_i] from at least k distinct prover keys are in the past of some block the certificate's signers could see. Measured inputs: the proof lag on the live devnet, block to carried record, p50 44 s, p90 52 s, p99 62 s, max 65 s (bench-log, proving v1 coverage windows, 5 Oct); coverage 2.4 to 4.7 percent of blocks with one prover (the same rows); the chain-mode cost 17 s per empty block on a mining 5090, about 5 s proving-only; a 12 GB card beside its miner 27 to 37 s per v1 shard (prover-tiers); a mandatory rule needs about 6 proving-only 5090s or 18 mining ones for an empty-block chain at 1 block/s (bench-log table), 45 proving-only at B_p. + +| Measure | Weight alone (today) | Weight AND k-prover attestations | Label | +|---|---|---|---| +| Lock delay after the checkpoint block | 1.26 s at 93 voters (3.2) | at least the slowest block's proof lag inside the interval: p99 62 s today, so about 60 to 70 s; the transaction-to-lock figure of C1 rises from 90 to 120 s to about 150 to 190 s | measured lag, derived sum | +| Checkpoints that could lock on tonight's devnet | all with two thirds signing | 2.4 to 4.7 percent (one prover): finality paused 95 percent of the time until proving is mandatory and the fleet is 6 to 18 cards | measured coverage | +| What it stops that weight does not | nothing for a full node: it re-executes and vetoes a statement that is not the native one (spec 7.2 item 5, the native veto) | a two-thirds weight holder cannot lock a checkpoint whose execution has no valid proof, which protects the LIGHT client, who trusts certificates and cannot execute (10.1); the design already gives the light client that by requiring the segment proof beside the certificate (10.4 item 4), so the leg moves the requirement from the client into the lock | design | +| Withholding to pause | a silent third pauses (L1) | a prover set that withholds proofs pauses finality for as long as no one else proves; the shard sortition names 8 provers by weight with a 10-s exclusive window and then anyone MAY prove (spec 7.2), so the price of a pause is out-proving every honest card for the whole pause, which in a thin market (tonight: one prover at times) is one card's outage | design, measured market | +| Per tier | unchanged | a 12 GB card beside its miner proves one 4.7 M-cycle shard in 27 to 37 s, so k = 2 provers per block means 37k mining 12 GB cards (or 10k proving-only 4070s at 12 s) kept busy for an empty chain, approximate; a pool user nothing; a holder a longer wait; a rollup customer the same proof it already needs | prover-tiers, derived | + +Verdict: not as a lock condition now. The leg converts "locked" into "locked and proven" at the cost of a minute of lock delay and a pause whenever proving coverage drops, which tonight is almost always. The design's four-state interface (included, executed, proven, locked; O-7.2) already gives the exchange and the wallet the conjunction as a reading. Gate before it could become a rule: 99 percent of chain blocks proven within 60 s for 7 days on the public testnet with at least 3 distinct provers per block, measured by `tools/proving-v1/coverage.mjs`. + +## 5. Results of the candidate runs (`finality_horizon.py`, seeds 7, 11, 13) + +### 5.1 T. Tonight's departure: first lock after x of weight stops mining and signing at once (31 days, seeds 7, 11, 13) + +| departed weight | rule | first final lock after the departure | provisional tier | stalled checkpoints | stalled after the first lock | conflicting final locks | conflicting provisional locks | +|---|---|---|---|---|---|---|---| +| 34% | v2 | 0.77 to 0.87 d (devnet 3 to 3 min) | | 4057 to 4727 | 1531 to 2489 | 0 | | +| 34% | v3 | 30.00 d (devnet 120 min) | | 86388 to 86472 | 0 to 31 | 0 | | +| 34% | leave | 0.04 to 0.04 d (devnet 0 to 0 min) | | 119 to 521 | 0 to 398 | 0 | | +| 34% | decay1 | 0.05 to 0.05 d (devnet 0 to 0 min) | | 133 to 534 | 0 to 398 | 0 | | +| 34% | decay6 | 0.30 to 0.30 d (devnet 1 to 1 min) | | 897 to 1298 | 24 to 442 | 0 | | +| 34% | hyst | 0.04 to 0.04 d (devnet 0 to 0 min) | | 881 to 1445 | 761 to 1325 | 0 | | +| 34% | twotier | 30.00 d (devnet 120 min) | provisional 0.000 to 0.004 d (devnet 0.0 to 0.0 min) | 86388 to 86472 | 0 to 31 | 0 | 0 | +| 45% | v2 | 7.85 to 8.03 d (devnet 31 to 32 min) | | 23947 to 25153 | 1369 to 2065 | 0 | | +| 45% | v3 | 30.00 d (devnet 120 min) | | 86382 to 86420 | 0 to 22 | 0 | | +| 45% | leave | 0.04 d (devnet 0 min) | | 119 to 204 | 0 to 83 | 0 | | +| 45% | decay1 | 0.07 to 0.08 d (devnet 0 to 0 min) | | 224 to 296 | 9 to 83 | 0 | | +| 45% | decay6 | 0.64 to 0.67 d (devnet 3 to 3 min) | | 1946 to 1985 | 0 to 129 | 0 | | +| 45% | hyst | 30.00 d (devnet 120 min) | | 86382 to 86420 | 0 to 22 | 0 | | +| 45% | twotier | 30.00 d (devnet 120 min) | provisional 0.031 to 0.034 d (devnet 0.1 to 0.1 min) | 86382 to 86420 | 0 to 22 | 0 | 0 | +| 50% | v2 | 10.09 to 10.34 d (devnet 40 to 41 min) | | 30107 to 31264 | 1065 to 1456 | 0 | | +| 50% | v3 | 30.00 d (devnet 120 min) | | 86387 to 86514 | 0 to 10 | 0 | | +| 50% | leave | 0.04 d (devnet 0 min) | | 118 to 490 | 0 to 371 | 0 | | +| 50% | decay1 | 0.08 to 0.09 d (devnet 0 to 0 min) | | 244 to 609 | 0 to 371 | 0 | | +| 50% | decay6 | 0.76 to 0.77 d (devnet 3 to 3 min) | | 2231 to 2543 | 0 to 371 | 0 | | +| 50% | hyst | 30.00 d (devnet 120 min) | | 86387 to 86514 | 0 to 10 | 0 | | +| 50% | twotier | 30.00 d (devnet 120 min) | provisional 0.042 d (devnet 0.2 min) | 86387 to 86514 | 0 to 10 | 0 | 0 | + +### 5.2 P1. Partitions of 360 minutes (each side retargets and counts only its own blocks) + +| rule | case | partition min | conflicting final locks | conflicting provisional locks | first conflict, min | first lock per side, min | every pre-heal lock kept | first lock after heal, min | stalls in 2 h after heal | +|---|---|---|---|---|---|---|---|---|---| +| v2 | 50/50 honest, 0% attacker | 360 | 0 | | never | never / never | yes | 0 | 0 | +| v2 | 50/50 + 20% equivocator (sides 60/60) | 360 | 0 | | never | never / never | yes | 0 | 0 | +| v2 | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 0 | | never | never / 279 (never in 2 of 3) | yes | 0 to 0 | 0 | +| v2 | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 142 to 291 | | 14 to 77 | 11 to 48 / 0 to 76 | yes | 0 to 0 | 0 | +| v2 | 40/40/20 honest | 360 | 0 | | never | never / never / never | yes | 0 to 0 | 0 | +| v2 | 60/40 honest | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| v2 | 70/30 honest | 360 | 0 | | never | 0 to 4 / never | yes | 0 | 0 | +| v3 | 50/50 honest, 0% attacker | 360 | 0 | | never | never / never | yes | 0 | 0 | +| v3 | 50/50 + 20% equivocator (sides 60/60) | 360 | 0 | | never | never / never | yes | 0 | 0 | +| v3 | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| v3 | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 139 to 283 | | 14 to 78 | 12 to 50 / 0 to 77 | yes | 0 to 0 | 0 | +| v3 | 40/40/20 honest | 360 | 0 | | never | never / never / never | yes | 0 to 0 | 0 | +| v3 | 60/40 honest | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| v3 | 70/30 honest | 360 | 0 | | never | 0 to 4 / never | yes | 0 | 0 | +| leave | 50/50 honest, 0% attacker | 360 | 0 | | never | never / never | yes | 0 | 0 | +| leave | 50/50 + 20% equivocator (sides 60/60) | 360 | 0 | | never | never / never | yes | 0 | 0 | +| leave | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| leave | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 139 to 283 | | 14 to 78 | 12 to 50 / 0 to 77 | yes | 0 to 0 | 0 | +| leave | 40/40/20 honest | 360 | 0 | | never | never / never / never | yes | 0 to 0 | 0 | +| leave | 60/40 honest | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| leave | 70/30 honest | 360 | 0 | | never | 0 to 4 / never | yes | 0 | 0 | +| decay1 | 50/50 honest, 0% attacker | 360 | 467 to 473 | | 121 to 126 | 120 to 122 / 121 to 123 | yes | 0 | 0 | +| decay1 | 50/50 + 20% equivocator (sides 60/60) | 360 | 528 to 535 | | 93 to 94 | 91 / 92 to 94 | yes | 0 | 0 | +| decay1 | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 587 to 595 | | 64 to 65 | 62 / 63 to 65 | yes | 0 to 0 | 0 | +| decay1 | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 575 to 612 | | 14 to 62 | 12 to 50 / 0 to 62 | yes | 0 to 0 | 0 | +| decay1 | 40/40/20 honest | 360 | 815 to 822 | | 142 to 144 | 140 to 142 / 140 to 140 / 166 to 166 | yes | 0 to 0 | 0 | +| decay1 | 60/40 honest | 360 | 435 to 436 | | 142 to 142 | 92 to 96 / 141 to 142 | yes | 0 to 0 | 0 | +| decay1 | 70/30 honest | 360 | 403 to 414 | | 154 to 156 | 0 to 4 / 154 to 156 | yes | 0 | 0 | +| decay6 | 50/50 honest, 0% attacker | 360 | 0 | | never | never / never | yes | 0 | 0 | +| decay6 | 50/50 + 20% equivocator (sides 60/60) | 360 | 0 | | never | never / never | yes | 0 | 0 | +| decay6 | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| decay6 | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 139 to 283 | | 14 to 78 | 12 to 50 / 0 to 77 | yes | 0 to 0 | 0 | +| decay6 | 40/40/20 honest | 360 | 0 | | never | never / never / never | yes | 0 to 0 | 0 | +| decay6 | 60/40 honest | 360 | 0 | | never | never / never | yes | 0 to 0 | 0 | +| decay6 | 70/30 honest | 360 | 0 | | never | 0 to 4 / never | yes | 0 | 0 | +| hyst | 50/50 honest, 0% attacker | 360 | 0 | | never | never / never | yes | 0 | 0 | +| hyst | 50/50 + 20% equivocator (sides 60/60) | 360 | 565 to 597 | | 60 to 61 | 58 to 61 / 58 to 61 | yes | 0 | 0 | +| hyst | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 596 to 603 | | 60 to 62 | 59 to 60 / 60 to 62 | yes | 0 to 0 | 0 | +| hyst | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 160 to 342 | | 14 to 60 | 12 to 50 / 0 to 60 | yes | 0 to 0 | 0 | +| hyst | 40/40/20 honest | 360 | 0 | | never | never / never / never | yes | 0 to 0 | 0 | +| hyst | 60/40 honest | 360 | 0 | | never | 58 to 61 / never | yes | 0 to 0 | 0 | +| hyst | 70/30 honest | 360 | 0 | | never | 0 to 4 / never | yes | 0 | 0 | +| twotier | 50/50 honest, 0% attacker | 360 | 0 | 589 to 603 | never | never / never | yes | 0 | 0 | +| twotier | 50/50 + 20% equivocator (sides 60/60) | 360 | 0 | 653 to 660 | never | never / never | yes | 0 | 0 | +| twotier | 50/50 + 33% equivocator (sides 66.5/66.5) | 360 | 0 | 705 to 715 | never | never / never | yes | 0 to 0 | 0 | +| twotier | 50/50 + 34% equivocator (sides 67/67, the bound) | 360 | 139 to 283 | 713 to 720 | 14 to 78 | 12 to 50 / 0 to 77 | yes | 0 to 0 | 0 | +| twotier | 40/40/20 honest | 360 | 0 | 1056 to 1062 | never | never / never / never | yes | 0 to 0 | 0 | +| twotier | 60/40 honest | 360 | 0 | 516 to 564 | never | never / never | yes | 0 to 0 | 0 | +| twotier | 70/30 honest | 360 | 0 | 523 to 532 | never | 0 to 4 / never | yes | 0 | 0 | + + +P2. The poisoned eclipse (a 34% attacker plus a 20% pool; the eclipsed side holds 54% of total) + +| rule | eclipse h | conflicting final locks | conflicting provisional locks | first conflict, min | locks on the eclipsed side | honest-side stalls during | stalls after heal | +|---|---|---|---|---|---|---|---| +| v2 | 1 | 0 | | never | 0 | 0 | 0 | +| v2 | 2 | 0 | | never | 0 | 0 | 0 | +| v2 | 4 | 0 | | never | 0 | 0 | 0 | +| v3 | 1 | 0 | | never | 0 | 0 | 0 | +| v3 | 2 | 0 | | never | 0 | 0 | 0 | +| v3 | 4 | 0 | | never | 0 | 0 | 0 | +| leave | 1 | 0 | | never | 0 | 0 | 0 | +| leave | 2 | 0 | | never | 0 | 0 | 0 | +| leave | 4 | 0 | | never | 0 | 0 | 0 | +| decay1 | 1 | 0 | | never | 0 | 0 | 0 | +| decay1 | 2 | 17 to 24 | | 109 to 111 | 22 to 24 | 0 | 0 | +| decay1 | 4 | 257 to 264 | | 109 to 111 | 263 to 265 | 0 | 0 | +| decay6 | 1 | 0 | | never | 0 | 0 | 0 | +| decay6 | 2 | 0 | | never | 0 | 0 | 0 | +| decay6 | 4 | 0 | | never | 0 | 0 | 0 | +| hyst | 1 | 0 | | never | 0 | 0 | 0 | +| hyst | 2 | 0 | | never | 0 | 0 | 0 | +| hyst | 4 | 0 | | never | 0 | 0 | 0 | +| twotier | 1 | 0 | 19 to 24 | never | 0 | 0 | 0 | +| twotier | 2 | 0 | 137 to 145 | never | 0 | 0 | 0 | +| twotier | 4 | 0 | 377 to 385 | never | 0 | 0 | 0 | + + +P3. Long honest partitions with view-local weight, 12 days + +| rule | honest split | days | first lock per side, day | conflicting final locks | conflicting provisional locks | first conflict | every pre-heal lock kept | first lock after heal, min | +|---|---|---|---|---|---|---|---|---| +| v2 | 50/50 | 12 | 10.15 to 10.18 / 10.12 to 10.34 | 2890 to 3550 | | 10.22 to 10.35 d | yes | 0 | +| v2 | 60/40 | 12 | 5.15 to 5.27 / never | 0 | | never | yes | 0 to 0 | +| v3 | 50/50 | 12 | never / never | 0 | | never | yes | 0 | +| v3 | 60/40 | 12 | never / never | 0 | | never | yes | 0 to 0 | +| leave | 50/50 | 12 | never / never | 0 | | never | yes | 0 | +| leave | 60/40 | 12 | never / never | 0 | | never | yes | 0 to 0 | +| decay1 | 50/50 | 12 | 0.08 to 0.08 / 0.08 to 0.09 | 34146 to 34212 | | 0.08 to 0.09 d | yes | 0 | +| decay1 | 60/40 | 12 | 0.06 to 0.07 / 0.10 to 0.10 | 33931 to 34254 | | 0.10 to 0.10 d | yes | 0 to 0 | +| decay6 | 50/50 | 12 | 0.77 to 0.77 / 0.75 to 0.78 | 32120 to 32246 | | 0.77 to 0.78 d | yes | 0 | +| decay6 | 60/40 | 12 | 0.52 / 0.92 to 0.93 | 31545 to 31873 | | 0.93 to 0.93 d | yes | 0 to 0 | +| hyst | 50/50 | 12 | never / never | 0 | | never | yes | 0 | +| hyst | 60/40 | 12 | 0.04 to 0.04 / never | 0 | | never | yes | 0 to 0 | +| twotier | 50/50 | 12 | never / never | 0 | 34267 to 34418 | never | yes | 0 | +| twotier | 60/40 | 12 | never / never | 0 | 34094 to 34381 | never | yes | 0 to 0 | + +### 5.3 Q1. Silent weight that keeps mining for 6 hours, then resumes + +| rule | silent weight | silent hours | first lock after the stop, min | stalled while silent | longest gap, min | first lock after resume, min | conflicting locks | +|---|---|---|---|---|---|---|---| +| v2 | 30% | 6 | 0 | 0 to 40 | 1 to 8 | 0 to 0 | 0 | +| v2 | 34% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| v2 | 45% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| v3 | 30% | 6 | 0 | 0 to 40 | 1 to 8 | 0 to 0 | 0 | +| v3 | 34% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| v3 | 45% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| leave | 30% | 6 | 0 | 0 to 40 | 1 to 8 | 0 to 0 | 0 | +| leave | 34% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| leave | 45% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| decay1 | 30% | 6 | 0 | 0 | 1 | 0 to 0 | 0 | +| decay1 | 34% | 6 | 66 to 68 | 134 to 135 | 66 to 68 | 0 to 0 | 0 | +| decay1 | 45% | 6 | 108 to 112 | 217 to 229 | 108 to 112 | 0 to 0 | 0 | +| decay6 | 30% | 6 | 0 | 0 to 40 | 1 to 8 | 0 to 0 | 0 | +| decay6 | 34% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| decay6 | 45% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| hyst | 30% | 6 | 0 | 0 to 40 | 1 to 8 | 0 to 0 | 0 | +| hyst | 34% | 6 | 59 to 61 | 120 | 59 to 61 | 0 to 0 | 0 | +| hyst | 45% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| twotier | 30% | 6 | 0 | 0 to 40 | 1 to 8 | 0 to 0 | 0 | +| twotier | 34% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | +| twotier | 45% | 6 | never | 714 to 722 | 360 | 0 to 0 | 0 | + + +Q2. Acquired keys that sign, stay silent or leave, under v3 + leave 1 h (30 days) + +| bought weight | bought keys | attacker's peak share of the denominator | share at the end | holds the veto (1/3) | stalled checkpoints | conflicting locks | +|---|---|---|---|---|---|---| +| 40% | sign | 39.8 to 39.8% | 30.0 to 30.0% | day 1 to 19 | 0 | 0 | +| 40% | silent | 39.8 to 39.8% | 30.0 to 30.0% | day 1 to 19 | 86402 to 86491 | 0 | +| 40% | leave | 30.0 to 30.0% | 30.0 to 30.0% | never | 119 to 144 | 0 | +| 49% | sign | 48.5 to 48.6% | 30.0 to 30.0% | day 1 to 23 to 24 | 0 | 0 | +| 49% | silent | 48.5 to 48.6% | 30.0 to 30.0% | day 1 to 23 to 24 | 86371 to 86408 | 0 | +| 49% | leave | 30.0 to 30.0% | 30.0 to 30.0% | never | 143 to 188 | 0 | + +Under v3 the silent bought 40 percent stalls every checkpoint of the 30 days (86,402 to 86,491), where `sim/results_v2.md` K at v2 measured 63,307 to 68,716: the frozen table keeps the bought weight in the denominator after the sliding table has aged it out, so a silent buyer pauses finality for a window, not until day 19 to 20. The leaving buyer holds 30.0 percent at most (its own hash), never the veto. + +### 5.4 Reading + +What holds. Every candidate keeps 0 conflicting final locks in every honest partition under two thirds (50/50, 40/40/20, 60/40, 70/30 for 360 minutes) except the fast decay, and every candidate conflicts at the 34 percent equivocator (139 to 612 locks in 360 minutes, the one-third bound of 3.11.2, unchanged). The leave rule's rows equal v3's in every partition, eclipse and equivocator case (no key leaves in those scenarios, which is the point: a partition does not sign leaves) and it is the only candidate that both ends tonight's pause in under an hour (0.04 days at 34, 45 and 50 percent: the one-hour delay) and keeps 0 conflicts in the 12-day splits. + +What breaks. The fast decay (T 1 h, r 0.5/h) conflicts in EVERY 360-minute partition, including 50/50 honest with no attacker (467 to 473 conflicting locks, both sides locking alone at minute 120 to 123, exactly T + 1/(2r) = 2 h) and the poisoned eclipse at 2 and 4 hours (17 to 264 conflicts, the eclipsed side locking the attacker's fork after 109 to 111 minutes); it also fails the 12-day splits in 2 hours (34,146 to 34,254 conflicts). The slow decay (T 6 h, r 1/24 per h) passes every 360-minute row because the decay has not started, then both sides of the 50/50 split lock alone at day 0.75 to 0.78 and the 60/40 at 0.52 and 0.93 (31,545 to 32,246 conflicts in 12 days): the hazard moved to the day scale, not removed. The hysteresis floor keeps the honest splits clean (the 60 side of 60/40 locks alone at minute 58 to 61, 0 conflicts) and reopens the equivocator bound: 20 percent across a 50/50 split gives 565 to 597 conflicting locks from minute 60 (the 13.3 percent bound of 3 October is back after H hours), and it does nothing for tonight's 45 percent departure (the stayers' 55 percent is under its 56.7 percent floor: 30.00 days, the same as v3). The two-tier's provisional tier conflicts in every partition and eclipse (516 to 1,062 provisional locks per 360 minutes, 19 to 385 in the eclipses, 34,000 in 12 days) while its final tier equals v3; it is a report of "the connected majority agrees", never a lock. + +The pass line (0 conflicting final locks in every scenario AND tonight's pause under an hour) is met by one candidate: the departure announcement. v2 would have met the hour on the devnet (35 minutes measured, 31 to 32 simulated at 45 percent) and not on mainnet (7.85 to 8.03 days); v3 meets neither (30.00 days, 120 devnet minutes, the frozen table's expiry, as the live chain is showing at the time of writing: 89.2 percent of the sliding table signing at 19:50Z and no lock). + +### 5.5 The aggregation path tonight (the coordinator's question of 19:3xZ) + +Measured: the 8 VRF-picked aggregators are drawn by weight (spec S1, fin-fixes); the fallback (any node, 15 DAA after the determination, aggregator `00000000`) produced 64 of the 251 certificates stored between 16:30 and 19:00Z; locks 6824 to 6842 formed while node 1 and the observer were down; the observer's node received 75 then 79 of 93 voters' votes through its 3 peers during the pause. The star the fleet forms is around the seed (`docs/bench-log.md`, the finality route: "on a Vast box the seed is the only peer"), not the Mac; if the seed fell, a one-peer box would lose blocks as well as votes, and the right fix is a peer floor (at least 4 outbound peers from the address book before a node reports synced), which is lane 5's bandwidth and p2p lane. Model of P(certificate | hub down) under the rule as written: with the fallback, a certificate forms whenever any node connected to two thirds of the signing weight exists, so the probability is 1 for any topology in which votes reach any node; without the fallback and with a star through the hub it is 0 for 8 aggregators or 800. The rule is already the right one; the harness case to add is `tools/finality-attacks` s4's shape (the eclipse) with the hub cut instead of a pool: N boxes peered to the seed and the hub, the hub killed for 300 s, pass line a lock within 2 checkpoints of the cut while two thirds of weight stays connected through the seed, and 0 conflicting certificates at the hub's return. Vote bytes per checkpoint are in 3.3 (26 KB at 93 voters, 2.3 MB at 8,192 single, about 1.2 KB aggregated). + +## 6. Ranked proposals + +| Rank | Proposal | Evidence | Model | Hours | Consequence per tier | Gate | +|---|---|---|---|---|---|---| +| 1 | The departure announcement (candidate iv): a `leave` item (key, DAA score, signature) carried in blocks; D = 1 h after inclusion the key is in no denominator (sliding and frozen) and its votes are invalid; the fleet and app send it on a clean stop | tonight's pause (3.1): 42.7 percent left in three minutes and the frozen table held finality for a window; sim T: first lock 1 h after the departure at 34, 45 and 50 percent, 0 conflicts in every P row, Q2: leaving bought keys gains the attacker nothing | section 4.2 arithmetic; `finality_horizon.py` `leave` | 6 (spec text 3.1 W7 and 3.3; node: the item, its carriage, `voters_at` and `frozen_table` exclusion, unit test; app and fleet library: send on stop; fast-time harness case) | home miner, rig: the app sends the leave on Stop, so a clean exit never holds the network; a crash still ages out over 30 days (v3) unless the operator sends the leave on return, which the app offers; pool: one leave per server on maintenance; holder: fewer and shorter pauses; rollup customer: the same; node operator: one more item type | harness: 45 percent of weight stops with leaves, first lock within D + 1 checkpoint, 0 conflicts in the 50/50 and 60/40 splits and the 34 percent eclipse; sim T and P rows reproduced on the node | +| 2 | Operational rule, no protocol change: a standing box never leaves the live chain for an experiment, and any orchestrated departure over 10 percent of weight is staged in slices under 10 percent an hour | the rehearsal took 36.5 percent at once; sim L2 and M4: a gradual departure costs nothing (every lock re-freezes the table) | spec 3.7 item 2 | 1 (the fleet library refuses to swap a standing box's chain; a `--slice` on the rehearsal script) | fleet operator: the swap takes longer; everyone else: no pause | the next rehearsal: `finality_active` stays true throughout | +| 3 | Aggregate-first vote verification and aggregated in-block carriage as the mainnet default (spec 3.4.2 item 2, decided) | 4.3: per-vote verification is 1.6 s per checkpoint per node at 1,000 voters and 13 s at 8,192 (approximate); the crate already has `aggregate` and `fast_aggregate_verify` | 4.3 table | 8 (node: batch the votes for one (index, hash) and verify once, bisect on failure; the in-block aggregate item; measure on the fast-time harness at 1,000 synthetic keys) | home miner, rig, pool: a node that stays under one core at 1,000 voters; node operator: the same; holder: lock delay flat at 2 to 3 s to 8,192 voters | fast-time harness with 1,000 and 8,000 synthetic voters: lock delay p50 under 3 s, CPU under 25 percent of one core, 0 conflicts | +| 4 | Report the two-tier state (candidate ii) as `finality_provisional` beside `finality_active`, never as a lock | sim P: 516 to 1,062 provisional conflicts per 360-minute partition, 19 to 385 per eclipse, about 34,000 in 12 days, final 0; sim T: provisional 0 to 0.2 devnet minutes after tonight's departure | 4.1 | 3 (node RPC field, explorer and wallet copy; spec 3.9 row) | exchanges: a third row in the guidance table ("provisional: proof of work plus a majority of the connected weight; credit nothing on it"); a holder sees why the pause is a pause | the explorer shows the field through a forced pause on the devnet; the guidance text reviewed by an operator (O-3.13) | +| 5 | The ZK light client's circuit as a phase-two design doc with a cycle measurement | 4.5: 15 to 35 M cycles per step, approximate; the pairing is the term to measure | `lightclient_cost.py` | 10 (an SP1 guest that verifies one certificate at 93 and 1,000 voters with the Fp2 precompiles; cycle count on the 5090 and a 12 GB card) | phone, bridge, rollup customer: the per-year columns of 4.5 become one proof; prover tiers: a steady 30-s job | measured cycles within 2x of the estimate; proof per checkpoint under 30 s on a proving-only 5090 | +| 6 | Hub-cut harness case for the aggregation path | 5.5: the fallback carried 26 percent of tonight's certificates; the seed, not the Mac, is the fleet's star | 5.5 | 3 | fleet operator: a proven answer to tonight's question | the case passes as written in 5.5 | +| 7 | Do NOT adopt the decaying denominator (i) or the hysteresis floor (iii) | sim P1 and P3 (5.2): decay1 467 to 473 conflicting locks in a 360-minute 50/50 honest split and 34,146 to 34,254 in 12 days; decay6 31,545 to 32,246 in 12 days; hyst 565 to 597 at a 20 percent equivocator from minute 60 | 4.2 | 0 | a holder keeps the one-third bound in every view | none: a negative result | +| 8 | Do NOT make prover attestations a lock condition before the coverage gate | 4.6: coverage 2.4 to 4.7 percent tonight, lag p99 62 s | 4.6 table | 0 now; 12 after the gate | holder: no new pause source; rollup customer: nothing lost, the four-state reading exists | 99 percent of blocks proven within 60 s for 7 days, 3 provers per block | + +**1. The departure announcement.** Tonight's cost was a window-long pause caused by keys that left on purpose, under a job that knew it was taking them. The frozen table (F21) exists so that a side of a partition cannot fill its own table, and it does that; its price is that it cannot tell a departure from a partition. A signed leave is the one thing a departing key can give that a partitioned key cannot: it is seen, not inferred. Section 4.2 shows the one-third bound survives it in both halves of a split, the sim shows 0 conflicting locks in every partition, eclipse and equivocator row under it and a first lock one hour after a 34, 45 or 50 percent departure where v3 waits 30 days, and Q2 shows an attacker who buys keys to leave them is worse off than one who signs with them. The hour is a parameter: it must exceed the certificate relay plus one presence of the leave in blocks (minutes), and shorter is better for the operator; one hour matches the merge-depth bound and gives a key that leaves by mistake time to see it. What it does not cover: a crash, a power cut, a region going dark, which still age out as today; the app's Stop button and the fleet library send the leave, and a node that restarts after an unplanned outage can send it on return to shorten the pause from that point. + +**2. Staged departures.** Every lock re-freezes the table, so weight that leaves while locks continue ages out of the frozen table as it ages out of the sliding one (M4's "gradual departure costs nothing"). Ten percent an hour keeps the stayers over two thirds at every step for any total departure under a third per three hours. This is a fleet-library rule, one afternoon, and it would have kept tonight's finality on without any protocol change; proposal 1 covers the case where staging is not possible. + +**3. Aggregate-first verification.** The delay data of 3.2 is flat to 93 voters because the devnet's cost is the poll and the pump, not the pairings; the arithmetic of 4.3 says the pairings take over near 1,000 voters and break the 30-s cadence near 8,192. The crate the fork already uses has both halves of the fix; what is missing is the batching in `ingest` and the in-block aggregate item that 3.4.2 item 2 proposes. The gate is a synthetic-voter harness, which `tools/finality-attacks` can host (its `lib/net.mjs` starts nodes; a vmine with 1,000 keys is a flag away). + +**4. The two-tier report.** The provisional tier is the active-denominator rule the project rejected on 3 October, and the sim says again why: it conflicts in every partition. As a reported state it is useful to a holder who wants to know whether the pause is a silent third (provisional true: the connected majority still agrees) or a split (provisional conflicting on the two sides), and useless to an exchange, which must credit nothing on it. Three hours, mostly copy. + +**5 and 6** are measurements with a design attached, priced above. **7 and 8** are the negatives this lane is confident about: a denominator that shrinks on silence is the 3 October rule under another name, and a lock that waits for proofs is a lock that pauses whenever the proving market is thin, which it is. + +## 7. Open questions and what could not be run + +- The fleet wrote no lock-delay or voter-count row by 19:45Z (`block-rate-devnet2.md` is a template); the 93-voter figures here are node 1's own log. When RUN_A and RUN_B land, the 10 blocks/s row should be checked against 4.3's claim that the hop term, not the voter term, sets the delay. +- The leave item does not exist in the node; the harness case of proposal 1 is designed, not run. Its interaction with W5 succession (O-3.11) and with a key that leaves and keeps mining (its blocks earn nothing, as the spec says for a succeeded key) needs the spec text. +- BLS costs are approximate (crate benchmarks from memory, anchored by one measured JavaScript run). A `cargo bench` of `fast_aggregate_verify` at 93, 1,000 and 8,192 keys on the Mac is one hour and belongs with proposal 3. +- The ZK light client's pairing cost in SP1 6.8.1 is the number the whole of 4.5 turns on; it is approximate until the guest of proposal 5 is counted. +- The pause's end was not observed at the time of writing (expected about 20:40Z at the frozen table's expiry, or earlier if the departed boxes return); the observer rows will show which. +- The box ran the sims at nice 19 under other agents' load; the tables are counts and days, not timings, so the load does not touch them. + +## 8. Summary for the coordinator + +Tonight's finality pause (first unlocked checkpoint 6843 at about 18:40Z, still paused at 19:30Z) is the two-thirds rule doing what it says, then the frozen table doing what F21 asked: 20 keys holding 42.7 percent of the frozen table left the live chain, the stayers held 53.1 percent at the first unlocked checkpoint and 74.9 percent of the sliding table from 19:14:53Z, and only Q5 explains why 74.9 percent did not lock; certificates formed through the hub outage and the aggregator fallback carried a quarter of them, so the topology hypothesis is refuted. The three findings: (1) under v2 the pause would have ended at 19:14:53Z, 35 minutes in, and on mainnet the same event is 7.7 days (v2) or 30 days (v3); (2) of the four candidate rules only the departure announcement keeps the one-third bound (0 conflicts in every partition row, first lock one hour after the departure), while decay and hysteresis reopen the double lock and the two-tier is a report; (3) renting a veto costs USD 8,424 x N x 0.52 for 30 days (USD 4,300 per GH/s of network), locking alone 2.03 x N for 30 days, and bought keys cost the same and decay in 30 days. diff --git a/docs/analysis/horizon/frontier.md b/docs/analysis/horizon/frontier.md new file mode 100644 index 000000000..db333c5d8 --- /dev/null +++ b/docs/analysis/horizon/frontier.md @@ -0,0 +1,675 @@ +# Horizon lane 7: frontier. Predictions to 2030, what no proof-of-work chain has shipped, and what Igneum can + +6 October 2026, evening UK. Lane 7 of the Horizon programme. Worktree `/Users/joshm/Projects/igneum-wt-horizon` (branch `horizon`, at origin/master 3f4f719). the project lead's words: "research anything else that we can research too, predictions, forward thinking, what we can actually do that has not been done or applied, think outside the box", and "be revolutionary". Main's bar: not features, but ideas that change what a proof-of-work chain is or what a GPU owner is to the world, each with its evidence, cost, gate, and the attack a Monero or Kaspa core developer would mount. I argue each attack as the project's own four personas would hear it (`.claude/agents/cryptographer.md`, `consensus-engineer.md`, `execution-engineer.md`, `miner-community-lead.md`). + +Nothing in this file is a prediction of the coin's price, an offer to sell anything, or a change to any consensus parameter. Every chip figure is arithmetic on cited memory and logic figures; every GPU figure names its bench entry; a figure from memory says approximate. No em dashes. + +**Read for grounding:** `docs/spec/00-overview.md`, `05-fees-and-economics.md`, `07-execution.md`, `09-pool-protocol.md`, `10-light-client.md`; `site/litepaper.html` (whole page, including "What Igneum does not claim"); `docs/fud-ledger.md` sections 3 (P1 to P10 present in the file; P11 to P23 are cross-referenced from the spec and round-3 entries), 4 (E1 to E8), 6 (C1 to C12), 9 (D1 to D6); `docs/commercial/prover-customer-brief.md`; `docs/design/payment-routes.md`, `developer-adoption.md`, `execution-layer.md`; `docs/analysis/chip-model-v3.md` sections 5 to 6; `docs/plans/counter-asic-3-status.md` section 4; `docs/analysis/prover-tiers-real-cards.md` (eleven rented cards, 6 October); `docs/analysis/economy-2026-10-04.md`; `docs/analysis/security-budget.md`; `docs/bench-log.md` line 2582 (rental cost of hash, measured 6 October); `vendor/rusty-kaspa/consensus/core/src/config/params.rs` (main checkout). `block-rate-devnet2.md` was still a template at 22:00 UK (RUN_A and RUN_B empty); nothing here depends on it. + +**Model:** `sim/horizon/frontier/frontier_model.py` (pure Python, no numpy, about 50 ms; `python3 sim/horizon/frontier/frontier_model.py > sim/horizon/frontier/out.md`). Every table below marked "model" is printed by it; its `INPUTS` block labels each input measured, cited, designed or approximate with the source. Not run under the lock: it is arithmetic, not a measurement. + +--- + +## 0. Everything ranked by payoff over difficulty + +Payoff 1 to 5 is what the idea does for the chain's security, the coin's utility or the GPU owner's position in the world, if it works. Difficulty is Claude-side hours to a measurable prototype (the project lead's rule: hours, never weeks). Verdicts: do now, prototype, watch, never. The "never" rows carry a sharp reason so the rest are not fantasy. + +| Rank | Idea | Payoff | Hours | Verdict | One line why | +|---|---|---|---|---|---| +| 1 | 3.3 The weight table carried inside the recursive segment proof: a consensus proof at mergeset cost, so a browser verifies finality from one proof and asks no node for the voter set | 5 | 60 | do now (design and guest prototype) | Phase two's hardest item becomes incremental: each segment proof updates W2 by its own blue blocks; the cost is one BLS aggregate verify per 30 s inside the zkVM, which SP1 has precompiles for (approximate) | +| 2 | 3.2 Work-stake: vote weight as the external-job bond | 5 | 24 | prototype | A bond nobody can buy: 30 days of blocks. The at-risk pool income is thousands of IGN against a 0.0015 IGN coin bond (model section 3); the design stays "no stake" because weight is work, not coins | +| 3 | 3.7 Reproducible-build attestations in a registry contract; Ember refuses a release under N of M attestations | 4 | 12 | do now | Bitcoin's guix.sigs with the chain as the sigs repo; closes the devnet's "release key acts as operator" sentence (litepaper, Governance) | +| 4 | 3.4 A WebAssembly verifier of the wrapped block proof in the tab | 4 | 16 | do now | Three working precedents (a16z Helios WASM, ProjectZKM ziren-wasm-verifier, xycloo wasm-groth16-verifier); the certificate half already runs at 58 to 155 ms (bench-log) | +| 5 | 3.8 Ember as node, wallet and light client for everyone: node count equals miner count | 4 | 20 | do now | 1,000 testnet miners become 1,000 verifying nodes; Monero shows about 5,000 peers in 72 h (monero.fail), Ethereum 8,136 execution nodes (ethernodes); Sybil counts are irrelevant here because nothing counts nodes | +| 6 | 3.15 A 30-s randomness beacon from the checkpoint VDF | 4 | 24 | prototype | The pipeline exists (10-min VDF, 4.47 ms verify); a drand-class beacon with no league and 120x drand's latency; honest limit is the class-group ASIC (Chia timelords) | +| 7 | 3.1 The reward rule that prices rented hash out (pay per block falls when hash arrives faster than the 30-day weight) | 4 | 40 | prototype | Doubles the renter's break-even price (model section 2) and routes the cut to the proving pool, not to incumbents; the cost is a 30-day income ramp for honest newcomers, which the vote already imposes | +| 8 | 3.5 Continuous miner-voted parameters, bounded per block like Ethereum's gas limit, for `B_p`, the floors and the window | 3 | 30 | prototype | Replaces two-week 60 percent proposals with a drift anyone can read on the chain; Kaspa's Crescendo was a fixed DAA score (`params.rs:648`), Bitcoin's BIP9 a 95 percent tally; neither moves a number continuously | +| 9 | 3.16 The hourly program swap as a research dataset and the fleet library as a product | 3 | 10 | do now | 8,760 random kernels a year, compiled on three vendors with per-variant timings; compiler and GPU-architecture researchers have no such corpus; income small, standing large | +| 10 | 3.13 Igneum as the settlement layer for GPU rental | 3 | 40 | prototype (escrow plus sampled verification) | The chain's fee is 3 to 5 orders under a 7 to 15 percent platform take (model section 5), but it can settle only what it can verify; the verifiable subsets are named | +| 11 | 3.6 Treasury-less audit funding: burn-redirect bounties by 60 percent signal, review escrow on upgrade proposals | 3 | 20 | watch | The money exists only when the chain is used (USD 1,600 to 16,000 per 30 days at launch traffic, model section 4), and it is the switch spec 5.5 removed, with a veto | +| 12 | 3.14 Proofs sold to AI labs for verifiable inference | 2 | 40 | watch | zkLLM: 803 s of proving per forward pass on LLaMA-2-13B (arXiv 2609.27367 citing 2404.16109); the competitor is a USD 0 TEE attestation on H100-class cards the fleet does not own | +| 13 | 3.9 Hardware wallets that verify proofs | 2 | 12 | never on the secure element; do the companion verify | A bn254 pairing on a Cortex-M-class secure element is seconds to minutes (approximate); Ledger and Trezor do their heavy work in the companion app, and Igneum Wallet already verifies certificates with the node's code | +| 14 | 3.12 The fleet as a public compute market (rendering, inference) priced in IGN | 2 | 60 | never for unverifiable work; do for the verifiable subsets | An escrow without a verifier is a trust-me payment with lower fees; Render uses result quorums, Akash reputation, io.net attestations (secondary), none of which a chain can check | +| 15 | 3.11 Miners paid for proving others' chains as the main income, the lottery a tiebreaker | 1 | 0 | never by 2030; watch | All of Ethereum L1's proving at the Sep 2026 tracker cost is USD 36 a day; Igneum's year-1 emission is USD 13,700 a day at 0.005 (model section 7); demand must grow 1,000x against a cost curve falling 3x to 30x a year | +| 16 | 3.10 Proof-of-useful-work: the lottery hash partly a proof | 1 | 0 | never | Every coupling of leader election to proving re-opens Aleo (fastest prover wins); Ball et al. 2017 and Ofelimos 2022 show the sampleability conditions, and zkVM proving meets none of them | + +Predictions (section 2) are not ranked; they are inputs. The three ideas a Monero or Kaspa core developer would not have thought of are 3.2, 3.3 and 4.3 (the hourly program as a hardware census), argued in section 4. + +--- + +## 1. Method + +Three kinds of work: + +1. **Trend lines with arithmetic.** Each 2030 prediction has a cited anchor (a product page, a tracker, a standards body, a secondary analysis labelled as such) and a formula in the model script. Where the trend is from memory (consumer VRAM generations) the row says approximate. +2. **Idea arithmetic.** For the five ideas whose value depends on numbers (the rental tax, work-stake, the burn bounty, rental settlement, the proving-income ceiling) the script prints the table and the document reads it. The attack costs use the measured rental entry (`docs/bench-log.md` line 2582: 1,748 MH/s for USD 20.44 an hour, USD 0.0117 per MH/s-hour, about USD 11.69 per GH/s-hour) and are given per GH/s and evaluated at 1, 10, 100 GH/s and 1 TH/s, as the brief asks. +3. **Prior art.** WebSearch on 6 October 2026 for every idea; the paper or repository that tried it is cited, or the idea is marked "new" when none was found. Claims about other chains cite the repository file when a clone exists in the main checkout (`vendor/rusty-kaspa`) and are marked "not cloned, approximate" otherwise. + +No simulator in `sim/` was re-run and no node harness was started: every idea here is a design question whose first gate is a measurement named in its section, and tonight the fleet, PC 1, PC 2 and the devnet were in use for the class v4 rehearsal and the Devnet 2 block-rate runs. What I could not run is listed in section 6. + +--- + +## 2. Predictions to 2030 + +Each row: the trend, its anchor, the arithmetic, and what it does to the chip model and the proving tiers. Tables marked model are `frontier_model.py` section 1. + +### 2.1 GPU memory per card + +| Year | Flagship consumer card | GB | Label | +|---|---|---|---| +| 2016 | GTX 1080 | 8 | approximate (from memory) | +| 2018 | RTX 2080 Ti | 11 | approximate | +| 2020 | RTX 3090 | 24 | approximate | +| 2022 | RTX 4090 | 24 | approximate | +| 2025 | RTX 5090 | 32 | cited (`chip-model-v3.md` 5.1: 16 x 2 GB GDDR7 on 512 bits) | + +Compound growth 1.167 a year (4x in 9 years). Extrapolated: 51 GB in 2028, 69 GB in 2030 (model). The module arithmetic is sharper than the curve: a 512-bit board is 16 devices; Micron has ended 2 GB GDDR7 (TrendForce, 24 September 2026, via `chip-model-v3.md` 5.1) and 3 GB devices are USD 60 to 70, so the next flagship is 48 GB (16 x 3 GB) and 64 GB is the 2030 shape. The RTX 60 series on Rubin (GR20x) is reported for 2028 after two slips (kopite7kimi via videocardz.com and thepcenthusiast.com; rumour, not a product). Datacentre: HBM4 at 36 GB per 12-high stack, 288 GB per GPU on Rubin NVL72 (Wikipedia HBM page, Micron March 2026 production). + +What it does to the chip model: nothing for the stored-dataset chip (f = 1), whose memory is already 24 to 32 GB against a dataset of 2 GiB growing to 4 GiB at year 4 (`chip-model-v3.md` 5.7: dataset size is "not a lever against this chip"). What it does for miners: the dataset schedule (2 GiB, doubling at years 4, 12, 28; litepaper) stays under every card from 8 GB for twelve years, and the proving side, not the mining side, is what wants VRAM (section 2.6). + +### 2.2 Memory dollars per GB + +| Point | USD per GB | Source | +|---|---|---| +| 2023, GDDR6 | 3.38 | Tom's Hardware, "GDDR6 VRAM prices plummet", USD 27 per 8 GB | +| 2025, GDDR6 | 2.50 | TechSpot, "AI is eating all the DRAM" (2026) | +| 2026, GDDR6 | 3.30 | TechSpot, same | +| Sep 2026, GDDR7 2 GB device | 10.00 | TrendForce via `chip-model-v3.md` 5.1 | +| Sep 2026, GDDR7 3 GB device | 21.67 | TrendForce (USD 60 to 70 per device) | +| Oct 2026, HBM3E 36 GB stack | about 8.3 | siliconanalysts.com/data/hbm-pricing (factory gate; contract about 2x), approximate | +| Oct 2026, HBM4 36 GB stack | about 15.3 | siliconanalysts.com (USD 550 per stack); Samsung quoting USD 4.50 to 4.90 per Gb for HBM4 against 1.50 for HBM3E (BigGo Finance), approximate | + +GB per dollar fell in 2026 for the first time in a decade and DRAM supply is forecast tight through 2027 with new fabs in 2028 (SoftwareSeni "HBM4 delays and GDDR7 shortages"). Memory is reported at 70 to 80 percent of the bill of materials of high-VRAM consumer cards by late 2025 (BuySellRam, secondary). + +What it does to the chip model: the f = 1 chip and the GPU buy the same devices, so the ratio of their memory bills is fixed; what moves is the share of each bill that is memory. The chip's bill is about 70 percent memory (USD 320 of USD 470, `chip-model-v3.md` 5.4) and the 5090's about 16 percent at MSRP (USD 320 of USD 1,999) or 9 percent at the 2026 street price of USD 3,695 (localaimaster.com). A doubling of device prices raises the chip's cost 1.7x and the card's 1.1x to 1.2x: **the stored-dataset chip gets dearer relative to the GPU through 2027**, and the dollars-per-MH/s row (USD 2.8 against 14.7 at MSRP, 5.4 against 27 at street prices) narrows a little and no more. The per-joule row does not move at all, and per joule is where the chip wins (section 2.3). + +### 2.3 Random-read bandwidth: GDDR7, HBM3E, HBM4 + +The lottery is latency-bound: one hash advances one dependent 4-byte read per memory latency, so the number that matters is random reads per second per watt, not GB/s (`chip-model-v3.md` 5.3 and 5.5). That ceiling is set by bank count and activate windows (tRC, tFAW), not by pin speed, so 48 Gbps GDDR7 is 28 Gbps GDDR7 here, and HBM3E is HBM3. + +| Memory system | Reads/s ceiling | Why | Label | +|---|---|---|---| +| GDDR7, 16 devices, 512-bit (the 5090 board) | 21.3 G | 4 activates per 12 ns per channel x 64 channels | approximate (`chip-model-v3.md` 5.3) | +| RTX 5090 measured | 17.5 G | 82 percent of the ceiling | measured (bench-log Counter ASIC 2.0) | +| HBM3 or HBM3E, one stack | 10.7 G | 16 channels | approximate | +| **HBM4, one stack** | **21.4 G** | JEDEC JESD270-4 raises channels per stack from 16 to 32, each with two pseudo-channels (allaboutcircuits.com, EDN), which doubles activate parallelism if tFAW per channel holds | approximate, derived (model 1.3) | +| A 48 GB GDDR7 board | 21.3 G | capacity does not add channels | approximate | + +The f = 1 chip in 2028 on HBM4 (model 1.4; every figure arithmetic, approximate): + +| Chip | MH/s per chip | W bare / with a 150 W shadow core at k = 1 | uJ per hash bare / shadow | Gain per joule vs the 5090 bare (2.40 uJ) | Gain under the class v4 shadow (card 2.95 uJ at N = 100,000) | +|---|---|---|---|---|---| +| GDDR7 f = 1 (today's row) | 166 | 78 / 228 | 0.47 / 1.37 | 5.1x | 2.2x | +| HBM3 one stack | 84 | 27 / 177 | 0.32 / 2.12 | 7.5x | 1.4x | +| HBM4 one stack (2028) | 167 | 36 / 186 | 0.22 / 1.11 | 11.0x | 2.6x | + +**Prediction:** HBM4 doubles the stored-dataset chip's rate per stack at about the same watts, so its bare per-joule edge rises from about 7x to about 11x, and under the class v4 shadow from about 2.3x to about 2.7x. The lever that answers it is N, the program work in the latency shadow: at N = 200,000 the HBM4 chip reads 1.74x at k = 1, at N = 330,000 (the 5090's full ALU budget) 1.33x (model 1.4). The verifier cost is N x 32 ops per warp: about 1 ms at N = 100,000 on one M5 Max core (measured class, counter-asic-3-status item 8), about 3 ms at 330,000, inside the 10 ms gate; the 2019-class core is unmeasured (O-1.14). + +**Consequence and proposal (for the coordinator, not a change tonight):** write the schedule for N into the era draw at genesis, the way the dataset size already is: a candidate is a doubling of N per era until the verifier gate binds (about 1,000,000 ops, 10x of headroom on the M5 Max). The memory generation it answers arrives every two to three years and the chain must not need a human release to answer it. Per tier: no hash-rate cost while cards stay latency-bound (the M5 Max binds at about 290,000, the 9070 XT at about 650,000, approximate), watts up toward TGP (a 5090 from 326 toward 575 W, which the Ember power cap already manages), a verifier cost nodes and pools pay in milliseconds. + +### 2.4 Price per card + +| Card | Launch MSRP | 2026 street | Source | +|---|---|---|---| +| RTX 5090 | USD 1,999 | USD 3,695 to over 5,000 | `chip-model-v3.md` 5.1; localaimaster.com; tech-insider.org ("RTX 5090 tops USD 5,000"), secondary | +| RTX 4090 | USD 1,599 (approximate) | rental USD 0.28 to 0.60 an hour (gpus.io median) | rental cited, MSRP from memory | + +Prediction: consumer card prices track memory prices through 2027 and ease in 2028 when fab capacity lands. For Igneum the price per card matters twice: the honest fleet's capital cost (not in the security budget, which is power only, `security-budget.md` section 6) and the renter's hourly price, which fell to USD 0.21 to 0.44 per 5090-hour on Vast.ai (getdeploying.com, 6 October 2026) even as purchase prices rose, because rented supply is sunk capital. **The rental market, not the purchase market, prices the 51 percent attack**, and the measured entry is USD 11.69 per GH/s-hour at RunPod list prices with the market unable to supply 20 more pods when asked (bench-log line 2582). At a TH/s: USD 11,700 an hour, and no supply. + +### 2.5 The chip-fab cost curve + +| Node | Mask set | Source | Igneum reading | +|---|---|---|---| +| 28 nm | USD 1 to 3 M | TubeTime (3 M); VBsemi (over 1 M) | The f = 1 memory-controller chip: no mixer on the die, a USD 5 to 30 M project (`asic-resistance-history.md` 2.5) | +| 7 nm | USD 10 to 15 M | VBsemi; Hacker News thread | The f = 0 recompute chip with 256 MiB on die: USD 50 to 75 M | +| 5 nm | USD 6.5 M (2026 data) to 30 M (2023 estimate) | siliconanalysts; HN | The shadow core (30 mm^2 at N5 for N = 100,000) drags the f = 1 chip toward this node, or to a reticle-class 28 nm die | +| 3 nm | USD 15 to 22 M (Q4 2025), up to 40 M (older) | siliconanalysts; semianalysis | Not relevant to a chip whose cost is memory | + +Prediction: mask cost at a fixed node falls (5 nm quoted at 30 M in 2023, 6.5 M in 2026) while the leading node rises. So the shadow lever's fab-bill teeth weaken about 4x over three years; what holds in 2030 is the rate and joule arithmetic of 2.3, not the bill. **The stored-dataset chip gets cheaper to design and dearer to populate** through 2027, and the net is roughly flat against the GPU on dollars; per joule it gains with each memory generation unless N grows with it. + +### 2.6 zkVM proving speed per dollar + +| Point | USD per Ethereum L1 block proof | Hardware | Source | +|---|---|---|---| +| Jan 2025 | 1.69 | about 160 RTX 4090s for 90 percent real-time, USD 300 to 400 K cluster | HackMD "Ethproofs 2025 review" (willcorcoran); Succinct SP1 Hypercube blog (May 2025), secondary | +| Dec 2025 | under 0.04 | 16 x RTX 5090 (SP1 Hypercube: 99.7 percent of blocks under 12 s; cluster under USD 100 K); Pico Prism 16 GPUs (Brevis blog, Feb 2026) | same, secondary | +| Apr 2026 | | Cysic Venus 7.4 s on 24 GPUs | bex.co, secondary | +| Aug 2026 | | ZisK p99 9.62 s on 4 x RTX 5090 | GitHub comparative analysis (Ricosworks1), secondary | +| Sep 2026 | about 0.005 | "sub-half-cent" fields on ethproofs | same, secondary | + +The 20-month ratio is 338x, about 33x a year (model 1.6). That cannot continue: it is software catching up with hardware. The table below uses 1.5x, 3x and 10x a year from the shard times measured on eleven rented cards on 6 October (`prover-tiers-real-cards.md`, the v1 shard, 4.7 M cycles). + +| Card | Beside the miner today, s | Alone today, s | 2028 at 1.5x a year (beside / alone) | 2028 at 3x | 2028 at 10x | Under 10 s beside the miner in 2028? | +|---|---|---|---|---|---|---| +| RTX 3060 12 GB | 37.5 | 14.4 | 16.7 / 6.4 | 4.2 / 1.6 | 0.4 / 0.1 | at 3x or more | +| RTX 4060 8 GB (core-only beside) | 22.1 | 18.4 | 9.8 / 8.2 | 2.5 / 2.0 | 0.2 / 0.2 | even at 1.5x | +| RTX 4070 12 GB | 27.3 | 12.1 | 12.1 / 5.4 | 3.0 / 1.3 | 0.3 / 0.1 | at 3x or more | +| RTX 4060 Ti 16 GB | 34.6 | 11.6 | 15.4 / 5.2 | 3.8 / 1.3 | 0.3 / 0.1 | at 3x or more | +| RTX 3080 10 GB | 25.6 | 7.1 | 11.4 / 3.2 | 2.8 / 0.8 | 0.3 / 0.1 | at 3x or more | +| RTX 3090 24 GB | 19.9 | 14.9 | 8.8 / 6.6 | 2.2 / 1.7 | 0.2 / 0.1 | even at 1.5x | +| RTX 4090 24 GB | 26.1 | 6.3 | 11.6 / 2.8 | 2.9 / 0.7 | 0.3 / 0.1 | at 3x or more | +| RTX 5070 12 GB | 37.2 | 4.8 | 16.5 / 2.1 | 4.1 / 0.5 | 0.4 / 0.0 | at 3x or more | +| RTX 5090 32 GB | 10.7 | 6.3 | 4.8 / 2.8 | 1.2 / 0.7 | 0.1 / 0.1 | even at 1.5x | + +**Prediction:** at the floor rate (1.5x a year, which is the GPU hardware cadence alone) only the 24 GB and 32 GB cards mine and prove inside 10 s in 2028; at 3x a year (half the historical software rate) every card from the 3060 up does, and an 8 GB card alone proves in 2 s. **The block-proof target ("under 10 s as provers improve", CLAUDE.md) should be written as a function of the measured fleet median shard time, re-read each era, not as a date.** Per tier: a 12 GB desktop card is the swing tier; under 1.5x it proves alone in under 7 s but not beside its miner, so the hand-off profile (`prover-tiers-real-cards.md`) is the thing to ship, not a bigger card. + +What the cost curve does to the economics: the dollars per proof on the open market fall as fast as the volume rises, which is the arithmetic behind the "never by 2030" of 3.11. + +--- + +## 3. The ideas, one section each + +Each section: the idea in a paragraph; why nobody shipped it (cited, or "new"); what Igneum already has; the model; hours; the gate; the per-tier consequence; the Monero attack; the Kaspa attack; the verdict. + +### 3.1 The reward rule that prices rented hash out + +**The idea.** The pulse attack M14 (a renter arrives, mines for an hour, leaves) is recorded in the ledger and the finality rule already denies rented hash a vote. The reward side is untouched: a renter is paid per block like anyone. The rule: the block subsidy paid to a producer is multiplied by `m = clamp(W30 / H_now, 0.25, 1)`, where `W30` is the 30-day work-weighted hash the finality window already computes (blue blocks per DAA second over the W2 window) and `H_now` the DAA-window estimate. The remainder `(1 - m)` of the subsidy goes to that block's proving-pool escrow, not to incumbents and not to a burn. Fees are untouched. Hash that arrives faster than the 30-day weight can follow is paid less per block until the weight catches up. + +**Why nobody shipped it.** Bitcoin Cash's EDA and every emergency rule since adjusted difficulty, never pay (approximate; the consensus engineer's list). Kaspa's DAA retargets per block over a sampled window (`vendor/rusty-kaspa/consensus/src/processes/difficulty.rs`, main checkout) and pays per block. Monero's RandomX changes what hash is, not what it is paid. Ethash coins and Ergo pay per block. No chain ties the subsidy to the ratio of fresh to sustained hash, because no chain had a sustained-hash number in consensus; Igneum has it in W2. Prior art searched: none found. New. + +**What Igneum already has.** W2 (blue blocks per key over 30 days) and the DAA estimate are both in the node; the proving-pool escrow exists in execution state (spec 7.7 item 6); the emission split is a state transition by rule (design 1.1). + +**The model** (frontier_model.py section 2, the measured rental entry USD 11.69 per GH/s-hour): + +| Network hash | Attacker adds | H_now / W30 | m | Attacker IGN per hour, no rule | With rule | Rent USD per hour | Break-even IGN price, no rule | With rule | +|---|---|---|---|---|---|---|---|---| +| 1 GH/s | 1 GH/s | 2.0 | 0.50 | 57,038 | 28,519 | 12 | 0.00020 | 0.00041 | +| 10 GH/s | 10 GH/s | 2.0 | 0.50 | 57,038 | 28,519 | 117 | 0.00205 | 0.00410 | +| 100 GH/s | 100 GH/s | 2.0 | 0.50 | 57,038 | 28,519 | 1,169 | 0.02049 | 0.04099 | +| 1 TH/s | 1 TH/s | 2.0 | 0.50 | 57,038 | 28,519 | 11,690 | 0.20495 | 0.40990 | +| 10 GH/s | 50 GH/s | 6.0 | 0.25 | 95,064 | 23,766 | 584 | 0.00615 | 0.02459 | + +A renter who doubles the network needs twice the coin price to break even; one who sextuples it needs four times. The diverted subsidy (57,000 to 85,000 IGN an hour in these rows) reaches the provers of the same blocks, who are the sustained population by sortition weight (spec 7.2). The honest-growth cost: a listing that doubles honest hash overnight cuts every miner's subsidy per block in half on top of the halving difficulty already imposes, until W30 catches up (the 30-day ramp of ledger C7, 0.9x by day 28 to 31). The floor 0.25 bounds the worst case at 4x. + +**Hours.** 40: the rule in the coinbase state transition (8), W30 as a consensus value from the window the finality module keeps (8), the economy simulator scenario f with and without the rule (8), the fast-time harness timestamp test (8), spec text and tests (8). + +**The gate.** (a) `sim/economy/sim.py` scenario f (a pool with the network's own hash arriving on day 10): incumbents' income under the rule above the no-rule row for all 30 days, newcomers' below. (b) The fast-time harness with headers back-dated inside Kaspa's 132-s tolerance: `m` moves under 2 percent. (c) Scenario d (a 20 percent operator vanishes): `m` stays at 1 (hash fell, so H_now < W30 and nobody is cut). + +**Per tier.** + +| Tier | Consequence | +|---|---| +| Home miner, 8 to 32 GB | In a doubling month, 25 percent of the pre-event subsidy instead of 50; unchanged in a steady month; a newcomer earns half-rate for its first month, as it votes nothing for its first month already | +| Rig | The same per block; a rig that joins during a listing spike earns half for a month | +| Pool user | The same through PPLNS; the pool's dashboard should show `m` | +| Prover | Gains: the diverted share lands in the pool escrow and is paid by sortition weight | +| Holder | Emission schedule unchanged in total; a larger share of it reaches sustained keys during spikes | +| Rollup customer | Nothing | +| Node operator | One more consensus value (W30) and one multiplier in the coinbase rule | + +**The Monero core developer's attack.** "You have built an incumbents' cartel. Every rule that pays old miners more than new miners entrenches whoever was there first; RandomX exists so that a newcomer with a laptop earns exactly what a veteran earns per hash. Your 'to the pool, not incumbents' is cosmetic: sortition is by weight, and weight is the incumbents. And your W30 is your own finality window, so a 30-day-old farm that goes dark and returns is 'sustained' while a thousand honest newcomers after a listing are taxed for a month. Qubic reached 23 to 34 percent of our hash for weeks in August 2025 (arXiv 2512.01437) by renting and by paying miners in its own token; your rule would have taxed the honest miners who moved to P2Pool to fight it, because they were new keys." Answer: the tax is per block not per key, so moving pools under the same key costs nothing (spec 9.6), and a returning farm's W30 is its own blocks, which it did not make while dark. The entrenchment point stands and is the cost the gate measures. + +**The Kaspa core developer's attack.** "H_now is your DAA estimate and the DAA is manipulable by timestamps inside the tolerance; a producer can lower H_now for its own block by back-dating within 132 s and raise its own m. Second, W30 is a function of the DAG past and differs between two honest tips every second; a reward that depends on it makes two honest nodes disagree about the coinbase amount of the same block unless W30 is read at a fixed ancestor (the checkpoint), and then it lags. Third, you have made emission depend on a window of 2.6 million blocks: your pruning point must now keep that window's per-second counts, which Kaspa prunes." Answer: read both numbers at the block's selected parent's last certified checkpoint (deterministic, in every node's past), accept the 30-s lag, and the timestamp test is gate (b). The pruning point already keeps the W2 window for finality (spec 3), so no new retention. + +**Verdict: prototype.** Doubles the renter's break-even and costs honest newcomers a month of half subsidy, which is the same month the vote already costs them; gate (a) decides whether miners will wear it. + +### 3.2 Work-stake: vote weight as the external-job bond + +**The idea.** The external job market needs a bond because a customer waits (spec 5.4, O-5.6: `maxPgas x f_p x 1.5` in IGN, slashed on a late or bad proof). Replace the coin bond with the key's 30-day vote weight: a key that claims an external job and delivers late or wrong loses a share `s` of its weight for 30 days, the way equivocation strips 100 percent (spec 3.6). Weight is blue blocks. It cannot be bought, borrowed or bridged; it can only be mined, in public, over 30 days. The job market then needs no IGN escrow from the prover, which removes the capital barrier that keeps home cards out of Boundless (ZKC collateral) and Succinct (PROVE staking, docs.succinct.xyz/docs/provers) while keeping a bond larger than either. + +**Why nobody shipped it.** Every proving network bonds in its own token (Boundless: stake scales with aggregate proving work per epoch, docs.boundless.network/zkc/mining/overview; Succinct: stake required to bid, more stake more concurrent auctions). No proof-of-work chain had a non-transferable, slowly earned weight per key until Igneum's finality rule. Decred's tickets are bought with coins; Ethereum's slashing is coins. New. + +**What Igneum already has.** W2 per key, the 30-day strip for equivocation, the sortition that already draws assignees by weight (spec 7.2), the job record format (design 6). + +**The model** (frontier_model.py section 3): + +| Key's hash share | Blocks per 30 days at 1 bps | 30-day pool income at risk, IGN | Lost at s = 25 percent | Lost at s = 100 percent | The coin bond for one 1 B-cycle job at the floor | +|---|---|---|---|---|---| +| 0.01 percent | 259 | 1,643 | 411 | 1,643 | 0.0015 IGN | +| 0.1 percent | 2,592 | 16,427 | 4,107 | 16,427 | 0.0015 IGN | +| 1 percent | 25,920 | 164,271 | 41,068 | 164,271 | 0.0015 IGN | +| 10 percent | 259,200 | 1,642,706 | 410,676 | 1,642,706 | 0.0015 IGN | + +The at-risk amount is five to nine orders of magnitude above the designed coin bond, before counting the lost vote. A late proof must be defined in DAA time against the claim (the P9 decision's 120-s claim timeout is the starting value), with one strike of grace per 30 days so a partition does not strip an honest key on its first miss. + +**Hours.** 24: the strip rule in the finality module keyed by a job-fault record (8), the fault record in the job contract (design 6) with the evidence a node checks (8), tests and a devnet injection script (8). + +**The gate.** Phase 4 devnet: 1,000 jobs with a 10 percent injected late or wrong rate: every injected fault stripped; zero honest keys stripped across a 60-s partition; a customer's job never waits more than the claim timeout plus one open window. + +**Per tier.** + +| Tier | Consequence | +|---|---| +| 8 GB solo miner below dust (under 100 blocks in 30 days) | No weight, so no external jobs under this rule; shards (no bond) unchanged; the pool protocol gives it a route (the pool's key, the pool's weight) | +| 12 to 32 GB home miner above dust | Takes external jobs with no IGN locked; one bad job costs a quarter of a month's sortition income and a quarter of its vote for 30 days | +| Rig | The same, at the rig's weight; the rig operator's whole weight backs each job, so a rig claims only jobs it can finish | +| Pool user | The pool's weight is the bond; the member's share of pool income carries the pool's record | +| Prover | A reputation nobody can buy, visible on chain per key | +| Holder | No IGN is locked in bonds, so no bond capital sits idle | +| Rollup customer | A bond measured in 30 days of public mining instead of a token balance; the customer brief's "your chain's own bond and slashing apply" becomes "Igneum's weight is at stake" once jobs settle on Igneum | +| Node operator | One more strip condition in a module that already strips | + +**The Monero core developer's attack.** "CLAUDE.md says no stake anywhere in consensus. You have just made the vote weight a stake: it is at risk for an execution-layer fault. Whatever you call it, a prover now rationally hedges by splitting its mining across two keys, one that votes and never proves, one that proves and holds dust weight, which your F17 says buys nothing for the vote but buys everything here: the proving key has nothing to lose. So the bond is only real for operators too small to split, which is backwards." Answer: the sortition draws assignees in proportion to weight (spec 7.2 step 2), so a dust key is drawn with probability near zero and the proving key must carry weight to be assigned at all; the hedge costs the prover its assignments. The attack is right that this is a stake of work; the design's "no stake" means no coin balance in consensus, and that still holds. The spec wording needs the distinction. + +**The Kaspa core developer's attack.** "'Late' is not a fact on a DAG. A proof included in a block at DAA score D is late relative to the claim at D minus T only along a chain; a reorg moves D. You will strip a key on one chain and not on another, and the strip is a consensus input to finality. Also, the fault evidence rides in blocks, so a producer who dislikes a prover can withhold its proof for T seconds and then carry the fault record. That is a griefing vector you did not have when nothing waited on a prover (ledger P9)." Answer: the evidence rule must be relative to the carrying block's own chain (as proof records are, spec 7.2 item 5), the deadline must be long relative to merge depth, and the withholding vector is real: a proof gossips to every producer, so withholding needs a majority of producers for T seconds, and a strip is only applied if no block in the carrier's past carried the proof. The griefing cost is one window of a majority, the same bound the finality rule already lives with. + +**Verdict: prototype.** The bond nobody can buy; the two attacks name the wording (work-stake is not coin-stake) and the rule (evidence relative to the carrier's chain) that the prototype must carry. + +### 3.3 The weight table carried inside the recursive segment proof: finality attested by provers, a consensus proof at mergeset cost + +**The idea.** Phase two's consensus proof is scoped as "a zkVM program over the 30-day header window and the vote certificates" (design 7; O-10.8), which is 2.6 million headers per proof and the reason it is phase two. But the segment proof already recurses: segment N verifies segment N minus 1 (spec 7.8 item 1, measured on the 5090). Carry the W2 weight table as a public commitment inside that recursion. Each segment's guest takes the previous segment's committed weight table, adds the blue blocks of its own mergeset per vote key hash (the segment is exactly the mergeset of its chain block, spec 7 terms), ages out the blocks that left the 30-day window, and commits the new table. Every 30 s, when a certificate exists for a checkpoint inside the segment, the guest verifies the BLS aggregate against the table it holds and emits "checkpoint i certified under rule v2 with x percent of total weight". The segment proof then attests both execution and finality, and a light client verifying one wrapped proof learns the certified checkpoint and the state root with no voter set fetched from any node. The provers are the attesters of finality, by construction, with no new role. + +**Why nobody shipped it.** Ethereum's sync-committee light clients (Helios, a16zcrypto.com "Building Helios") trust a committee and fetch it; Succinct's eth-proof-of-consensus (github.com/succinctlabs/eth-proof-of-consensus) proves sync-committee signatures in a SNARK but over a fixed committee, not a weight table that moves with every block. No proof-of-work chain has a weight table to carry. Mina carries a recursive proof of the whole chain but its consensus is stake (approximate, not cloned). The incremental-weight-in-recursion form: new. + +**What Igneum already has.** The aggregator guest with `chain_len` and `prev` (spec 7.8 item 1), the 340-byte `BlockOutput`, the canonical voter list and bitmap (spec 3.10 C3), SP1 with BLS12-381 precompiles (approximate: SP1's precompile set includes bls12-381 field operations; the pairing cost inside the guest is unmeasured), O-10.2 which already asks for a header commitment to the weight table. + +**The model.** Cost per segment: the segment adds at most 180 blocks per chain block at 1 BPS (mergeset limit, spec 7.1) times `N = 8` chain blocks, so about 1,440 table updates (a hash-map add and an age-out) per segment, which is negligible beside the execution; plus one BLS aggregate verification per certificate, at most one per 30 s. The BLS verify is the cost: G1 aggregation of up to V keys and one pairing. In SP1 with the bls12-381 precompiles a pairing is of the order of tens of millions of cycles (approximate, from memory of the precompile benchmarks; unmeasured here), so at 1 pgas = 1,000 cycles it is tens of thousands of pgas, about one shard's budget (`S_p` 30,000 pgas) per 30 s. That is a real cost: about one extra shard per 30 blocks, 3 percent of proving capacity at launch traffic. The table commitment is 32 bytes in the public values; the voter list for a 10,000-key table is 10,000 x 60 bytes = 600 KB of witness per segment, which gossips with the shard witnesses (design 5.1: witnesses are not consensus data). + +**Hours.** 60: the guest's table update and commitment (16), the BLS verify inside the guest and its cycle count on the 5090 (16, needs PC 2 or a fleet box), the light-client path that reads the certified index from the public values (8), the spec text for 7.8 and 10 (8), a fast-time run where a partition's two certificates are both presented to the guest and it accepts one (12). + +**The gate.** (a) Cycle count of one certificate verification inside the guest under 50 M cycles on the pinned SP1 (so under two shards). (b) The browser card (spec 10.8) shows "voter set: verified" with no node asked for the set. (c) The fast-time C4 scenario (a certificate over a chain the node is not on, `docs/fud-ledger.md` C4 sweep): the proof refuses a certificate whose signers' weight at that block is under 2/3 of the table it carries. + +**Per tier.** + +| Tier | Consequence | +|---|---| +| Home miner, any card | Nothing changes in mining; a 12 GB prover's shard gets the certificate verification about once in 30 shards | +| Rig, prover | About 3 percent more proving work at launch traffic, paid from the same pool; the aggregator's record grows by 32 bytes | +| Pool user | Nothing | +| Holder, wallet user | A phone or tab verifies "locked" from one proof and trusts no node for the voter set; the spec 10.1 row "voter list from nodes" is deleted | +| Rollup customer | The bridge on Ethereum verifies one wrapped proof and needs no relayer or committee: this is the proof bridge of spec 7.3, delivered earlier | +| Node operator | The witness gossip carries the voter list per segment (600 KB at 10,000 keys) | + +**The Monero core developer's attack.** "You have moved finality's safety from a BLS signature every node checks to a SNARK every node trusts. A soundness bug in SP1 (ledger P7) now forges not only a state root, which full nodes veto by native execution, but a certificate, which full nodes cannot veto because they verify the real BLS certificate separately and will disagree with the proof. Which do you believe? And your 2/3 test inside the proof is against a table the proof itself computed; a bug in the table update is a bug in finality, and it ships in a guest program, not in node code anyone reads." Answer: full nodes keep verifying the BLS certificate natively and the native-execution veto extends to the public values (a record whose certified index or table commitment differs from the node's own is invalid, spec 7.2 item 5 as written), so a forged certificate is, as for state, a light-client problem and never a chain split. The table update is a second implementation of W2 and must be differential-tested against the node's (gate c). + +**The Kaspa core developer's attack.** "The weight table is defined over the block's DAG past (W2 counts blue blocks in the past of the chain block); your segment is the mergeset of chain block C in GHOSTDAG order, so the incremental update is only correct if every block in the window is in exactly one segment's mergeset, which holds for blue and red blocks of the selected chain's mergesets, but a reorg of the selected chain re-cuts the segments and the table must be re-derived from the fork point. Your proof chain breaks at every reorg deeper than one segment, and at 10 BPS with k = 124 a reorg of 8 chain blocks is ordinary." Answer: correct, and the recursion already restarts at an unproven segment (spec 7.8 item 7, the unproven rule); a reorg deeper than a segment invalidates the records of the abandoned chain as it does today. The table commitment must therefore be part of the statement per chain block, re-proven on the new chain, which is what re-proving the segment already does. The cost at 10 BPS is the open question for the gate. + +**Verdict: do now (design and guest prototype).** It turns phase two's hardest item into an incremental one on code that exists, and it is the only road to "your browser verifies Igneum" with no node in the trust row. + +### 3.4 A WebAssembly verifier of the wrapped block proof in the browser + +**The idea.** The homepage card verifies a BLS certificate in JavaScript today (58 to 68 ms warm, 139 to 155 ms cold, bench-log round 6, P3). Ship the other half: the Groth16 or Plonk wrapper of the segment proof verified in WebAssembly in the tab, with the measured millisecond count shown. + +**Why nobody shipped it on a proof-of-work chain.** Because no proof-of-work chain proves its blocks. The working precedents are rollup-side: ProjectZKM's `ziren-wasm-verifier` (github.com/ProjectZKM/ziren-wasm-verifier: "Verify STARK, Groth16 and Plonk proofs in browser", one Rust codebase to native and WASM), xycloo's `wasm-groth16-verifier` (github.com/Xycloo/wasm-groth16-verifier, with a live demo), a16z's Helios shipped as `@a16z/helios` on npm with WASM bindings (github.com/a16z/helios issue 76 and the npm package). + +**What Igneum already has.** `site/verify/core.js` (BLAKE2b header hashes, canonical voter list, BLS aggregate over `@noble/curves`), the SP1 light verifier as a 58 MB native binary (bench-log, "the program id split"), the `wrap` step in the `ProofSystem` trait (design 5.6) unbuilt. + +**The model.** A Groth16 proof over bn254 is three group elements, about 128 bytes compressed (spec 10.5, approximate); verification is one multi-pairing. In WASM a bn254 pairing is of the order of 10 to 50 ms on a laptop core (approximate, from the ziren and xycloo demos' order of magnitude; unmeasured here). Bytes per day in phase two on-demand mode: 800 bytes per open (spec 10.5). + +**Hours.** 16: wrap the pinned aggregator proof to Groth16 with SP1's wrapper on a 24 GB fleet card (8, the P3 phase 2 benchmark brought forward), compile the verifier to WASM and wire it to the card (8). The wrapper's own cost on consumer hardware is the open measurement R4. + +**The gate.** The card shows the wrapped proof verified in the tab, with bytes and milliseconds, on a phone-sized viewport, against the live devnet; the number lands in the bench-log with the browser and the device. + +**Per tier.** A home miner's Ember node serves the proof to the tab; a holder with no node verifies state in the tab (the state root still rests on a certificate the client is given until 3.3 lands); a rollup customer sees the verifier it will run on its own chain; node operators serve one more 128-byte object. + +**The Monero core developer's attack.** "A verifier in a tab served by your domain verifies whatever your domain says the verifying key is. Your 'no middleman' is your web server. Monero's answer to this class is: run a node." Answer: correct, which is why spec 10.8 already removed "no node, no trust, no middleman" and why the phone app with a pinned seed list is the client that meets 10.6; the tab is a demonstration with its trust row stated on the card. + +**The Kaspa core developer's attack.** "Fine, it verifies a proof. Of which chain? The proof commits to a chain block hash; the tab needs to know that block is on the selected chain at or below a certified checkpoint, which it asks a node for (spec 10.4 item 4). You verified the arithmetic and trusted the topology." Answer: correct until 3.3 folds the certified index into the same proof. + +**Verdict: do now.** Cheap, precedented, and the phase 2 wrapper measurement has to happen anyway. + +### 3.5 Continuous miner-voted parameters, bounded per block, in place of two-week proposals + +**The idea.** Spec 5.8 sets a parameter the genesis rules leave to miners by a registered proposal passing 60 percent of blue blocks over two weeks. For the handful of parameters that are dials rather than switches (`B_p`, `S_p`, the base-fee floors, the exclusive window, the external claim timeout) use Ethereum's gas-limit mechanism instead: each block carries the producer's vote for each dial, the value in force at a block is the median of the window's votes, and the median may move at most 1/1,024 of its value per block, within a hard range fixed at genesis. No proposal, no bit, no two-week window, no human. Switches (a new instruction family, a proof-system version) keep the 90 percent signal. + +**Why nobody shipped it this way.** Ethereum moves its gas limit by producer vote, bounded to 1/1,024 of the parent's limit per block (geth `core/block_validator.go`, VerifyGaslimit; approximate, not cloned). Bitcoin's BIP9 is a 95 percent tally over 2,016 blocks with LOCKED_IN and one more retarget before activation (bips.dev/9); BIP 135 generalised the thresholds. Kaspa's Crescendo was a fixed DAA score: `crescendo_activation: ForkActivation::new(110_165_000)` for mainnet and `88_657_000` for testnet (`vendor/rusty-kaspa/consensus/core/src/config/params.rs` lines 648 and 704; the struct at line 28), with nodes connecting only to protocol version 7 peers from 24 hours before (docs/crescendo-guide.md at v1.0.0). Monero's upgrades are scheduled hard forks, formerly every six months, now every 9 to 12 months (getmonero.org). Igneum's own 6 October incident was a fixed-height activation crossing a half-updated fleet (CLAUDE.md, Devnet 2 rules). Nobody applied Ethereum's dial to a proof-of-work chain's economic parameters. The combination is new; the mechanism is Ethereum's. + +**What Igneum already has.** The header's version bits (O-5.3 candidate), the 60 percent rule, the fee parameters as `Params.fees` per network (spec 5.11), the DAA window every node computes. + +**The model.** At 1/1,024 per block and 1 BPS a dial can move 2.3x in a day (1.001^86,400) if every producer votes the same way, 1.07x if 51 percent do and 49 percent vote the other way (the median moves only when a majority agrees, and then one step per block). A hostile 51 percent can therefore walk a dial to the genesis bound in days; the bound is the defence, as it is on Ethereum (the gas limit has a hard floor and no cap besides the vote). + +**Hours.** 30: the vote field and median rule (10), the clamp and bounds in `Params` (6), tests including the 51 percent walk (8), spec 5.8 text (6). + +**The gate.** On the fast-time harness, 100 producers at 60/40 split: the dial moves toward the 60 side at the predicted rate and stops at the bound; with a 50/50 split it does not move; a producer that votes outside the range is invalid. + +**Per tier.** Miners set the dials with their blocks (Ember shows the vote and defaults to "hold"); a pool votes for its members in mode A and B templates and the member sees it (spec 9.4); provers watch `B_p` and `S_p` move with the fleet's measured shard time instead of waiting for a human; holders and rollup customers see fee floors that track usage; node operators gain one field per header. + +**The Monero core developer's attack.** "You have handed the fee floor to whoever has 51 percent of blocks, with no social veto. On Monero the dynamic block size has a penalty curve exactly so that a majority cannot cheaply walk it; your 1/1,024 is a speed limit, not a cost. A pool with 51 percent lowers `f_p` to its floor, bloats blocks with wash gas it no longer pays for, and the provers eat the backlog." Answer: the base fee is burned in full, so wash gas is never free (ledger E3), and the backlog rule halves `B_p` regardless of the vote (design 4.3); the range bound caps the walk. The point stands that a dial needs a cost curve, not only a speed limit: the prototype should add Monero's shape (a vote away from the median costs the producer a fraction of its subsidy). + +**The Kaspa core developer's attack.** "A per-block vote on a DAG: which blocks vote? Blue blocks of the selected chain's mergesets, in order, and the median over a window is a function of the block's past, fine. But a parameter in force 'at a block' must be the same for every node validating that block: use the value at the block's selected parent's checkpoint, or two honest nodes meter the same transaction at two prices. You have the same determinism bug the proof-record rule had before P11." Answer: correct; the value in force is read at the last certified checkpoint in the block's past, as 3.1's W30 is. + +**Verdict: prototype.** The chain's economic dials follow the fleet without a human; the two attacks give it the two rules (a cost curve, a checkpoint-anchored read) it needs. + +### 3.6 Treasury-less audit funding: bounties from the burn, a review escrow on upgrades + +**The idea.** the project lead removed the dev fund (spec 5.5) and the project pays audits from the Ember dev fee and founders' mined coins (litepaper). The question: money for audits that comes from users paying for something, with no standing address. Two mechanisms. (a) **Burn redirect.** The base fee burns to nobody. A reproducible break submitted under spec 0.5 and accepted by 60 percent of blue blocks over a window redirects the base-fee burn of the next 7 (execution) or 30 (consensus) days to the submitter's address, once, then returns to burning. No address exists between events. (b) **Review escrow.** An upgrade proposal under 5.7 must escrow IGN in a contract that pays reviewers named in the proposal on a 60 percent "review complete" signal, or refunds on failure; the proposer pays, which is a user paying for a thing (the right to propose code). + +**Why nobody shipped it.** Zcash funds development from the block subsidy (NU6: 8 percent to Zcash Community Grants, 12 percent to a protocol lockbox, ZIP 1015); Decred from a 10 percent treasury spent by stakeholder vote, capped at 4 percent of balance a month since January 2026 (DCP-0013); Monero from the CCS, donations off-chain; Optimism from an 850 M OP reserve for retro funding. Bug bounties pay 10 percent of funds at risk (Immunefi's standard) from the protocol's own treasury; Code4rena runs contests at zero platform fee since 2025. Nobody funds audits from a burn redirect, because a burn redirect is a subsidy to a payee by rule, and the chains that wanted that built a treasury. New in form; a dev fund in substance (see the Monero attack). + +**What Igneum already has.** The base-fee burn in both dimensions, the 60 percent signalling, the ledger's break-submission rule (spec 0.5), the proposal registration transaction (spec 5.8). + +**The model** (frontier_model.py section 4): + +| Chain traffic (fraction of full blocks) | Base fee burned per day, IGN | 30-day redirect, IGN | USD at 0.02 | USD at 0.10 | +|---|---|---|---|---| +| 0.01 | 2,592 | 77,760 | 1,555 | 7,776 | +| 0.10 | 25,920 | 777,600 | 15,552 | 77,760 | +| 0.50 | 129,600 | 3,888,000 | 77,760 | 388,800 | +| 1.00 | 259,200 | 7,776,000 | 155,520 | 777,600 | + +At launch traffic a 30-day redirect is under one audit contest; at half-full blocks it is a serious bounty. The money exists only once the chain is used. + +**Hours.** 20 for the escrow contract and the redirect rule as a proposal kind; 0 for the honest alternative, which already exists. + +**The gate.** None that a simulator settles; the gate is the project lead's: does a per-event, miner-approved payee with no standing address pass the test that removed the dev fund? + +**Per tier.** Miners vote on each payout with their blocks and can refuse all of them; holders see supply that would have burned paid to a named person; a prover, rig, pool user and rollup customer see nothing unless a break affects them; the node operator gains a proposal kind. + +**The Monero core developer's attack.** "This is a dev fund with extra steps. You removed a 5 percent fund because 'a switch that routes money to an address somebody controls is the first thing a critic points at'; you have now written a switch that routes money to an address somebody controls, gated by the same miners who gate everything else, and you have made the miners the judge of which cryptographer gets paid. Our CCS works because it is off-chain and voluntary and no consensus rule touches it. Keep the burn a burn." The attack is right. Answer: there is no counter besides the honest one: the alternative is the one the litepaper already states (client fee, founders' mined coins, grants off-chain), and the ledger should carry this entry as considered and rejected on the same ground as E4. + +**The Kaspa core developer's attack.** "Also a soft target: a miner cartel with 60 percent invents a break, 'accepts' it, and un-burns 30 days of fees to itself. Your spec 0.5 reproducibility rule is a human judgement; consensus cannot check it." Correct. + +**Verdict: watch.** Design it, do not ship it; record it in the ledger beside E4 as the honest answer to "where do audits come from with no fund": from the company's dev fee and from the people who care, in the open. + +### 3.7 Reproducible-build attestations in a registry contract; Ember refuses a release under N of M attestations + +**The idea.** Bitcoin Core builds with Guix and independent builders publish signed attestations of the output hashes to the `guix.sigs` repository (`bitcoin/bitcoin` PR 21462 added `guix-attest` and `guix-verify`; bitcoinops.org reproducible builds). Put the attestation registry on Igneum: a contract where a builder set posts `(release tag, artefact hash, signature)`; the Ember updater refuses to install a release whose artefact hash has fewer than N attestations from M builders listed in the release key's policy, and shows the attesters. Windows exes are already reproducible here (`-Wl,--no-insert-timestamp`, CLAUDE.md), so the hash is well defined. + +**Why nobody shipped it on chain.** Bitcoin keeps its sigs in a Git repository because Bitcoin has no contract state; Ethereum clients attest off-chain. Igneum has an EVM and a signed updater that already checks a manifest hash. The on-chain registry read by the updater: new in placement, not in idea. + +**What Igneum already has.** Reproducible builds on the box (`tools/build-remote.sh`, `cross-remote.sh`), the signed manifest and updater in Ember (litepaper, Ember table), the commit-string check (`tools/ci/commit-string-check.sh`), the release key in genesis (spec 8). + +**The model.** Trust goes from one key (the release key, which on the devnet "acts as the operator", litepaper Governance) to N of M builders, with M growing as outside builders arrive. The failure the rule catches: a release signed by a stolen key whose hash no independent builder reproduced. Cost per release: one transaction per builder. + +**Hours.** 12: the registry contract (4), the updater's N-of-M check and the display (6), the CI step that posts the box's attestation (2). + +**The gate.** A release whose binary is altered after signing is refused by Ember on three machines; a correct release with N attestations installs; the registry shows both. + +**Per tier.** Every miner's updater refuses an unattested binary and names who attested; a pool operator and a node operator get a chain-readable answer to "is this the binary everyone runs"; holders and rollup customers see that the "release key as operator" sentence has a closing mechanism. + +**The Monero core developer's attack.** "Who are the M builders at launch? The founder, under three names. Reproducible builds are only as good as the independence of the builders, and a pseudonymous one-founder project has one builder. Gitian and Guix were worth something because dozens of people with names attested. You are moving a sigs repo on chain; you are not adding a builder." Answer: correct, and the registry is what lets a second builder exist with a public record; the gate should be the first attestation from a machine the project does not own. + +**The Kaspa core developer's attack.** "A node that reads a contract to decide whether to update is a node whose update path depends on the chain being live and unforked; during the 6 October two-sided chain you would have had two registries." Answer: the updater installs nothing while finality is paused, which is a rule worth adding anyway. + +**Verdict: do now.** Twelve hours, and it closes a sentence the litepaper has to carry today. + +### 3.8 Ember as node, wallet and light client for everyone + +**The idea.** Ember already runs a node, mines, proves and keeps a key; Igneum Wallet reads Ember's node when present. Make the one app the client for everyone: a holder who does not mine runs Ember in "verify" mode (the light client of spec 10 inside the same binary, the node card to pin a seed), a miner runs it in full mode. Every miner is a node; every holder is at least a light client; nobody runs a browser wallet against someone else's RPC by default. The node count becomes the miner count plus the holders who chose full mode. + +**Why nobody shipped it.** Bitcoin Core is a node and a wallet but not a miner; miners run separate software (approximate). Monero's GUI runs a node and a wallet and can mine on the CPU (approximate; the litepaper's reason for no CPU lane is botnets). Kaspa's miners run kaspad plus a separate miner. Igneum's Ember already supervises node, miner, prover and key (litepaper, Ember table), so the step is small. Not new; the combination with the light client and the vote key in one binary is Igneum's. + +**What it does to node counts and Sybil counts.** Bitcoin: 24,682 reachable nodes (bitnodes.io, 5 October 2026); Ethereum: 8,136 execution clients on ethernodes.org, 11,781 on Etherscan the same day; Monero: about 5,000 peers seen in 72 hours by one tracker (monero.fail), all secondary. Igneum's gate 4 is 1,000 independent miners; with Ember as the node those are 1,000 full nodes on day one of the public testnet, each with a vote key. Sybil counts are irrelevant on Igneum by design: nothing in consensus counts nodes or keys (spec 3.1 W6, ledger F17), so a Sybil inflates a node map and nothing else. The one place a count matters, "no verifier, no vote" (spec 9.7 item 2), is served better: every member has a verifier because the signer is the verifier. + +**Hours.** 20: the light-client engine inside Ember's process with a mode switch (12), the wallet reading it (4), the node card pinning (4). + +**The gate.** A machine with no GPU runs Ember in verify mode, shows "locked" from a certificate it verified, and sends a transaction; a miner's Ember shows one key in the header of its blocks and the same key signing votes. + +**Per tier.** A home miner runs one program; a holder with a laptop runs a verifier instead of trusting an RPC; a pool user's member process is Ember (spec 9.1); a rig runs one signer and many workers (spec 9.6); the node operator is now everyone. + +**The Monero core developer's attack.** "A node that is also a hot wallet with a vote key and a miner is one process with every secret in it; one bug in the dashboard's local HTTP server (you serve it behind a per-launch token) and the key, the vote and the coins go together. Monero separates the daemon from the wallet for this reason." Answer: the separation stays at the process level (signer, workers, node, wallet are separate processes under one supervisor), and the vote key and the payout key are different keys; the attack names the test (the dashboard token's threat model) that gate 4 must include. + +**The Kaspa core developer's attack.** "Node count is a vanity metric; what matters is who produces blocks and who the honest majority peers with. A thousand Ember nodes behind home NAT accept no inbound connections, so your reachable count is your seed list plus the rigs, and an eclipse of the seed list eclipses the fleet." Answer: correct; spec 10.6's pinned seed list with identity keys and the local peer set is the defence, and the eclipse test O-3.7 with Ember nodes is the gate. + +**Verdict: do now.** Twenty hours; the testnet gate then measures nodes, not only miners. + +### 3.9 Hardware wallets that verify proofs + +**The idea.** A Ledger or Trezor that verifies the wrapped block proof (or the certificate) before signing, so "final" is checked on the device, not in the companion app. + +**Why nobody shipped it.** Ledger's secure element is EAL6+ certified and Trezor's Safe 3 and 5 use an Infineon OPTIGA Trust M (trezor.io; ledger.com), both small, slow, memory-poor chips. The cryptographic work hardware wallets do is signing; the heavy lifting (sync, proofs, history) is in the companion. A bn254 pairing on a Cortex-M-class secure element is seconds to minutes (approximate, from memory; the Bulletproofs-on-Trezor paper, eprint 2020/281, shows what Micropython on a Trezor costs for range proofs, and it is slow). Igneum Wallet already verifies the finality certificate with the node's own code (litepaper, Wallet table), which is the companion doing it. + +**The model.** Certificate verify: G1 aggregation of up to 10,000 keys plus one BLS12-381 pairing; on a laptop in JavaScript 58 to 155 ms (bench-log). A secure element is 100x to 1,000x slower on scalar arithmetic than a laptop core (approximate), so 6 to 150 s per certificate, every 30 s. Not shippable. + +**Hours.** 12 for a companion-side integration (the wallet already does it); the on-device path is not worth hours. + +**Per tier.** Holders get "final means final" in the companion today; nobody gets it on the secure element. + +**The Monero core developer's attack.** "Monero's Ledger app exists and does nothing but sign; it took years and a custom protocol (eprint 2020/281). You will not get a proof verifier onto a secure element and you should not pretend to." Correct. + +**The Kaspa core developer's attack.** "A device that verifies a proof still needs to know which chain tip the proof is of; it will take that from the companion, which is the thing you did not trust." Correct. + +**Verdict: never on the secure element; do the companion verify** (already done in Igneum Wallet 0.1.1; the Ledger and Trezor apps when they exist should display the companion's verified state and sign). + +### 3.10 Proof-of-useful-work: the lottery hash partly a proof + +**The idea as asked.** Make the leader election depend in part on proving work, so the energy that picks the block maker is useful. + +**Why every attempt failed, cited.** Primecoin (2013) found Cunningham and bi-twin prime chains that nobody uses (Bitcoin Magazine, July 2013). Gridcoin pays for BOINC work and stops if BOINC stops (gridcoin.us; the 2022 "Challenges of PoUW" survey, arXiv 2209.03865). Ball, Rosen, Sabin and Vasudevan (eprint 2017/203) gave proofs of useful work from fine-grained problems (Orthogonal Vectors, 3SUM, APSP) and state the conditions: the problem must be sampleable at a tunable hardness with instances the miner cannot choose, and the verifier must be cheaper than the work. Ofelimos (Fitzi, Kiayias, Panagiotakos, Russell, CRYPTO 2022, eprint 2021/1379) got a provably secure protocol by making the work a doubly efficient local search whose usefulness is a side effect and small. The 2026 "Economics of Proof-of-Useful-Work" (arXiv 2606.06700) and the empirical study of Pearl's cuPOW (arXiv 2606.04819, "The Usefulness Gap") find the same gap between the work paid for and the work anyone wanted. I found no Coinbase paper on the subject (searched 6 October 2026); if the project lead has one in mind, its title is needed. Aleo ran proving as the consensus work and the fastest prover won (CLAUDE.md: the Aleo lesson; litepaper precedents table, approximate). Boundless's PoVW (docs.boundless.network/zkc/mining/overview) pays ZKC pro rata to cycles proven per epoch with a stake that scales with the work, which is a reward for proving, not a leader election, and it is on a proof-of-stake chain. + +**The sampleability problem, plainly.** A lottery needs a puzzle whose instances are drawn at random from a distribution the miner cannot steer, whose hardness is tunable by a target, and whose solution is verifiable in milliseconds. zkVM proving has none of these: the instances (segments, jobs) are chosen by users and producers, the hardness is whatever the program is, and the verifier is tens of milliseconds to seconds. Any blend ("a miner's lottery target eases in proportion to its proven cycles last hour") gives the fastest prover more blocks, which is Aleo with a cap, and a cap small enough to be safe is a reward too small to be useful. + +**What Igneum already has instead.** The separation (litepaper: "the lottery and the proving are kept separate on purpose"), the 20 percent pool paid by sortition by weight, PoVW-like cycle metering through pgas. + +**Hours.** 0. + +**Per tier.** Nothing changes; the 12 GB card still earns from proving through the pool. + +**The Monero core developer's attack.** "RandomX's whole point is that the work has no second use, because any second use is a subsidy to whoever does the second thing best, and that is a specialist. The moment your hash is 'partly a proof', the best prover is the best miner, and the best prover is a datacentre. You know this; it is in your own CLAUDE.md." + +**The Kaspa core developer's attack.** "Leader election on a DAG must be a memoryless Poisson process so that GHOSTDAG's k and the orphan analysis hold; a target that depends on the miner's past hour of proving is not memoryless and your blue-set bounds no longer apply." + +**Verdict: never.** Both attacks are correct and the second is fatal to the DAG analysis. The honest version of "useful work" is the one Igneum has: the same card, two jobs, two payments, no coupling. Lane 8 may take one adjacent idea by name: **the shadow-useful puzzle**, in which the program work placed in the latency shadow (class v4, 100,000 ops per hash that cost the card nothing) is itself a small verifiable sub-computation drawn from chain state (a hash-based commitment to a sampled Merkle path of the segment's state witness), so the shadow ops have a second use that does not change who wins. It changes nothing about leader election because the shadow is free; whether a useful shadow program is as chip-hostile as a random one is lane 8's question. + +### 3.11 Miners paid for proving others' chains as the main income, the lottery as the tiebreaker + +**The idea as asked.** Invert the design: proving is the income, the lottery only orders. + +**The arithmetic** (frontier_model.py section 7): + +| Income line | USD per day | Basis | +|---|---|---| +| Proving every Ethereum L1 block at the Sep 2026 tracker cost | 36 | USD 0.005 x 7,200 blocks; a buyer pays above cost, call it 10x: 360 | +| The same at the Dec 2025 cost | 288 | under USD 0.04 per block | +| All rollup proving spend (customer brief) | 8,200 to 27,400 | "low millions a year", approximate | +| Boundless, trailing day in the explorer, 4 Oct 2026 | 2 | 8.4 T cycles at USD 0.21 per billion, `developer-adoption.md` 2b, approximate | +| Igneum year-1 emission at USD 0.005 per IGN | 13,700 | 31.688 IGN per block x 86,400 | +| At USD 0.02 | 54,800 | | +| At USD 0.10 | 273,800 | | + +The whole public proving market is three to four orders of magnitude under year-1 emission at any price input. The cost curve (section 2.6) falls 3x to 30x a year, so dollars per proof fall as fast as volume rises; for proving to be the main income by 2030, paid demand must grow about 1,000x in dollars. The design's own claim is the defensible one: a second income that keeps cards on after the subsidy fades (spec 5.10.2). + +**Why nobody shipped it.** Succinct and Boundless are exactly this (proving as the income) and have a token for the lottery's role; their provers are datacentre operators (ledger C10). Nobody has made it a GPU home-miner's main income because the market is this size. + +**Hours.** 0. + +**Per tier.** The 12 GB home card earns pool emission today and job income later; the number that matters to it is the pool share, not the market. + +**The Monero core developer's attack.** "Your 'paid, useful, verifiable work' line implies the work pays. It does not and will not; say so in the litepaper's income table." Answer: the litepaper already says "small market today", "upside, not a promise" (ledger P6); the arithmetic above should join it. + +**The Kaspa core developer's attack.** "If proving were the income, the lottery would be a cost centre miners minimise, hash would fall to the floor, and your 51 percent cost would be the cost of a few 5090s. Keep the lottery paid." Correct. + +**Verdict: never by 2030 as the main income; watch the market yearly.** + +### 3.12 The GPU fleet as a public compute market beyond proofs, priced in IGN + +**The idea.** Rendering, inference, transcoding, simulation sold by Igneum miners for IGN, through the same client that switches between hashing and proving. + +**The honest problem.** General compute is unverifiable: a renter cannot tell a rendered frame from a cheaper one, an inference from a smaller model's, without redoing the work. The existing markets answer with trust substitutes: Render uses result quorums for graphics, Akash provider auctions plus reputation, io.net proof-of-work-style attestations (all secondary, io.net's own comparison page and a 2026 DePIN survey). None of those is checkable by a chain. + +**The verifiable subsets, named.** + +| Work | How it is verified | Status for Igneum | +|---|---|---| +| ZK proving jobs | The proof | The precompile (design 6), Designed | +| Deterministic recompute with sampling | Commit to every intermediate, a verifier re-runs a random fraction (Statistical Proof of Execution, arXiv 2503.18899; sampled layerwise proofs for inference, arXiv 2609.27367) | Feasible as an app on the precompile: the sampled chunk is the job; the rest is a commitment | +| Rendering with result quorum | Two or three miners render the same frame; the chain pays on agreement (Render's approach, approximate) | An app; the chain pays per agreement, cannot judge quality | +| TEE-attested inference | NVIDIA confidential computing attestation on H100 and H200 (phala.com GPU TEE) | The fleet's cards have no TEE; not Igneum's | +| Bitwise-reproducible training | Verde-style proofs of learning on a rollup (secondary, io.net comparison page) | Research | + +**Hours.** 60 for a sampled-recompute job type on top of the precompile; 0 for the general market. + +**Per tier.** A 24 GB card could sell sampled-recompute work; an 8 GB card cannot hold most inference models; the rollup customer is unaffected; a holder sees IGN demand only for the verifiable subset. + +**The Monero core developer's attack.** "You would be Golem, Render and Akash with a worse token story and a settlement layer nobody asked for. The honest answer to 'GPU owners should be paid for useful work' is a market with reputation, and reputation is not a consensus rule." Correct for the general case. + +**The Kaspa core developer's attack.** "Every second a card spends on a render is a second off the lottery; the design's own economy model shows hash falling 14 percent when external pay rises 10x (scenario b). A compute market large enough to matter would empty the lottery." Correct, and it is the reason 3.11 is never. + +**Verdict: never for unverifiable work; do the verifiable subsets as apps on the precompile** (the sampled-recompute job type is the one worth 60 hours). + +### 3.13 Igneum as the settlement layer for GPU rental itself + +**The idea.** Vast.ai and RunPod match renters and hosts and take a platform cut; the escrow, the metering and the payout could run on Igneum, where every miner is already a host with a funded wallet and a card that is on. + +**The fee arithmetic** (frontier_model.py section 5): + +| Card | Vast.ai on-demand USD/h | Platform take modelled | Host loses USD per card-year | Igneum settlement per rental (2 transfers at the floor) | At USD 0.02 / 0.10 per IGN | +|---|---|---|---|---|---| +| RTX 5090 | 0.44 (getdeploying.com, 6 Oct 2026) | Vast about 15 percent (secondary) | 579 | 0.0102 IGN | 0.0002 / 0.0010 | +| RTX 5090 | 0.44 | RunPod about 7 percent (secondary: hosts keep 93) | 270 | 0.0102 IGN | | +| RTX 4090 | 0.31 | Vast about 15 percent | 408 | 0.0102 IGN | | +| RTX 4090 | 0.31 | RunPod about 7 percent | 190 | 0.0102 IGN | | + +Caveat on the takes: secondary comparisons put Vast at about 15 percent and RunPod at about 7 percent; Vast's own June 2024 product update says the host fee was removed and replaced by a surcharge it does not publish, so the 15 percent is a market estimate, not a fee page. The chain's fee is three to five orders of magnitude under either. The platform's take pays for matching, images, dispute, trust and the verification of delivered work, and the last is what the chain cannot do (3.12). + +**What Igneum already has.** Funded miner wallets, the pool protocol's TLS transport and member identity (spec 9), the job escrow shape (design 6), the sampled-recompute path above. + +**Hours.** 40: a rental escrow contract with hourly streaming and a sampled attestation of liveness (the host signs a challenge per minute with the vote key; proves possession of the card by running one lottery warp on it, which the CPU verifier checks in 0.44 ms) (24), a client-side matching list (16). It settles payment and liveness; it does not verify the renter's workload. + +**The gate.** Ten rentals between fleet boxes with one host that goes dark: the escrow pays to the minute of the last valid challenge; the renter's refund is exact; the chain fee per rental under 0.02 IGN. + +**Per tier.** A home miner rents out idle hours with no platform cut and a 30-day public record as a host; a rig lists eight cards; a pool user is unaffected; the prover role and the host role compete for the same seconds; a holder sees IGN demand per rental; a rollup customer is unaffected. + +**The Monero core developer's attack.** "Escrow is 1 percent of a marketplace. The 15 percent is the other 99: the people who answer when a pod dies. You will have a cheaper escrow and no renters, and every renter you do get will be running the thing Vast bans. Also: a card that is rented is a card that is not mining, so you are paying people to leave your lottery." The last point is 3.12's and stands. + +**The Kaspa core developer's attack.** "Streaming payments per minute at 1 BPS are 1,440 transactions a day per rental, each burning a base fee; at a thousand rentals that is your whole block budget. Use a channel, settle twice." Correct, and the model's two transfers assume exactly that. + +**Verdict: prototype** the escrow with the liveness challenge, because it reuses the vote key and the CPU verifier in a way no other chain can, and because miners are hosts already; do not call it a marketplace. + +### 3.14 Proofs sold to AI labs for verifiable inference + +**The state of the art, cited.** zkLLM (arXiv 2404.16109, CCS 2024) proves a 13 B-parameter LLM's inference in under 15 minutes with proofs under 200 kB, verified in 1 to 3 s; the 2026 sampled-layerwise paper (arXiv 2609.27367) measures 803 s of proving per forward pass on LLaMA-2-13B and extrapolates about 18 days per 2,000-token generation under full ZK. EZKL's median proof time on small workloads is about 8.2 s and a 100 M-parameter model is about 10,000 s per proof at today's throughput (proofoftech.org, secondary). Modulus Labs' Remainder prover was benchmarked at USD 0.085 per proof to verify on Base; the team joined Tools for Humanity in late 2024 and no longer sells (proofoftech.org). The competitor is a TEE: NVIDIA confidential computing on H100 and H200 with remote attestation, sold today at near-zero overhead (phala.com; arXiv 2607.19353 benchmarks), and sampling schemes (SPEX, arXiv 2503.18899) that are statistical, not cryptographic. + +**Cost per token, approximate.** 803 s of one GPU per forward pass on a 13 B model at a USD 0.44 5090-hour is about USD 0.10 per token proven. An unverified 13 B token is of the order of USD 0.0000002 (secondary inference pricing pages, 2026). The gap is five to six orders of magnitude. + +**What Igneum could sell by 2030.** Not inference proofs for frontier models. Proofs that a committed small model (under 100 M parameters) produced an output from a committed input, batched; proofs of aggregation over many small inferences; proofs of a sampled layer (the hybrid in arXiv 2609.27367) as a job type. `developer-adoption.md` 2b already draws the line at "verifiable compute, not verifiable AI". + +**Hours.** 40 for a sampled-layer job type once the precompile exists; 0 today. + +**Per tier.** A 24 GB card could prove a small model's inference as a job; nothing for smaller cards; a rollup customer is unaffected. + +**The Monero core developer's attack.** "A lab that wants verifiable inference buys an H100 with a TEE and gets an attestation for free. Your 100,000x-slower proof is for people who do not trust NVIDIA's attestation key, and those people are not buying GPU time from strangers." Fair for 2026 to 2028. + +**The Kaspa core developer's attack.** "Nothing here touches consensus; it is an app on the precompile. Stop listing apps as protocol ideas." Fair. + +**Verdict: watch** the cost curve yearly; the crossing where ZK beats a TEE on cost per token is not in sight by 2030 on the cited numbers. + +### 3.15 The Igneum program pipeline as a verifiable randomness beacon + +**The idea.** The chain already derives an unbiasable seed once an hour: a certified checkpoint, through a 10-minute class-group VDF (spec 04; 516-byte proof, 4.47 ms verify). Run the same VDF on every certified checkpoint hash at a 30-s delay and publish the output: a public randomness beacon at 30-s cadence with no league, no threshold key and no trusted set. + +**What drand is, cited.** The League of Entropy runs drand: threshold BLS over `H(round)` in unchained mode, a 2/3 threshold of a fixed set of organisations (the threshold must exceed 50 percent), quicknet at 3-s rounds since October 2023, timelock encryption built on it (docs.drand.love quicknet post and cryptography page). Its trust assumption is that under a third of a named set collude. + +**The model** (frontier_model.py section 6): + +| Beacon | Period | Latency | Unbiasability | Trust | +|---|---|---|---|---| +| drand quicknet | 3 s | about 3 s | threshold BLS, under 1/3 of about 20 organisations collude | a league | +| Igneum epoch seed today | 3,600 s | 600 s | certified checkpoint plus a VDF the last producer cannot evaluate in time | nobody | +| Proposed per-checkpoint beacon | 30 s | 30 to 60 s | the checkpoint is locked by 2/3 of 30-day weight before the VDF starts; a last-block grind costs a block's subsidy per try and buys a bit only if the attacker evaluates the VDF faster than the chain | nobody; the honest limit is the class-group ASIC (Chia's timelords are software or ASIC, docs.chia.net) | + +Chia's hardware timelords are the precedent for "the fastest squarer learns the value first" (Boneh, Bonneau, Bünz, Fisch, eprint 2018/601 for the VDF; Chia's class-group VDF competition repository for the implementation lineage). That is a front-running edge measured in seconds, not a bias. + +**What Igneum already has.** The VDF prototype (`proto-vdf/`), `seed_source` in headers, PREVRANDAO already defined from the epoch VDF (spec 7.1), the certificate every 30 s. + +**Hours.** 24: a 30-s VDF parameter set and the proof relay per checkpoint (12), an RPC and a `wss` feed (6), a contract exposing the latest value and a verify function (6). + +**The gate.** 2,880 values a day on the devnet for a week; every value verified by an independent client in under 5 ms; no value published before its checkpoint locked; a deliberate withholding of the last block before a checkpoint measured for its effect on the output (none, because the checkpoint is what is locked). + +**Per tier.** A node operator evaluates one 30-s VDF per checkpoint (one core); a miner does nothing new; an app developer gets a 30-s beacon and timelock encryption; a holder sees a product that drand's users (lotteries, raffles on Sui, approximate) might pay gas for; a rollup customer could read it through the proof bridge. + +**The Monero core developer's attack.** "Your beacon is only as unbiasable as your finality, and your finality pauses whenever under 2/3 of weight is connected (spec 03). A beacon that stops when the chain is partitioned is not a beacon; drand ran through every outage its members had because it needs a threshold, not a supermajority of all." Answer: correct; the beacon publishes nothing during a pause and must say so, which is still a stronger statement than a league's liveness. + +**The Kaspa core developer's attack.** "A 30-s VDF on a 1-BPS chain is fine; at 10 BPS your checkpoints are still 30 s of DAA time, fine; but the VDF input must be the checkpoint hash as every node agrees it, and your C4 finding showed two honest nodes can hold two certified checkpoints at one index for a window. Two beacons." Answer: the beacon for index i is published only when a single certificate for i is in the past of the next certified checkpoint, which is the F24 re-determination path; one window of delay in the worst case. + +**Verdict: prototype.** Twenty-four hours on code that exists, and a product no proof-of-work chain offers. + +### 3.16 The hourly program swap as a research dataset; the fleet library as a product + +**The idea.** Igneum generates 8,760 random GPU kernels a year, compiles each on Metal, CUDA and OpenCL, races up to 17 variants per card (lever 1, measured +17 to +21 percent on the M5 Max), and logs per-card per-variant timings to the fleet log (lever 2). That corpus does not exist anywhere: a continuous stream of random, bit-exact-across-vendors integer kernels with measured performance on every consumer GPU, under a fixed memory footprint. Publish it (the generator is public with the spec; the timings are the product) and the fleet library (the per-card best-variant table) as a dataset. + +**Who would pay, what for.** Compiler teams (LLVM's NVPTX and AMDGPU backends, Apple's Metal compiler) for a regression corpus with ground truth across vendors; GPU microarchitecture researchers for a latency-bound random-read benchmark across generations (the dependent-read ceilings of `chip-model-v3.md` 5.3 are exactly what such a corpus measures); the project's own cryptanalysts (the weak-program census, `weak-program-census-2026-10-03.md`) for the distribution of program properties. Money: small (research datasets are grants and goodwill, not revenue); standing: large, and it is the public benchmark the litepaper promises for January 2027 made continuous. + +**Why nobody shipped it.** RandomX programs are per hash, interpreted, and never logged; ProgPoW's period changes were never published as a corpus (approximate). New as a dataset. + +**Hours.** 10: a daily export of the fleet log and the generator seed list to a public bucket with a schema (6), a README with the citation form (4). + +**The gate.** One outside group cites it. + +**Per tier.** Every miner's timings are in it (anonymised to card model); a 9070 XT owner sees why their card is 7x worse per joule than a 5090 on dependent reads (`chip-model-v3.md` 5.8); nothing else changes. + +**The Monero core developer's attack.** "A public corpus of your programs with timings is the chip designer's training set." Answer: the generator is public already (github.com/igneum-network/spec) and a chip must run next hour's program, not last year's; what the corpus gives a chip designer is the distribution, which the spec gives too. + +**The Kaspa core developer's attack.** "Not a consensus matter." Correct. + +**Verdict: do now.** Ten hours and it makes the benchmark promise continuous. + +--- + +## 4. What would make a Monero or Kaspa core developer say "I had not thought of that" + +Three, with the exact reasoning each would use to attack it. The first two are 3.2 and 3.3 restated as the thing that is new; the third is new in this file. + +### 4.1 Work as the only stake, and it is slashable + +Monero's and Kaspa's shared premise: in proof of work nothing is at stake except the block you are mining, so misbehaviour by a miner outside block production (a bad job, a withheld proof) cannot be punished, only priced. Igneum's finality weight is a quantity that is at stake, is earned by work alone over 30 days, cannot be transferred, and is already stripped for equivocation. Extending the strip to execution-layer faults (3.2) gives proof of work a slashable bond with no coin and no stake class. + +**The Monero developer's attack, verbatim form.** "Then it is stake. You have a class of participants with something to lose that others do not, and a rule that takes it from them for a judgement call. Every argument you make against proof of stake (capture, cartels, nothing-at-stake inverted into everything-at-stake) applies to a stake made of blocks. Worse, your stake depreciates on its own in 30 days, so the rational prover front-loads bad behaviour in the last days of its weight." Answer: the weight is not transferable and not purchasable, which removes capture by capital; the last-days attack is bounded by the 30-day re-earn, and the sortition is proportional to current weight, so a depreciating key is drawn less. The concession: the spec must stop saying "no stake" and say "no coin stake; the only thing at stake is 30 days of public work". + +**The Kaspa developer's attack.** "Any slashing condition needs an objective, deterministic fault; on a DAG 'late' needs a clock, and your clock is DAA score along the carrier's chain, which is deterministic. Fine. But you now have a second use for the weight table that the finality module computes, and the two uses must read the same table at the same block or two honest nodes strip differently. Your proof-record rule needed P11 for this; write the same sentence now." Accepted. + +### 4.2 Finality carried forward inside the execution proof + +The Kaspa premise: finality on a DAG is a fork-choice property computed by every node from the DAG it holds; it cannot be a proof. The Monero premise: a light client trusts whatever gave it the checkpoint. Igneum's segment proof already recurses from genesis; carrying the weight table in it (3.3) makes "certified under rule v2" a public output of the same proof that attests the state root, with the update costing one mergeset per segment, not a 30-day window per proof. + +**The Kaspa developer's attack.** "The proof attests a chain; finality is about the DAG. Your W2 counts blue blocks in the chain block's past, and 'blue' is GHOSTDAG's judgement, which the proof does not recompute (it would have to run GHOSTDAG over k = 18 or 124 anticone sets inside a zkVM). So the proof takes blueness as a witness from the node, and a node that lies about which blocks are blue gives the proof a wrong table. You have proven the arithmetic and trusted the colouring." This is the sharp one. Answer: the colouring is committed by the header (the mergeset and blue set are determined by the parents, which the header commits to), so the witness is checkable against headers the proof also carries; but checking it means running GHOSTDAG's blue-set rule for each merged block inside the guest, which is bounded (anticone size at most k) and unmeasured. The gate for 3.3 must add: cycle count of the GHOSTDAG colouring check per mergeset inside the guest, and if it is too heavy, the colouring stays a witness and the light client's trust row says "blue set from nodes" until it is not. + +**The Monero developer's attack.** "You have made finality depend on your proof system's soundness in the light client. Say so on the card." Already in spec 10.1 for the proof system row; the row must now name finality too. + +### 4.3 The hourly program as an 8,760-question hardware census + +**The idea.** Every hour the chain hands every card a new random program and every card races 17 compiled variants of it and reports which won and how fast (lever 1, measured; lever 2, shipped). A chip built for the lottery cannot look like a GPU on 8,760 different programs a year: its best variant, its timing distribution across programs, its sensitivity to instruction mix are a fingerprint. Make the fingerprint part of the share protocol: a pool records, per member and per epoch, the variant that won and the share-rate ratio between consecutive programs; the chain's observer publishes the distribution per card model from the fleet library; a key whose ratio pattern sits outside every known card's envelope for N epochs is flagged publicly (the share-pattern detector of Counter ASIC item 4, which found Monero's chips by nonce patterns, now with a per-program timing axis a chip must fake 24 times a day). + +**Why it is new.** RandomX programs are per hash and no pool sees their timing; Monero's chip detection used nonce distributions (MoneroCrusher, approximate); ProgPoW audits priced the chip but had no running census. Igneum's hourly swap with per-card racing produces the census as a by-product. New. + +**The Monero developer's attack.** "Timing is self-reported. A chip reports whatever a 4090 would report; it has the 4090's published envelope from your own dataset (3.16). And MoneroCrusher found us the chips not by timing but by nonce patterns, which a chip emulates trivially once it knows you look. Detection that depends on the attacker's cooperation is theatre." Answer: the share rate per epoch is not self-reported; it is the pool's count of verified shares, and a chip that throttles itself to a 4090's per-program envelope on every program forfeits its edge on the programs where it is strong, which is a cost measured in hash. The detector cannot prove a chip; it can price the chip's camouflage. That is the honest claim. + +**The Kaspa developer's attack.** "We welcomed chips, so nothing here is for us. But as engineering: your per-epoch ratio depends on the pool's vardiff and on network luck; the envelope for one card model will be wide, and a 2x chip sits inside it. Your detector finds a 10x chip and misses the 2x one your model says is the threat." Fair: the detector's resolution is the gate (one epoch's share-rate variance per member at one share per 10 s is about 5 percent over an hour; a 2x step is 40 standard deviations, a 1.2x step 4; so it resolves 1.2x in a day and 1.05x in a month, approximate). + +**Hours.** 16: the per-epoch ratio in the pool protocol's `stats` (spec 9.5) and the observer's envelope per card model (12), the public page (4). + +**The gate.** The observer flags a deliberately throttled fleet box (a 5090 capped to a 4070's rate) within 24 epochs, and flags no honest card over a week. + +**Per tier.** Every miner's card model gets an envelope; a home miner on an unusual card (Apple, Intel) must be in the library or will be flagged; pools carry one more statistic; nothing in consensus. + +**Verdict: watch,** then do once the pool protocol exists: it is the cheapest instrument the chain has for the question the chip model cannot answer from a spreadsheet. + +--- + +## 5. The incremental list + +Smaller than the sections above; each with hours and a gate. + +| # | Item | Hours | Gate | Why now | +|---|---|---|---|---| +| I1 | Expose per-key 30-day weight and blue-block count in `IgneumInfo` so hashrate forwards and hardware-finance contracts settle from chain state (`developer-adoption.md` 2c) | 6 | A forward contract settles on the devnet against `getFinalityWeights` with no oracle | The data is already maintained for finality | +| I2 | Write the N schedule (latency-shadow program length) into the era draw at genesis, a doubling per era until the verifier gate binds (section 2.3) | 8 (spec text and the draw) | Verifier under 10 ms on a 2019-class core at the year-6 N | HBM4 arrives in 2027 to 2028 and the chain must answer it without a release | +| I3 | Define the block-proof target as a function of the fleet's measured median shard time, published per era, not as "under 10 s" (section 2.6) | 4 | The site reads it from the bench table | Honesty about the 12 GB tier | +| I4 | A second zkVM implementation of the `ProofSystem` trait (RISC Zero or OpenVM) running on one fleet box as a shadow verifier, so a soundness bug in one system is detected by disagreement before it reaches a light client | 24 | 1,000 segments agree across both; one injected bad proof disagrees | Ledger P7, D6: the veto protects full nodes, nothing protects light clients today | +| I5 | The Ember updater installs nothing while finality is paused (3.7's Kaspa attack) | 2 | A paused devnet, a published release, no install | Free | +| I6 | A finality-pause page on the site that shows the connected weight fraction live, so the "node reports the pause" sentence has a public face | 4 | Shows tonight's 18:42Z pause from the observer's data | Tonight's incident | +| I7 | Equivocation-evidence bounty paid in sortition slots: the key that first carries valid evidence inherits the stripped key's shard assignments for 30 days (no coins move; weight is reassigned, not created) | 12 | Two signers under one key on the fast-time harness; the evidence carrier wins the stripped key's draws | Makes watching for equivocation pay without a treasury | +| I8 | Mandatory proofs activation height set from a measured coverage share (spec 7.8 item 10) | 4 | Coverage above 99 percent for 7 days on the devnet | The rule is written and off | +| I9 | The exclusive window at 25 s and the claim timeout at 120 s on the phase 4 devnet (decided by the project lead, P9) with the economy simulator re-run at the measured shard times from `prover-tiers-real-cards.md` instead of the 20-s target | 6 | The 3060 class's shard share within 5 points of its weight share | The inputs changed today | +| I10 | `eth_getProof`, `debug_traceTransaction`, `eth_subscribe` (D5 step 2) before any outside team | 24 | Foundry's debugger and the Blockscout fork run against a devnet node | The light client and every tool depend on `eth_getProof` | +| I11 | Register chain ids 4461 to 4463 on ethereum-lists/chains before the public testnet (spec 7.1) | 1 | The PR merged | Wallets | +| I12 | Publish the 2028 tier table (section 2.6) on the miner page with its three rates, so no card owner buys on a promise | 2 | Live | the project lead's consequences rule | +| I13 | A spec sentence in 03 and 05: "no coin stake; the only thing at stake is 30 days of public work" (4.1) | 1 | Text | Before 3.2 is prototyped | +| I14 | The litepaper's income table gains the proving-market arithmetic of 3.11 in one line | 1 | Text | Ledger P6 asked for honesty; the number makes it concrete | +| I15 | A ledger entry beside E4 recording 3.6 as considered and rejected on E4's ground | 1 | Text | So the question is not re-asked | + +--- + +## 6. Open questions and what I could not run + +- **The BLS verification cycle count inside the SP1 guest** (3.3's gate a) needs a 24 GB card; PC 2 and the fleet were on the class v4 rehearsal and the Devnet 2 block-rate runs tonight. Without it, the 3 percent proving-capacity cost is an estimate. +- **The GHOSTDAG colouring check inside the guest** (4.2's Kaspa attack) is unmeasured and may be the real cost of 3.3; it is added to that gate. +- **The wrapper** (3.4) does not exist in the repository (ledger P3, R4); the 16 hours include building it on a fleet card. +- **HBM4 energy per random read** (section 2.3) is an unsourced estimate (1.0 nJ); JEDEC timing is behind the paywall; the 2x channel count is cited, the tFAW-per-channel assumption is mine. +- **The rental-tax rule's determinism** (3.1) depends on reading W30 and H_now at a checkpoint in the block's past; the lag's effect on the renter's first 30 s is unmodelled. +- **Vast.ai's actual take** is unpublished; the 15 percent is secondary. +- **No Coinbase paper on useful work was found**; if one exists its title is needed to cite it. +- **`block-rate-devnet2.md`** was a template at writing time; the 10 BPS question matters for 3.3 (segments re-cut at reorgs) and 3.5 (votes per block), and should be re-read when RUN_A lands. +- **Lane 8** holds the shadow-useful puzzle (3.10's handover) and anything about new puzzle shapes; nothing here designs a puzzle. + +--- + +## 7. Summary for the coordinator + +Lane 7 read the spec, the litepaper, the ledger sections asked, the design files, the chip model and the fleet's eleven-card table, searched prior art for sixteen ideas, and wrote one arithmetic model (`sim/horizon/frontier/frontier_model.py`) behind every number. Three findings: + +1. **HBM4 raises the stored-dataset chip's per-joule edge from about 7x to about 11x bare and from about 2.3x to about 2.7x under the class v4 latency shadow at N = 100,000 (model 1.4, every chip figure arithmetic), because JEDEC doubled channels per stack (16 to 32); N = 200,000 brings it to 1.7x and N = 330,000 to 1.3x at k = 1. The N schedule belongs in the era draw at genesis (I2), with 10x of verifier headroom.** +2. **Vote weight is a slashable, non-purchasable bond (3.2): a key with 0.1 percent of hash has 16,427 IGN of 30-day pool income and its vote at risk against a designed coin bond of 0.0015 IGN per job (model section 3). The design's "no stake" must become "no coin stake".** +3. **The consensus proof can be incremental (3.3): carry the W2 table inside the recursive segment proof and update it by one mergeset per segment, with one BLS verify per 30 s (about one shard's budget, approximate, unmeasured). It is the only road to a browser that trusts no node for the voter set, and its real cost is the GHOSTDAG colouring check inside the guest (4.2), which is the first measurement to run.** + +Two honest nevers with arithmetic: proving others' chains cannot be the main income by 2030 (all of Ethereum L1's proving is USD 36 a day at the Sep 2026 tracker cost against USD 13,700 a day of year-1 emission at USD 0.005; 3.11), and the lottery hash cannot be partly a proof without re-opening Aleo and breaking the DAG's memoryless election (3.10). One rule for main: the litepaper's "proving: a second income" line should carry the 3.11 arithmetic (I14), and the spec should carry the "no coin stake" sentence (I13) before any work-stake prototype starts. diff --git a/docs/analysis/horizon/new-pow.md b/docs/analysis/horizon/new-pow.md new file mode 100644 index 000000000..827db9886 --- /dev/null +++ b/docs/analysis/horizon/new-pow.md @@ -0,0 +1,239 @@ +# Horizon lane 8: a new proof of work (three candidate schemes, reviews, prototypes, verdicts) + +6 October 2026, evening UK, lane `new-proof-of-work`, worktree `/Users/joshm/Projects/igneum-wt-horizon` (branch `horizon` from master, at 3f4f719). Output of this lane: this file and `proto-newpow//`. Nothing here touches the shipped hash, `igneum-pow`, the node, the manifest or the live devnet; every prototype is a benchmark beside the worker, never inside it. + +the project lead's mandate, verbatim: "if we create a new way of hashing or a new way of proof of work to revolutionise the space then that's absolutely fine, I want you to deploy everything to create something that has not ever been done before." + +## 0. Progress (kept current for the coordinator) + +| Time (UTC) | State | +|---|---| +| 19:05 | Lane started. Read: preamble, CLAUDE.md, the two personas, spec 01 (whole), 04, 07, chip-model-v3 (whole), asic-resistance-history (sections 0 to 3 and 4.3, 5), latency-shadow-2026-10-06 (whole), counter-asic-3-status sections 1 to 5, counter-asic-3-node section 6 (the P2 signalling rule), int8-matrix-family sections 1 to 3, scratch-soundness verdict, proving-methods (whole), fud-ledger M1, M7, M16, M22, M28, P2, F13, proto-cuda host.cu and the mx8-genesis pack (kernel.cu, memhard.h, program.h, vectors.h), proto-cuda/emu, family-probe.cu, the fleet's prover-tiers-real-cards.md, bench-log line 2582 (rental cost) | +| 19:25 | Fleet agent asked for two boxes; answered at 19:29: two quiet RTX 4090s (RunPod, nvcc 12.8 at /usr/local/cuda/bin, directory /root/horizon-newpow, until 22:30Z). No quiet Ampere card exists tonight; a loaded 3090 is offered. Main's note: cost rows use bench-log 2582 (USD 0.0117 per MH/s-hour) | +| 19:35 | File skeleton written. Two prototype sub-agents launched (budget two at once): `mma-shadow` on box 1 (47.47.180.77), `state-dataset` on box 2 (213.173.98.36) plus CPU rows on igneum-build-1. Designs being written in this file meanwhile | +| 19:41 | Section 3 complete: the three designs, the one-table comparison, the migration path. Scheme A's verdict is already visible in its own numbers (A1 dead on 2.9 MB of openings per block, A2 dead on sampleability and a 32 to 40 ms proof verify; A0 is scheme C with the trace as state). Prototypes running: `mma-shadow` (box 1) and `state-dataset` (box 2 and igneum-build-1). mm8 two-output correction sent to the prototype | +| (next) | Section 4 reviews (cryptographer, consensus engineer, two per scheme); the pick; section 5 measured rows as they land; section 6 verdicts; section 7 ranked next steps | + +## 1. What was read and the facts this lane stands on + +Every figure below is from the named file; "approximate" marks a figure from memory. + +| Fact | Value | Source | +|---|---|---| +| The shipped hash | 64 instructions x 8 iterations, 16 loads per program (128 dependent 4-byte reads per hash), 8 registers, 32-lane unit with xor shuffles, class v3 = mixer x8 item derivation over a 256 MiB ChaCha12 cache, 1 GiB dataset in the packs (2 GiB designed), era draws, VDF seeds | `docs/spec/01-lottery-hash.md` 1.4 to 1.13 | +| Verifier today | 2.06 ms per unit on one M5 Max core (class v3, 4,096 item derivations), about 5.2 ms on a 2019-class core by the 2.5x rule; the 10 ms gate | `docs/plans/counter-asic-3-status.md` section 3, `latency-shadow-2026-10-06.md` section 4 | +| RTX 5090 at the hash | 136.1 MH/s (readwidth), 132.2 (shadow control), 290 W in the app, 350 W in the bench; 2.34 to 2.65 microjoules per hash; 17.5 G dependent reads per second, 82 percent of the GDDR7 activate ceiling; 45.2 T int op/s; marginal ALU energy 10 to 13 pJ per counted op | `chip-model-v3.md` 5.1, `latency-shadow-2026-10-06.md` 5 | +| The chip that matters | the f = 1 stored-dataset memory-controller chip: 5.1x per joule on GDDR7, 7.5x to 9.2x on HBM3 in the model; 2.1x to 4.8x by the Ethash precedent; the recompute chip (f = 0) 0.31x per chip, 1.86x per joule | `chip-model-v3.md` 5.4 to 5.6 | +| The one lever against it | program work in the latency shadow: at N = 100,000 ops per hash the chip's edge over the 5090 falls from 5.6x to 2.1x at k = 1 (chip core energy per op equal to the GPU's 11 pJ), to 3.2x at k = 0.5, 4.1x at k = 0.3; class v4 candidate `mx8+sh256x27` | `latency-shadow-2026-10-06.md` 6 and 10 | +| Step costs per family on the 5090 (ratio to the add-xor-rotate chain, 7,941 G lane-steps/s) | rotr 1.32, shflx 1.49, shfla 1.53, dot4 1.16, mm8 (`mma.m8n8k16.u8`, bit-exact) 2.43 | `counter-asic-3-status.md` section 3, item 6 | +| mm8 on other vendors | AMD RDNA 4: WMMA iu8 builtin reaches gfx12, 1.68 to 1.83 per step, fragment layout UNVERIFIED (exactness not attempted); Apple: no integer simdgroup matrix in MSL, Metal 4 `matmul2d` uchar x uchar into int exists but not from the Swift toolchain used here, per-lane dot4 emulation 1.6x unsigned, 4.7x signed | `counter-asic-3-status.md` item 6 AMD column, `int8-matrix-family.md` 1 and 4 | +| Proving today | SP1 6.8.1 Hypercube; the v1 shard (4.7 M cycles) proves in 4.8 to 18 s on 12 to 32 GB cards with the patched server, 7.4 to 8.0 GB alone; compressed proof 1.27 MB, verified in 32 to 40 ms; the aggregator 2.2 to 9.7 s per block | `prover-tiers-real-cards.md`, `proving-methods.md` 1 and 2.1 | +| Proof payment | 80/20 lottery/proving split of the subsidy; shards by weighted sortition (8 assignees, 10 s window), aggregator share 1,000 bps, unproven deadline 600 DAA s; the native-execution veto: a record whose statement differs from the node's own execution pays nothing | `docs/spec/07-execution.md` 7.2, 7.7, 7.8 | +| Class activation | P2: a class flips when 95 percent of blue blocks over a one-day window carry the object byte (header version high byte), with a fixed-height floor; one-sweep binary rollout; Devnet 2 gate first | `docs/plans/counter-asic-3-node.md` section 6, CLAUDE.md 6 Oct rules | +| Rented hash | USD 0.0117 per MH/s-hour (1,748 MH/s for USD 20.44 per hour on RunPod community pods, 18:45Z); the live devnet 1.16 GH/s | `docs/bench-log.md` line 2582 | + +## 2. Method + +Designs first (section 3), each reviewed in two personas (section 4), two picked, two prototypes measured on real cards (section 5), verdicts (section 6). Prototype shape: the mx8-genesis pack's own kernel text (`proto-cuda/packs-ca2-mixer/mx8-genesis/kernel.cu`, `memhard.h`) modified by the smallest change each scheme needs, compiled with nvcc 12.8 on the two RunPod 4090 boxes, timed by CUDA events over 2^24-nonce batches with `nvidia-smi` at 1 Hz, and checked bit for bit against a C CPU reference that interprets a 32-lane unit register-major with lazy item derivation (the verifier's shape) on 1,024 random lanes. CPU rows on igneum-build-1 (EPYC 9454P, Zen 4, one core at up to 3.8 GHz, which is NOT a 2019 core; the 2.5x rule of the project stands in for that core, labelled). Chip rows are the chip-model-v3 method (section 5 of that file) applied to each scheme, approximate where that file is approximate. + +## 3. The three candidate schemes + +Shared notation: `K_d` the day key (spec 1.8.1), `S_e` the epoch seed words (spec 1.3), the unit = 32 aligned nonces (spec 1.9), `item(t)` the 16-word class v3 derivation of spec 1.8.5, `target64` as spec 1.10. Difficulty in every scheme is the unchanged 64-bit target comparison on the unchanged DAA (spec 2.3): none of the three changes what a block's work unit is worth, only what the unit of work consists of, so the difficulty controller sees the same statistics. Each scheme is a program class in the sense of spec 1.4.5 (a `generator` number and a class byte), so activation runs through P2 (section 3.5). + +### 3.1 Scheme A: mining is proving ("proof of committed trace") + +**The claim to test.** The lottery's work is a bounded piece of the chain's own proving, so the 80/20 split collapses into one payment and the hash rate is the proving capacity. + +**The puzzle, in its most favourable form.** Every full node already runs the segment natively (spec 7, the native-execution veto). Add one step to that: every node also runs the zkVM executor (SP1's RISC-V executor, CPU, no proving) on the segment's shard inputs and keeps the shard TRACE: the cells of every table the shard touched, about 280 M cells for the adopted v1 shard, 1.1 GB (`proving-methods.md` 1.4). The lottery of epoch `e` then uses as its dataset the trace of the last segment whose last chain block has DAA score at most `3,600 e - 1,200` (the same 20-minute lead as the epoch seed, spec 4.3), serialised row-major and padded by zero to the dataset size, and the item derivation becomes `item_A(t) = class v3 derivation with s[i] ^= row(t)[i]` for the 16 words of trace row `t` (64 bytes of trace per item). Everything else is the shipped hash: 128 dependent 4-byte reads, the 32-lane unit, the fold, `target64`. Header commitment: nothing new; the trace is a function of the segment, the segment of the chain, the chain of the header's past, exactly as the epoch seed is (spec 4.3 item 4); the class byte 5 of P2 marks the object. Difficulty: unchanged. Verifier: the node derives up to 4,096 items per unit from the 256 MiB cache (as today) plus 4,096 reads of the trace rows it holds in RAM (1.1 GB): the measured cost of exactly this read pattern is scheme C's row in section 5 (the two schemes share the verifier shape). Under 10 ms on a 2019 core if scheme C's row is. + +**Two stronger forms, and why each dies on a number.** + +| Form | What the miner must hold or do | Verifier | Why it dies | +|---|---|---|---| +| A1, "proof of committed codeword": the dataset is the Reed-Solomon codeword of the trace (BaseFold's stacked encoding at blowup 4, 4.5 GB, `proving-methods.md` 1.1 and 1.4), whose Merkle root the shard record already publishes; the miner must have done the COMMIT stage of the proof (encode and hash) to mine | the LDE and the Merkle tree: the first stage of every STARK or BaseFold prover, the part a GPU spends a large share of its proving time on (approximate: 30 to 50 percent of the stage time, unmeasured here) | cannot derive a codeword word locally: one evaluation of a stacked column at one point is O(2^21) field operations (the stacking height, `proving-methods.md` 1.1), so 4,096 words per unit is about 8 G operations, about 1 s on a core, 100x over the gate. The block must therefore carry Merkle openings: 4,096 per unit (every lane's loads feed every other lane through `shfl`) x 22 levels x 32 bytes = 2.9 MB per block; with a 1-lane unit (no `shfl`) 128 x 22 x 32 = 90 KB per block, 7.8 GB per day of PoW witness at one block a second against about 200 B per header today (Kaspa header, approximate). Headers-first validation, the pruning proof and the light client (spec 10) all break on the bytes | +| A2, "mine a proving step": each nonce selects a random piece of the pending proof work (a FRI fold of one column, a Poseidon2 Merkle layer, a zerocheck round) and the hash is of that piece's output | that piece | the verifier either recomputes the piece (then the verifier did the useful work, and the piece bought nothing: the definition of useless) or verifies a proof of it (an SP1 compressed proof verifies in 32 to 40 ms, `proving-methods.md` 2.1, four times the whole gate, and a per-piece proof does not exist). And the pieces run out: a segment's proof is about 5 s of one 5090 (`prover-tiers-real-cards.md`: 4.8 to 18 s per shard on 12 to 32 GB cards, 2.2 to 9.7 s of aggregation) against 8 G hashes per 8-s segment at 1 GH/s; the useful fraction of the lottery's work is bounded by (proving work per segment) / (network hashes per segment), about 8 percent at 1 GH/s and 0.08 percent at 100 GH/s (arithmetic on the cited figures), because proving work is set by gas and lottery work by the security budget. They are the same quantity only by coincidence at one network size | + +**The sampleability objection, stated and answered.** Ball, Rosen, Sabin and Vasudevan, "Proofs of Useful Work" (ePrint 2017/203) build PoUW for problems with a random self-reduction (orthogonal vectors, 3SUM, all-pairs shortest paths): a useful instance is embedded into a random challenge so that the challenge is hard on average, solving it solves the instance, and verification is fast; the price is a polynomial blow-up and a problem class with that structure. Ofelimos (Fitzi, Kiayias, Panagiotakos, Russell, CRYPTO 2022) makes the useful work a doubly-parallel local search whose QUALITY improves with more work, so more hash rate yields better solutions. Primecoin (2013) mined Cunningham chains (useless, but sampleable: the nonce picks the chain's origin). Gridcoin pays BOINC credit through a trusted whitelist, not a puzzle (approximate, from memory for the last two). Proof generation has none of the three properties these constructions need: (1) a segment has one proof, not a distribution of instances, so there is nothing for the nonce to sample; (2) partial progress has no verifiable value under the gate without a proof, and a proof verify costs 32 to 40 ms; (3) the quantity of useful work is fixed by demand (gas), the quantity of lottery work by the security budget (hash rate), and a puzzle whose per-solution work is fixed by demand is not a difficulty-adjustable lottery. The answer this design gives is therefore no: the only form that survives the gate and the bytes is A0 above, in which the miner must HOLD the trace, which is "proof of stored state" with the trace as the state, and the useful work gained per hash is zero (every node computes the trace natively anyway; ledger F13). Mining does not become proving; it becomes proof that the miner executes. + +**Chip edge per joule (chip-model-v3 method).** A0 changes the dataset's contents, not its size or read pattern; the f = 1 stored-dataset chip stores whatever the items are: 5.1x per joule on GDDR7, 7.5x to 9.2x on HBM3, unchanged from `chip-model-v3.md` 5.4. The f = 0 recompute chip must now hold the 1.1 GB trace somewhere (it cannot derive an item without row `t`), so it needs DRAM beside its SRAM and becomes an f = 1 chip; the 0.31x row disappears, which is a small gain since that chip was never the threat. A1 and A2 are not priced: they fail before a chip is drawn. + +**Verifier cost.** A0: the class v3 derivation (2.06 ms per unit on an M5 Max core, measured) plus 4,096 random 64-byte reads from a 1.1 GB array; the read row is measured in section 5 (scheme C's CPU rows, the same pattern). A1: 2.9 MB of openings or a 1-lane unit (see table). A2: a proof verify (32 to 40 ms, measured) or nothing useful. + +**Bit-exactness.** A0: the trace rows are bytes; the derivation is integer; nothing vendor-specific is added. The zkVM executor's trace must itself be deterministic across platforms (SP1's executor is Rust, no floating point in the trace path, approximate: not audited here); any disagreement about a trace cell is a consensus split, so A0 adds the SP1 executor to the consensus-critical code, which ledger P7 already names as a risk class for the proofs and which here would extend to the lottery. + +**Known attacks.** Grinding: a block producer influences the trace through the transactions it includes, but the trace used is 20 minutes old and keyed by `K_d` through the mixer; a producer cannot predict a useful bias in 128 dependent reads of a keyed derivation (the MTP lesson, `asic-resistance-history.md` 2.3: Dinur and Nadler controlled addresses by controlling contents; here the contents enter only through a keyed, chained derivation whose addresses are the cache-line indices of the mixer state, not the trace). Outsourcing: pools serve the dataset (1 to 2 GiB per miner per day), so "the miner holds the trace" becomes "someone in the pool holds it". Precomputation: the dataset is computable 20 minutes early, as today. Light evaluation: as the f = 0 row above. Sampleability: the paragraph above. Empty segments: a day or an epoch with no transactions has a near-empty trace (the shard statement still applies rewards, spec 7.7 item 8), so the dataset is mostly padding and the hash degrades to today's class v3: graceful, not an attack. + +**Game theory of the collapsed payment (if A1 or A2 had worked).** The 20 percent pool would go: provers are miners and the proof is the by-product of the lottery. Who is paid for what: the block reward pays for the block and the proof piece in it; a prover that mines earns exactly a miner that proves. Pools: the pool does the useful work and sells shares, as today, so proving centralises exactly as mining does (Aleo's proof of succinct work centralised on the same path: the coinbase puzzle was a synthetic circuit proven by whoever had the most GPUs; approximate, from memory, the cryptographer persona's own list). Proving demand at zero: the puzzle has no useful content and must fall back to a synthetic dataset, so the chain carries two puzzle modes and a mode switch, a consensus rule and a grinding surface. External jobs: a customer's proof could only be mined if its segment entered the puzzle, so the security budget would be spent on the customer's work at the marginal cost of inclusion, a subsidy from holders to customers unless priced by a burned fee. These are the reasons CLAUDE.md records the lottery and the proving as separate on purpose; nothing found tonight overturns them. + +**Migration.** A0 is a class byte (P2): class v5 by the 95 percent signal with the floor height, one-sweep binary rollout, Devnet 2 gate first (CLAUDE.md 6 Oct). Every node must run the zkVM executor on every segment before the flip (CPU cost: the v1 shard is 4.7 M cycles; SP1's executor runs at tens of MHz on a CPU, approximate, so under a second per 8-s segment); a node without it cannot validate PoW after the flip, which is what the floor height is for. + +**Verdict line (section 6 has the reasoning):** NEVER as "mining is proving" (A1, A2); A0 is scheme C with the trace as the state and is folded into C. + +### 3.2 Scheme B: a GPU-structure-bound puzzle ("mx8+mm8xR", the tensor-shaped integer shadow) + +**The claim to test.** Fill the latency shadow (the only lever that moves the f = 1 chip, `chip-model-v3.md` 5.7, `latency-shadow-2026-10-06.md`) with work shaped like a GPU's own tensor datapath rather than its scalar ALUs, so that a chip must carry GPU-class matrix units whose energy per operation NVIDIA's own silicon already sits near the floor of, and the chip's residual edge `k` (its energy per op divided by the GPU's) cannot fall far under 1. The brief's other candidates are rejected on definition: shared-memory bank timing and register-file width are timings and capacities, not values, and a consensus rule can only check values; a per-warp scratchpad was measured and found not sound as a chip layer (`docs/analysis/scratch-soundness.md`: the live state is bounded by the read-modify-write count, 64 to 320 bytes per lane, which a chip keeps in SRAM at under 5 percent of its mirror). + +**The puzzle.** Class v3 (mixer x8, 16 loads, the 64 base instructions, the era draws) plus a block of `R` `mm8` steps executed at the end of every iteration, after instruction 63 and before the next iteration samples `sel`; `8 R` steps per hash, no load in the block, the base program untouched (the same seam the class v4 shadow uses, `latency-shadow-2026-10-06.md` section 2, so the acceptance rule of 1.4.6 keeps its verdict draw for draw). Step `k` has four draws from the program stream after the base and shadow draws: `a = below(8)`, `b = below(7) + (b >= a)`, `c = below(8)`, `c2 = below(7) + (c2 >= c)`. Its semantics over the unit: + +``` +A: 8 x 16 uint8 lane l holds A[l >> 2][4 (l & 3) .. 4 (l & 3) + 3] = the 4 bytes of r[a] (byte 0 = lowest k) +B: 16 x 8 uint8 lane l holds B[4 (l & 3) .. +3][l >> 2] = the 4 bytes of r[b] +C = A x B C[i][j] = sum over k of A[i][k] B[k][j], exact in int32 (at most 1,040,400) +r[c] = r[c] + C[l >> 2][2 (l & 3)] (mod 2^32) +r[c2] = r[c2] + C[l >> 2][2 (l & 3) + 1] (mod 2^32) +``` + +This is the fragment layout of PTX `mma.sync.aligned.m8n8k16.row.col.s32.u8.u8.s32` with the two `.s32` outputs `d0`, `d1` of each lane (PTX ISA, "Matrix Fragments for mma.m8n8k16", the integer layout; `docs/analysis/int8-matrix-family.md` 2.2 quotes it and `proto-cuda/family-probe.cu` carries the CPU reference that was bit-exact on the RTX 5090 on 5 October 2026, `counter-asic-3-status.md` item 6). The spec defines the matrices and the lane ownership, not the instruction: a vendor permutes its own fragment layout into this one (a shuffle) and the result is defined whatever the hardware. Why TWO destinations where the reserve entry R8 of 1.13.2 has one: with one element per lane only 32 of the 64 products of C are consumed, so a chip does 512 multiply-adds per step where the GPU does 1,024 and the GPU hands the chip a free 2x on the block; with both outputs consumed the whole tile is load-bearing. This is a correction to the reserve text as well (section 7). Unit of work: still the unit. Header, difficulty: unchanged; the class byte 5. + +**Parameters and the verifier's law.** Per unit the verifier adds `8 R x 1,024` unsigned byte multiply-adds (the register-major interpreter already holds the 32 lanes' registers, so A and B are in hand). Plain scalar C: about 2 ops per multiply-add, 16,400 ops per step per unit; at the 18 G op/s the x8 verifier shows on the M5 Max core (`chip-model-v3.md` 5.7, measured) that is 0.9 microseconds per step per unit: `R = 128` adds about 0.9 ms, `R = 512` about 3.7 ms. With a byte-dot instruction (AVX-VNNI `vpdpbusd`, 64 multiply-adds per instruction; NEON `udot`, 16 per instruction) the same work is 4x to 16x fewer instructions (approximate). The headroom is the class v3 margin: 7.9 ms steady on the M5 Max core, 4.6 ms on a 2019-class core by the 2.5x rule (`latency-shadow-2026-10-06.md` section 4), so scalar `R` is bounded near 500 on the 2019 core and the measured rows of section 5 set it. On the GPU side the 5090's dependent-chain probe runs `mm8` at 2.43x the add-xor-rotate step, 7,941 / 2.43 G lane-steps per second = 102 G `mm8` per second per card, 104 T multiply-adds per second (the chain probe, not the tensor peak); at 4.25 M units per second (136 MH/s) the card could hide about 24,000 `mm8` per hash before the probe rate binds, `R` about 3,000, far above what the verifier allows. So the verifier binds first, at about `R = 500` scalar on a 2019 core (approximate until section 5) and perhaps 4x higher with VNNI: the honest card never leaves the latency bound on the candidate `R`. + +**Chip edge per joule (chip-model-v3 method).** The f = 1 chip (memory, controller, static: 0.466 microjoules per hash on GDDR7, 0.321 on one HBM3 stack, `chip-model-v3.md` 5.4) plus a tensor array: energy per hash = memory + `8 R x 1,024 x e_mac x k_mma`, where `e_mac` is the honest card's marginal energy per multiply-add at the block (measured in section 5 as watts delta over MACs per second) and `k_mma` the chip's ratio to it. The difference from the ALU shadow (`k` down to about 0.3 for a fixed-datapath array at N5, `latency-shadow-2026-10-06.md` 6) is where the honest card's engine sits: NVIDIA's tensor cores are int8 multiply-add arrays at N4/N5-class density already, so a chip's array is the same circuit (approximate: int8 MAC datapath about 0.05 to 0.1 pJ at N5, the movement of fragments through the register file the larger term on both sides; from memory) and `k_mma` is near 1 with a floor near 0.5 for a chip that keeps the fragments in a local register file instead of the GPU's banked one. Rows at `k_mma` = 1, 0.5 and the measured `e_mac` are filled in section 5.3 from the 4090 measurement; the shape of the result is already clear: the block lowers the chip's edge by the same mechanism as the ALU shadow and the chip's best case is better bounded, at the price that the honest card's own watts rise by the block's energy (the tensor path is efficient, so the rise per unit of chip-forcing work should be smaller than the ALU shadow's 11 pJ per op; the measurement says). + +**Bit-exactness across vendors.** + +| Vendor | Path | State | +|---|---|---| +| NVIDIA sm_75 and later (Turing, Ampere, Ada, Blackwell) | one `mma.sync.m8n8k16.u8` per step, identity permutation, wrap on the `.s32` accumulate (the wrap edge vector of the R8 entry was bit-exact on the 5090, `int8-matrix-family.md` 3) | measured bit-exact on the 5090 (5 October) and on the 4090 tonight (section 5) | +| NVIDIA sm_61 to sm_72 (Pascal GTX 10 series, Volta) | no `mma` with `.u8`; emulation: 8 `__shfl_sync` gathers plus 8 `dp4a` per lane per step (`dp4a.u32.u32`, sm_61+) | unmeasured; cost about 16 steps per `mm8` against 2.43 native, approximate; within the 8x emulation bound of 1.13.2 on a per-op basis only if the shuffles are cheap; a GTX 1080 owner is the first NVIDIA tier to pay | +| AMD RDNA 3 and 4 (gfx11, gfx12) | `V_WMMA_I32_16X16X16_IU8` with the 8 x 16 and 16 x 8 tiles zero-padded to 16 x 16 and a fixed lane permutation (`ds_bpermute`) into the spec layout; the RDNA 4 builtin takes 2 ints per lane for A and B (`int8-matrix-family.md` 1) | the fragment layout is UNVERIFIED (status item 6: not in any source at hand; the CPU reference was not attempted rather than guessed). This is the gate for AMD: a PC 1 job on the 9070 XT with the spec reference. Until it passes, AMD runs the emulation path (`v_dot4_u32_u8` is native on gfx11 and gfx12, 1.06x per op measured) at about 12 to 16 steps per `mm8`, approximate | +| AMD RDNA 2 and older, CDNA | no WMMA on RDNA 2; `v_dot4_i32_i8` exists (`dot1-insts`, signed only, approximate); CDNA 3 has `V_MFMA_I32_16X16X32_I8` with its own layout | emulation; unmeasured | +| Apple (M-series, Metal) | no integer `simdgroup_matrix` in MSL; Metal 4 `mpp::tensor_ops::matmul2d` has `uchar x uchar -> int` (table 7.3, OS 26.4) through a tensor API not reachable from the Swift toolchain this project uses, and its wrap semantics are unverified (`int8-matrix-family.md` 1). The emulation: 4 shuffles plus 4 unsigned `dot4` emulations at 1.6x per op (measured 5 October), about 10 ALU steps per `mm8` | an Apple miner pays about 4x NVIDIA's per-step cost on the block (approximate); the M5 Max is latency-bound to about 130,000 counted ops per hash (measured), so `R = 128` (1,024 `mm8` per hash, about 10,000 steps emulated) fits inside its shadow and `R = 512` (about 41,000) still does by the ops count, with the hash-rate cost owed to a Metal measurement. Apple's path is the honest card's worst and the chip's argument does not depend on it | +| Intel Arc | XMX through `cl_intel_subgroup_matrix_multiply_accumulate` (approximate, unverified); dp4a-class `dot` otherwise | unmeasured | + +So the fleet splits by generation: Turing-and-later NVIDIA and RDNA 3-and-later AMD run the block natively; everything older and Apple emulate. The 5 percent rule (`counter-asic-2-public.md`) is checked per card with the block live, as 1.13.2 requires for an emulating vendor. + +**Known attacks.** Grinding: none new; the block has no data-dependent control flow and reads no memory. Outsourcing, precomputation: as today (the draws are public per epoch; there is nothing to precompute because the inputs are the per-nonce registers). Light evaluation (the f = 0 chip): untouched; the block never reads the dataset. MTP-class content control: not applicable (no attacker-chosen memory). Sampleability: not applicable. New: (i) the half-tile shortcut, closed by the two-destination form above; (ii) a zero or low-entropy fragment (if `r[a]` is zero in every lane the step is free): the acceptance rule's register-saturation test (1.4.6 (c)) already rejects programs with stuck registers, and the base program's loads re-randomise every register every iteration; (iii) the trailing-step contraction: the last `mm8` of the last iteration writes two registers that feed only the fold; a chip could skip nothing because the fold reads all eight, but a step whose destinations are both never read again before the fold still costs the GPU a full tile; the draw rule should forbid `c, c2` outside the fold's register set, which is every register, so there is no such step. (iv) The licensable-IP objection (the history's reason for ranking `mm8` last in the reserve, `asic-resistance-history.md` 4.3 row 6): a chip maker licenses an int8 MMA block at any node. True, and it is the point of the design: the chip must then carry a GPU-class tensor array per 32 lanes in flight at the memory's activate ceiling, 1,172 lanes on GDDR7 (`chip-model-v3.md` 5.5), 37 tiles in flight, and its edge is `k_mma`, a ratio of two copies of the same circuit; the design does not claim the chip cannot be built, it claims the chip is a GPU. + +**Game theory.** None of the payment changes; this is a hash change. A pool user sees nothing. A prover that mines pays the block's watts on the same card it proves on; the tensor path is also the proving path's (SP1's Poseidon2 and NTT kernels are integer, not tensor, so there is no contention beyond the power limit, approximate). When proving demand is zero nothing changes. + +**Migration.** Class v5 by P2: the object byte 5, the 95 percent one-day window, the floor height; one-sweep binary rollout because the digest flips; Devnet 2 gate first. The kernel emitter (`igneum-pow/src/emit.rs`) gains the block in its three dialects, the CUDA one with inline PTX and the `IGNEUM_MM8_REF` fallback for sm_61 to sm_72, the OpenCL one with the AMD builtin behind a feature test and the emulation otherwise, the Metal one with the emulation; the one-click workers compile the text as they do today (NVRTC accepts inline PTX). Gates before a cut: the six gates of `counter-asic-2-rollout.md` section 7 plus the AMD layout verification and the Metal emulation's hash-rate cost on the M5 Max. + +### 3.3 Scheme C: proof of stored state ("sd1", the dataset is the chain) + +**The claim to test.** The dataset is the recent chain state, so every hash proves the miner holds the chain, and the lottery's reads double as a verifiable random sample of state for light clients. + +**The puzzle.** Day `d`'s snapshot `SS(d)` is the execution state at the state root `R_d` of the certified checkpoint `C_day(d)`, the highest-index checkpoint whose block has DAA score at most `86,400 d - 1,200` (the epoch seed's lead, spec 4.3). Its leaves: the `(key, value)` pairs of the execution state trie in key order (storage slots, account records, 64-byte chunks of code), leaf `t` serialised as `leaf(t) = Blake2b-512(R_d || t_le32 || key_t || value_t)` (the chain's own hash, spec 0.6), 64 bytes each, so every leaf carries full entropy whatever its content and no two days share a leaf; for `t` beyond the state's leaf count `leaf(t) = 0`. When the state has more leaves than the dataset has items, the dataset holds the first `2^(D-4)` leaves in the order of `Blake2b-256(K_d || key)`: a keyed sample that cannot be chosen without the whole state. The item derivation is class v3's with one line added before the round loop: `s[i] ^= leaf(t)[i]` for `i` in 0..15. The hash kernel is byte for byte the shipped one; only the daily build changes. Header commitment: none new. `R_d` is the state root of a block in the header's own past at a fixed blue score, so "which snapshot was this block mined under" is a function of the header alone once the chain is known, as the program is (spec 1.12). The class byte 5 marks the object. Difficulty: unchanged. Unit of work: unchanged. + +**The verifier.** A node holds the 256 MiB cache (as today) and `SS(d)` in RAM or mmap (2 GiB at the genesis dataset size, growing on the 1.13.3 schedule), derives up to 4,096 items per unit lazily as today and reads `leaf(t)` for each: 4,096 random 64-byte reads. The measured cost of those reads and of the derivation is section 5.2. Verifier memory: +2 GiB (+4 GiB at year 4). The daily snapshot build: one pass over the state trie, hashed per leaf (one Blake2b-512 per 64 bytes: about 2^25 hashes for 2 GiB, seconds on a core, section 5.2 measures the stand-in). + +**What is new, and the prior art.** Permacoin (Miller, Juels, Shi, Parno, Katz, IEEE S&P 2014) made the puzzle a proof of retrievability over a large PUBLIC FILE chosen by a dealer, with Merkle openings in each block; the file was external to the chain and the openings were the bytes. Spacemesh (proof of space-time over a plotted file of random data) and Chia (Abusalah, Alwen, Cohen, Khilko, Pietrzak, Reyzin, "Beyond Hellman's time-memory trade-offs with applications to proofs of space", ASIACRYPT 2017; Chia's plots) prove storage of USELESS data. Verthash (Vertcoin, January 2021; `asic-resistance-history.md` row 8) is the nearest: a 1.2 GB file generated from the chain's own block headers, random reads, no chip after 69 months on a small prize; its data is headers (low entropy per byte, static once written) and it proves nothing about state. Ethash's DAG is from the epoch seed (random). What Igneum C adds: (1) the dataset is the EXECUTION STATE, keyed per day by `K_d` through the memory-hard derivation, so it is never easier than today's dataset (the leaf is one more 64-byte input to a 9,360-op chain) and it cannot be built from the day key alone: whoever builds it holds the state; (2) every block's 128 loads per lane name 128 keyed items whose leaves are a uniformly random sample of state (the addresses are the mixer-state cache-line indices through 128 dependent reads, unbiasable by the producer at a cost below a block), so a light client that asks any full node for the block's `(key, value)` leaves with their openings against `R_d` gets a free daily spot check of state availability; (3) the beacon: the lottery output is already public randomness, biasable by withholding at the cost of a block, as every PoW; C adds nothing there and the design says so. Honest limit: a pool can ship the 2 GiB dataset or the snapshot to its miners once a day (2 GiB per miner per day, 23 MB/s for a thousand miners), so "every miner holds the chain" is really "every mining OPERATION holds the state", which is still a change: today a pool miner needs nothing but the day key. + +**Chip edge per joule.** Unchanged against the f = 1 chip (it stores items whatever they are): 5.1x on GDDR7, 7.5x to 9.2x on HBM3 in the model, 2.1x to 4.8x by the Ethash precedent. The f = 0 recompute chip must hold the leaves (2 GiB) in DRAM to derive anything, so it becomes an f = 1 chip and the 0.31x row disappears. C is therefore not an anti-chip scheme and does not claim to be; it composes with B (the shadow is in the kernel, the state is in the build). + +**Bit-exactness.** The leaf is the output of the chain's own hash over bytes every node agrees on by consensus; the derivation is integer; nothing vendor-specific is added. The one new consensus-critical function is the canonical serialisation of state (key order, chunking of code), which every node must compute identically: a bug there splits the chain on a day boundary, the class of M20 and the DAA 198,000 incident. The Devnet 2 gate exists for exactly this. + +**Known attacks.** State grinding: a producer can write state (pay gas) to influence leaves; the leaf is hashed with `R_d`, which depends on every leaf, and enters a keyed chained derivation whose read addresses are mixer state, so no bias on 128 dependent reads is reachable at a cost below a block (the MTP lesson, `asic-resistance-history.md` 2.3, is the reason for the hash and the key, not the plain bytes). Compressible state: an attacker fills state with zeros hoping a chip stores it compressed; the hashed leaves are full-entropy, and the padding region (`leaf = 0`) is today's dataset, which the chip already stores at 64 B per item. Precomputation: the snapshot is fixed when `C_day(d)` is certified and `K_d` is known, 20 minutes before the day (the same lead as the epoch seed), and the build is 13 to 77 ms on the GPUs measured (`counter-asic-3-status.md`) plus the leaf pass; a reorg across `C_day(d)` is a merge-depth-scale event, accepted as for the epoch seed (spec 4.3 item 4, O-4.3). Outsourcing: the pool ships the dataset (above). Light evaluation: the f = 0 row above. Long-range: an attacker building an alternative history must build its alternative state snapshots to mine on it, which it does anyway; no change. Finality pause: `C_day(d)` must be certified; if finality is paused for more than the lead the day's snapshot is not derivable and mining would stop, the coupling spec 4.3 argues against for the epoch seed. Rule, as there: take the selected-chain block at that blue score certified or not, deep enough that a reorg across it is a merge-depth event. Empty state at launch: every leaf is `Blake2b(R_d || t || empty)`, full entropy, the dataset as good as today's: graceful. + +**Game theory.** No payment changes. A miner must run or rent a node (or trust a pool's dataset); the solo-mining floor rises by a full node's state (today's devnet: megabytes; a used chain: gigabytes). A pool user sees a 2 GiB daily download or nothing (the pool serves the dataset). A prover that mines already holds state. A holder gains a daily sample of state availability per block, for free. A rollup customer gains nothing directly. + +**Migration.** Class v5 by P2 (object byte 5, 95 percent over a day, floor height, one-sweep rollout, Devnet 2 first). Every node needs the snapshot builder before the flip (a node without it cannot validate PoW after the flip: the floor height's job). Workers need nothing new: the kernel text is unchanged, the dataset arrives from the node's `prepare` line as today, built on the GPU from the cache plus a leaf array the node hands over (2 GiB per day over the local socket) or built on the node's CPU and uploaded. The one-click miner's "nothing to install but the driver" line holds; "nothing to download but the day key" does not. + +### 3.4 The three schemes in one table + +| Scheme | What it is | Chip edge per joule vs the 5090 (f = 1 chip, chip-model-v3 method) | Verifier ms per unit (model, then measured in section 5) | Vendor bit-exactness | Ships as class v5? | +|---|---|---|---|---|---| +| A, mining is proving | A1 committed codeword, A2 proving steps: dead on bytes and on sampleability; A0 trace-as-dataset survives and is C with the trace as state | A0 unchanged (5.1x GDDR7); A1, A2 not priced | A0: 2.06 + the leaf-read row; A1: 2.9 MB of openings; A2: 32 to 40 ms | A0 adds the zkVM executor to consensus | NEVER as mining = proving; A0 folds into C | +| B, tensor-shaped shadow | class v3 plus `8 R` int8 8x8x16 tile steps per hash in the PTX fragment layout, two outputs per lane | memory + `8 R x 1,024 x e_mac x k_mma`; `k_mma` near 1 with a floor near 0.5 (approximate); rows from the measured `e_mac` in 5.3 | 2.06 + about 0.9 microseconds per step per unit scalar (R = 128: +0.9 ms; R = 512: +3.7 ms); VNNI 4x to 16x less | native on sm_75+ and RDNA 3+ (AMD layout unverified); emulated on Pascal, RDNA 2, Apple | prototype further; a class v5 candidate after the AMD gate | +| C, stored state | the daily dataset derives from the execution state snapshot; kernel unchanged; a state sample per block | unchanged (5.1x GDDR7, 7.5x to 9.2x HBM3); the f = 0 chip disappears | 2.06 + 4,096 leaf reads (section 5.2) | nothing vendor-specific; the serialisation is the consensus risk | prototype further; a class v5 candidate on its own or beside B | + +### 3.5 Migration through the class system (common to B and C) + +The P2 rule as designed (`docs/plans/counter-asic-3-node.md` section 6): the header version's high byte carries the producer's object version; epoch `e` is the new class when the window of one day ending at its seed block has at least 9,500 bps of blue blocks at or above the byte, or when the floor height `N` is reached, or when epoch `e - 1` already was; the rule answers v5 only where it would answer v4. For B and C the object byte is 5 and the floor is set at the publish as DAA + 14,400 rounded up to the epoch boundary. The order: Devnet 2 crossing with `tools/fleet/devnet2-gate.sh` (zero rejected blocks across the flip, no reorg over depth 3, exec roots agreeing, a segment record paid, every node on the new version), then the live devnet in one binary sweep (the digest flips), then the flip by signal. A node that synced from a pruning proof takes the floor rule for epochs whose window reaches below its pruning point (the same class as the era witness, status item). For C the floor also bounds how long a non-upgraded node can keep validating PoW: none after the flip, so the sweep must be complete before the floor, which is the 10,800-DAA check already in the rule. + + +## 4. Reviews: two personas, two short reviews per scheme + +Written by this lane in the persona files' voices (`.claude/agents/cryptographer.md`, `.claude/agents/consensus-engineer.md`): every design claim with its attack, every claim about another chain with its file, and the smallest change the code allows. Each review names the break if there is one. + +### 4.1 Scheme A, mining is proving + +**Cryptographer.** The break is structural and has a name: a lottery needs a distribution of instances and proving has one instance per segment. A1 moves the work into the commit phase and pays for it in witness bytes (2.9 MB per block, or 90 KB with the unit cut to one lane, which also removes `shfl` and with it the only thing that makes the 32-lane unit a unit; `docs/spec/01-lottery-hash.md` 1.9). A2 either recomputes (useless by definition) or verifies a proof (32 to 40 ms measured, `proving-methods.md` 2.1; the gate is 10 ms). The useful fraction bound (proving work per segment over network hashes per segment) is the argument Ball, Rosen, Sabin and Vasudevan make in the negative direction: without a random self-reduction the embedded instance is a constant, and a constant is amortised to zero by the first miner who computes it. A0 is sound as far as it goes and is scheme C. Second attack on A0 that C does not have: the SP1 executor enters the consensus path for the lottery, so an executor bug that produces a different trace on one platform (an undefined-behaviour corner in a precompile patch, a `sha3` or `k256` version skew) splits the chain at the PoW, not at the proof; ledger P7 priced that class for proofs where the native veto bounds the damage to one payout; here nothing bounds it. Verdict: never for A1 and A2; A0 only as C with the trace, and then the state is the better choice of data because every node already agrees on it without a second executor. + +**Consensus engineer.** The code says the same thing from the other side. Block validation in the fork validates the header's PoW before the body is fetched and before execution (`check_pow` on the header path, rusty-kaspa's `header_processor`; the fork's `igneum/exec` runs after the block is accepted into the DAG). A puzzle whose verification needs the segment's trace makes header validation wait on the executor of a segment 20 minutes old, which is fine for a synced node and fatal for IBD: a syncing node must execute every segment of history, in order, to validate the headers of history, so headers-first sync and the pruning proof (which validates headers without bodies) are gone; Kaspa's pruning-point sync (`consensus/src/pipeline/pruning_processor`, approximate location) assumes PoW is a function of the header and a small amount of context. A0 shares this break with C and C answers it in 4.3 by making the snapshot a function of a certified checkpoint's state root plus the state itself, which a pruned node fetches as a snapshot (the exec snapshot path the node already has, CLAUDE.md 6 Oct rule "the p2p snapshot path refuses a snapshot below the node's tip"). For A1 the 90 KB per header kills the header relay and the 600-block record window arithmetic alike. Verdict: never for A1 and A2; A0 is C with a worse data source. + +### 4.2 Scheme B, the tensor-shaped shadow + +**Cryptographer.** No break in the puzzle's soundness: the block is a straight-line integer map with no memory and no data-dependent control flow, its inputs are the per-nonce registers, and the two-output form makes the whole tile load-bearing. Two things to name. (i) The claim that `k_mma` cannot fall far under 1 rests on the honest card's tensor path being near the floor of int8 multiply-add energy; that is an engineering judgement, approximate, and the external chip review (status item 3, `funding.md`) is where it is tested, with the ALU shadow's `k` beside it. The design's advantage over the ALU shadow is bounded, not proven: it narrows the chip's best case from about 0.3 to about 0.5 (approximate) and does not remove the edge. (ii) The fragment layout is a specification of lane ownership; every emulating vendor must reproduce it exactly, and the AMD WMMA layout is unverified (status item 6). Until a 9070 XT run with the spec reference passes, B is bit-exact on one vendor's hardware and in every emulation, which is the state class v2 was in on 3 October (ledger M8) and not a state to cut from. No grinding, outsourcing or precomputation surface is added. A statistical point: the mm8 step's outputs are sums of 16 byte products, so each added value is at most 1,040,400 and its top 12 bits are zero; added into a register it changes the low 20 bits in a structured way. That is fine inside a chain of multiplies and rotates, and the stats run of `TESTS.md` section 3 should be run on the class before any vector is frozen. Verdict: prototype further; a class v5 candidate after the AMD gate and the stats run. + +**Consensus engineer.** No consensus change beyond the class byte and the emitter: the block is kernel text (`igneum-pow/src/emit.rs` gains the step in the three dialects), the verifier (`verify.rs`) gains the step in the register-major loop, the acceptance rule is untouched by construction, and the node's seam is the v5 switch beside the v4 one (`counter-asic-3-node.md` section 1 lists every file the v4 switch touched; v5 is the same list with one more number). The break to name is operational: the fleet splits by hardware generation. Pascal, Volta, RDNA 2 and every Apple card emulate, and the one-click workers compile three paths where they compile one today; the OpenCL path on AMD needs a feature test at compile time (the WMMA builtin exists on gfx11 and gfx12 and not on gfx10, `int8-matrix-family.md` 1), which the pack text must carry as a preprocessor branch, and a wrong branch is a wrong hash, which the self-test catches before the worker serves (`packfile.h`, M28's fix). The 5 percent rule must be checked per emulating card with the block live, and the Apple row is the one most likely to fail it at high `R`. Verdict: prototype further; set `R` from the measured rows with the Apple emulation measured on the M5 Max before any cut; the AMD layout is a hard gate. + +### 4.3 Scheme C, proof of stored state + +**Cryptographer.** The construction is never weaker than today's: the leaf is one more input to the same chained derivation, keyed by the day key through the first mixer, and the f = 1 chip's row is unchanged, which the design says. The break to name is the one Permacoin and MTP both met: who controls the data controls the addresses, unless the data enters through a key the controller does not have. Here the controller of state content (anyone paying gas) does not control `K_d` (a VDF output fixed 20 minutes before the day, spec 4) and the leaf is `Blake2b(R_d || t || key || value)`, so the only lever is choosing content before `R_d` is known, which affects every leaf through `R_d` and none in a predictable way. I find no bias at a cost below a block. The second point: the "verifiable sample of state" is real but modest. A block commits to 128 leaves per lane through 128 dependent reads; a light client checking them needs openings against `R_d` from a full node (depth about 25 at 2^25 leaves, 128 x 25 x 32 B = 102 KB per block if fetched, arithmetic), which is a spot check of availability, not a proof of state correctness; the consensus proof of spec 10 and ledger P4 is still what a light client needs for correctness. The design says this. Third: the canonical serialisation is new consensus-critical code, and the day-boundary flip is the moment it bites (every node rebuilds at once). Verdict: prototype further; a class v5 candidate; the serialisation needs the same test discipline as the DAA switch (a Devnet 2 crossing over a day boundary with a non-trivial state). + +**Consensus engineer.** The break I would have named, the IBD and pruning-proof problem of A0, C answers: the snapshot is a function of `R_d`, a state root at a certified checkpoint, and the node already carries an exec snapshot path (`exec_restart_*` fields, the p2p snapshot message, CLAUDE.md 6 Oct). A syncing node validates historical PoW only by holding every day's snapshot, which is 2 GiB per day of history, which is NOT acceptable for IBD. Fix, the smallest I can see: PoW of blocks below the pruning point is not re-validated (Kaspa's pruning proof validates the proof's headers' PoW; rusty-kaspa `consensus/src/processes/pruning_proof`, approximate), so historical snapshots are needed only for the headers inside the proof, which are a bounded set per level; and for them the proof carries the day's `R_d` and the node either holds that day's state (recent days) or trusts the certificate (the finality rule's lock already makes those headers irreversible). That is a spec item for `docs/spec/10-light-client.md` and the pruning section of spec 02, and it is the same shape as the era-seed witness (status item). Second: the verifier's RAM (+2 GiB, +4 GiB at year 4) and the daily build on a node without a GPU (a seed node, a Hetzner box: the leaf pass is CPU work, measured in 5.2) must stay inside the node's budget; the devnet hands on igneum-build-1 have 128 GB, a home node has 16. Third: a day boundary is now a consensus event that depends on a certified checkpoint 20 minutes before it; under a finality pause (6 October, 18:42Z) the day's snapshot falls back to the uncertified selected-chain block, as spec 4.3 argues for the epoch seed; the rule must be written once and tested on the fast-time harness across a pause. Verdict: prototype further; a class v5 candidate; three spec items (pruning-proof witness, the pause rule, the node RAM budget) before a cut. + +### 4.4 The pick + +B and C are the two to prototype: both are class objects on the shipped hash, both leave the dataset's memory bound untouched, and they compose (B is kernel text, C is the daily build). A is not prototyped: A1 and A2 fail on bytes and on sampleability before any kernel, and A0 is C with a worse data source. The order of merit at this point, before measurement: C first (no vendor risk, unchanged hash rate by construction, a real new property per block, the pool caveat stated), B second (a real lever against the f = 1 chip with a bounded `k`, a vendor split and an unverified AMD layout). Section 6 revisits the order on the measured rows. + +## 5. The prototypes and the measured rows + +Both prototypes live under `proto-newpow/` with a README carrying the exact commands, the card, the driver and the RESULTS table; this section carries the rows and their consequences. Boxes: two RunPod RTX 4090 24 GB (driver 595.91, nvcc 12.8, `-arch=sm_89`), quiet, the card to itself; CPU rows on igneum-build-1 (EPYC 9454P, one pinned core, `nice -n 19`). Power by `nvidia-smi` at 1 Hz, the mean after the first 10 s of each timed run. Bit-exactness: the PTX path against the reference path on 2^24 lanes (fingerprint), and the GPU against the C CPU reference on 1,024 random lanes. + +### 5.1 `mma-shadow` (scheme B), box 1 + +ROWS_B + +### 5.2 `state-dataset` (scheme C), box 2 and igneum-build-1 + +ROWS_C + +### 5.3 The chip rows on the measured numbers + +CHIP_ROWS + +## 6. Verdicts + +| Scheme | Verdict | Why, in one line | +|---|---|---| +| A, mining is proving | NEVER (A1, A2); A0 folds into C | one proof per segment is not a distribution of puzzles; the bytes (2.9 MB of openings per block) or the verify (32 to 40 ms) kill every form that is not "hold the trace", and holding the trace is C with a worse data source | +| B, tensor-shaped shadow | VERDICT_B | +| C, stored state | VERDICT_C | + +**A, in full.** The mandate asked for something never done, and "mining is proving" is the thing everybody has wanted and nobody has shipped; this lane's contribution is the reason, stated as a bound rather than a feeling: the useful fraction of a proving-as-lottery scheme is (proving work per segment) / (network hashes per segment), 8 percent at 1 GH/s and 0.08 percent at 100 GH/s on this chain's measured figures, because gas sets one and the security budget sets the other, and a puzzle whose verifier either recomputes the piece or verifies a 32 to 40 ms proof cannot sit under a 10 ms gate. The 80/20 split stays. Ledger F13's answer stands and gains this bound. What survives (A0) is scheme C. + +VERDICT_BC_PROSE + +## 7. Ranked next steps + +Hours are agent hours (the project lead's rule: Claude-side work takes hours). Each gate is a measurable pass line. Consequence per tier is the row's own. + +| Rank | Proposal | Evidence | Model | Hours | Consequence per tier | Gate | +|---|---|---|---|---|---|---| +| 1 | Scheme C as class v5 content: the daily dataset derives from the state snapshot (`sd1`), spec text for 1.8.5 (the leaf line), 1.12 (the snapshot's checkpoint and lead), 10 (the pruning-proof witness), 4.3's pause rule applied to the day boundary | section 5.2: the hash kernel and rate are unchanged by construction, the build and verifier costs are the measured rows; every miner operation must hold state | the verifier row: 2.06 ms + the leaf-read row per unit; node RAM + the dataset size | spec 3 h; emitter and `memhard.rs` leaf line 2 h; node snapshot builder (canonical serialisation, one pass per day, the `prepare` hand-over) 6 h; fast-time harness across a day boundary and a finality pause 3 h; Devnet 2 crossing 2 h | 8 to 32 GB cards: no hash-rate change, +2 GiB device memory during the build only (streamable); rig: the same per card; pool user: a 2 GiB daily download or nothing; solo miner: a full node's state; node operator: +2 GiB RAM (+4 at year 4) and a daily leaf pass; holder: a daily random sample of state per block; prover, rollup customer: nothing | the fast-time 3-node network crosses a day boundary with a non-trivial state and no fork; verifier under 10 ms on a 2019-class core with the snapshot in RAM; Devnet 2 PASS over a day boundary | +| 2 | Scheme B's AMD gate: the WMMA iu8 fragment layout on the RX 9070 XT against the spec reference (the two-output tile), a PC 1 job with the card alone | status item 6 (layout unverified); section 5.1's bit-exact rows on NVIDIA | the spec layout as the definition; a lane permutation per vendor | 3 h (the probe exists: `family-probe.cu` mm8 row; the OpenCL twin needs the builtin path and the permutation) | AMD 16 GB tier: decides whether RDNA 3 and 4 run B natively or emulate at about 12 to 16 steps per mm8 | 1,024 random units bit-exact on the 9070 XT, both tile outputs | +| 3 | Scheme B's Apple row: the emulated mm8 block in Metal on the M5 Max at R = 32, 128, 512, hash rate and watts under `with-lock.sh measure` | section 3.2's vendor table: Apple is the honest card's worst case; the M5 Max binds at about 130,000 counted ops | 4 shuffles plus 4 dot4 emulations per step, about 10 steps per mm8 (approximate) | 3 h | Apple tier: the 5 percent rule decides the largest R the class can carry | rate within 5 percent of mx8 at the chosen R; bit-exact against the C reference | +| 4 | Scheme B as class v5 content beside C (`mx8+sd1+mm8xR`) once ranks 2 and 3 pass: the emitter's three dialects (inline PTX with the `IGNEUM_MM8_REF` fallback for sm_61 to sm_72, the AMD builtin behind a feature test, the Metal emulation), the verifier step in `verify.rs`, the stats and fuzz runs of `TESTS.md` on the class, the v5 switch beside v4 | section 5.1 and 5.3: the block's measured watts and the chip rows at k | the chip rows of 5.3 | emitter 4 h; verifier 1 h; suites 2 h; node seam 2 h; Devnet 2 2 h | NVIDIA Turing and later, AMD RDNA 3 and later: native, the measured watts; Pascal, RDNA 2, Apple: emulation at the measured 5 percent check; pool user: nothing; chip: a tensor array per 32 lanes in flight | the six gates of `counter-asic-2-rollout.md` 7 plus the AMD and Apple rows; verifier under 10 ms on a 2019-class core at the chosen R | +| 5 | The reserve text correction: R8 `mm8` consumes both tile outputs (two destinations) so a chip cannot halve the work | section 3.2 (the half-tile shortcut) | arithmetic: 32 of 64 products consumed in the single-output form | 1 h (spec 1.13.2 text and the edge vectors) | none until era 4 or a signal | the R8 edge vectors re-cut for two outputs, bit-exact on the three vendors | +| 6 | The light-client state sample: a node RPC that returns, for a block, the 128 leaves of lane n with openings against R_d, and a client check | section 3.3 (the sample is real but modest: availability, not correctness) | 128 x 25 x 32 B = 102 KB per block fetched on demand (arithmetic) | 4 h | holder and light client: a spot check of state availability per block; node: one RPC | 128 openings verify against R_d on the fast-time network | +| 7 | The 2019-class core measurement (O-1.14) for the verifier under C and under B at the chosen R | every verifier row here is M5 Max or Zen 4 plus the 2.5x rule | the 2.5x rule stands in | 1 h once a core is found (a 2019 laptop or a rented older CPU box) | every tier: the gate that fixes R and the snapshot read budget | under 10 ms per unit, worst cold | +| 8 | Do not build scheme A (mining is proving) in any form; record the sampleability bound (proving work per segment over network hashes per segment: 8 percent at 1 GH/s, 0.08 percent at 100 GH/s) in the ledger beside F13 | section 3.1 and 4.1 | the bound's arithmetic | 0.5 h (a ledger row) | none | none | + +One paragraph each. + +**1. Scheme C first.** It is the cheapest change with a new property: the kernel text, the hash rate and the chip rows are untouched, so every measured number of Counter ASIC 2.0 and 3.0 stands; what changes is the daily build and the node. The cost is a canonical state serialisation in consensus, which is why the fast-time harness must cross a day boundary with state and a finality pause before the Devnet 2 crossing. The pool caveat is stated: the design forces the operation, not the card, to hold state. + +**2 and 3. B's two vendor gates.** B is bit-exact tonight on NVIDIA (section 5.1) and in every emulation; it is not a class candidate until an AMD card reproduces the spec layout and the Apple emulation's hash-rate cost is measured. Both are short jobs with the card alone. + +**4. B beside C.** The order matters: C lands first because it needs no vendor work; B joins the same class byte or the next one once ranks 2 and 3 pass, with R set from 5.1 and the 2019-core row. + +**5 to 8.** Small, named, and each closes a thread this lane opened. + +## 8. Open questions and what could not be run + +| Question | Why it could not be closed tonight | What closes it | +|---|---|---| +| The 2019-class core (O-1.14) | no such core in the fleet; igneum-build-1 is Zen 4, the Mac is M5 Max; the 2.5x rule stands in | rank 7 | +| The AMD WMMA fragment layout | PC 1 is the project lead's desk and the AMD rows were owed all day (status file); no AMD card on RunPod or Vast tonight (fleet agent) | rank 2 | +| The Apple emulation of mm8 | a Metal emulation kernel is a 3-hour job and the Mac measure lock was free; not started because the AMD gate decides first whether B proceeds | rank 3 | +| The canonical state serialisation for C | a design item that touches the exec layer (`igneum/exec`), out of this lane's files | rank 1 | +| The pruning-proof witness for C's historical PoW | spec 02 and 10 items | rank 1 | +| Whether the tensor path's marginal energy on the 5090 differs from the 4090's | one card measured (box 1); the 5090 is on the project lead's desk | a PC 2 job with the same `run.sh` | +| The Ampere row (3060, 3080, 3090) | every Ampere card of the fleet was mining and proving the live devnet; a loaded 3090 was offered and declined (a loaded card's rate is not a number) | one quiet Ampere pod | +| The verifier with a byte-dot instruction (VNNI, NEON udot) | the C reference is scalar | 1 h: an AVX-VNNI and a NEON path in `verify_ref.c`, measured on both cores | +| Scheme C's leaf array on an 8 GB card at the 2 GiB design size | the build holds dataset + cache + leaves on the device (4.3 GiB) unless chunked | the chunked build (section 5.2 says whether it is trivial) | + +## 9. Summary for the coordinator + +SUMMARY diff --git a/docs/evidence/reproduced/0.3.14.md b/docs/evidence/reproduced/0.3.14.md new file mode 100644 index 000000000..32a4d037b --- /dev/null +++ b/docs/evidence/reproduced/0.3.14.md @@ -0,0 +1,14 @@ +# Reproduced: Igneum Miner 0.3.14 (node 4c6b129d75c3d77a3689d22f1e1dc721b556aebb, app a90f6a5371ed19c62511255a4713eb36191848b9) + +06 October 2026, 20:03 UTC on igneum-build-1 by `infra/build-server/repro/rebuild-on-box.sh` (driven by `tools/repro/rebuild-release.sh`): a clean clone of the fork at the node commit on branch `release-0.3.14-node` under a clean clone of the repo at the app commit, 2 independent clean passes per target in one target path each (no sccache, SOURCE_DATE_EPOCH 1791305478, TZ UTC), rustc 1.99.0, x86_64-w64-mingw32-gcc-posix (GCC) 13-posix, clang 18.1.3, glibc 2.39. Shipped hashes read from the public downloads (no token) where marked. Whole run 3 s; log `/srv/builds/_repro/0.3.14/rebuild.log`. + +| Artefact | Shipped sha256 (source) | Box pass A | Box pass B | A vs shipped | A vs B | Reason for a DIFFER | +|---|---|---|---|---|---|---| +| igneumd | 934f393cacc31a06d0c45a9fe2e2f504941a32533110b51851968e70cf90fa3a (given) | 03f35e056922fa1e... (49600096 B) | 03f35e056922fa1e... (49600096 B) | **DIFFER** | **MATCH** | the shipped binary was not on hand this run (no public artefact), so only the hash is compared; the box's needs GLIBC_2.39, embeds /srv/builds/_repro/0.3.14, clock string 16:51:18; commit string 4c6b129d75c3d77a3689d22f1e1dc721b556aebb: 1 hit(s) in the box's binary | +| igneum-miner | 7e296541 (given) | 900c1f0bf8a3b504... (9842168 B) | 900c1f0bf8a3b504... (9842168 B) | **DIFFER** | **MATCH** | the shipped binary was not on hand this run (no public artefact), so only the hash is compared; the box's needs GLIBC_2.39, embeds /srv/builds/_repro/0.3.14, clock string none | +| igneumd.exe | 44fa74c02415ff258b5956ef55909dc97890e3f29fca3d2db26f7152ef4ce541 (given) | 166e604e01c668e6... (51758592 B) | 166e604e01c668e6... (51758592 B) | **DIFFER** | **MATCH** | box exe: Ubuntu GCC 13 posix, -Wl,--no-insert-timestamp (PE timestamp 'Jan 1 01:00:00 1970'), build path /srv/builds/_repro/0.3.14, clock string 16:51:18; the shipped exe itself is not on hand (innoextract 1.9 cannot read the Inno Setup 6 installer: setup loader revision 2; or no public installer for this version), so its hash is the given one and its header was not read; commit string 4c6b129d75c3d77a3689d22f1e1dc721b556aebb: 1 hit(s) in the box's binary | +| igneum-miner.exe | 819ea9ce (given) | fefd266c3bd6470f... (10994688 B) | fefd266c3bd6470f... (10994688 B) | **DIFFER** | **MATCH** | box exe: Ubuntu GCC 13 posix, -Wl,--no-insert-timestamp (PE timestamp 'Jan 1 01:00:00 1970'), build path /srv/builds/_repro/0.3.14, clock string none; the shipped exe itself is not on hand (innoextract 1.9 cannot read the Inno Setup 6 installer: setup loader revision 2; or no public installer for this version), so its hash is the given one and its header was not read | + +Full box hashes: igneumd A 03f35e056922fa1e406e14d35963e8d3ca57f98f0d58a04c3f7cc450a26d1fdc; igneum-miner A 900c1f0bf8a3b504dfb2a7fa7abb91f3286eb0d020ed1e0aa5f3ab808c0489eb; igneumd.exe A 166e604e01c668e69b88556cad959429c67b040ec1e024cf7e514e1b5fc8edae; igneum-miner.exe A fefd266c3bd6470f61476a96453d4ea0cb54c42b8b23038cf5ef5a3397399514; + +Reading: MATCH against the shipped bytes is the goal; A vs B MATCH with a DIFFER against the shipped bytes means the box is deterministic and the shipped build came from another toolchain (the reason column says which facts differ); A vs B DIFFER is a non-determinism on the box itself and is the row to fix first. diff --git a/docs/evidence/reproduced/0.3.15.md b/docs/evidence/reproduced/0.3.15.md new file mode 100644 index 000000000..6f28b6534 --- /dev/null +++ b/docs/evidence/reproduced/0.3.15.md @@ -0,0 +1,14 @@ +# Reproduced: Igneum Miner 0.3.15 (node 713ef876073d3661e9b48d2ead9a515afd1b2156, app 563485b769868ee34a530f1c40f7419109cc493f) + +06 October 2026, 20:03 UTC on igneum-build-1 by `infra/build-server/repro/rebuild-on-box.sh` (driven by `tools/repro/rebuild-release.sh`): a clean clone of the fork at the node commit on branch `release-0.3.15-node` under a clean clone of the repo at the app commit, 2 independent clean passes per target in one target path each (no sccache, SOURCE_DATE_EPOCH 1791312828, TZ UTC), rustc 1.99.0, x86_64-w64-mingw32-gcc-posix (GCC) 13-posix, clang 18.1.3, glibc 2.39. Shipped hashes read from the public downloads (no token) where marked. Whole run 2 s; log `/srv/builds/_repro/0.3.15/rebuild.log`. + +| Artefact | Shipped sha256 (source) | Box pass A | Box pass B | A vs shipped | A vs B | Reason for a DIFFER | +|---|---|---|---|---|---|---| +| igneumd | 1e51bfb6401e2d86022eeaddf03750a72d6eb200fa879b7c58fb5c3afbf38a50 (igneum-hive-0.3.15.tar.gz (1715e58ea1d4a1ed...)) | 1f1b6eee4aaf4cdf... (49720224 B) | 1f1b6eee4aaf4cdf... (49720224 B) | **DIFFER** | **MATCH** | toolchain: the shipped binary needs GLIBC_2.34, the box's GLIBC_2.39 (a glibc GLIBC_2.34 build is the Mac's infra/cross/build-linux.sh with zig; the box links the native clang/lld); build path in the shipped binary: /Users/joshm/.cargo/registry, in the box's: /srv/builds/_repro/0.3.15 (prost's protowire.rs embeds OUT_DIR, so a different path is a different binary); build clock string (mimalloc's __TIME__) in the shipped binary: 11:05:57, in the box's: 18:53:48 (with SOURCE_DATE_EPOCH the string is the commit's time of day, the same in every build; none = no mimalloc in the binary); commit string 713ef876073d3661e9b48d2ead9a515afd1b2156: 1 hit(s) in the box's binary, 1 in the shipped one (0 = the empty-commit class: a worktree build before the two-step clean) | +| igneum-miner | c5b489105d933b01e4dceff8dc31e2db8e9aa53de06dddafc6eb12ee85b8f7a6 (igneum-hive-0.3.15.tar.gz (1715e58ea1d4a1ed...)) | a34e0a56c859a667... (9978968 B) | a34e0a56c859a667... (9978968 B) | **DIFFER** | **MATCH** | toolchain: the shipped binary needs GLIBC_2.34, the box's GLIBC_2.39 (a glibc GLIBC_2.34 build is the Mac's infra/cross/build-linux.sh with zig; the box links the native clang/lld); build path in the shipped binary: /Users/joshm/.cargo/registry, in the box's: /srv/builds/_repro/0.3.15 (prost's protowire.rs embeds OUT_DIR, so a different path is a different binary); build clock string (mimalloc's __TIME__) in the shipped binary: none, in the box's: none (with SOURCE_DATE_EPOCH the string is the commit's time of day, the same in every build; none = no mimalloc in the binary) | +| igneumd.exe | none | 9b377455ac9cc3b9... (51847168 B) | 9b377455ac9cc3b9... (51847168 B) | NO SHIPPED HASH | **MATCH** | | +| igneum-miner.exe | none | 65b30edd266d137f... (11129856 B) | 65b30edd266d137f... (11129856 B) | NO SHIPPED HASH | **MATCH** | | + +Full box hashes: igneumd A 1f1b6eee4aaf4cdfec07a165e8242b6d69a9fe20eb1b73f3caf672ec3ff53f91; igneum-miner A a34e0a56c859a667200600d3bca32f9ae22e33deb98cd226e8f54e40a6e354a4; igneumd.exe A 9b377455ac9cc3b90f081bd12d954e400ad1549c158ac179ccf07d16b6bf2c8e; igneum-miner.exe A 65b30edd266d137f3320d4d477e83bf73e0795ac3c697cbcf46b05e7dba0f8a7; + +Reading: MATCH against the shipped bytes is the goal; A vs B MATCH with a DIFFER against the shipped bytes means the box is deterministic and the shipped build came from another toolchain (the reason column says which facts differ); A vs B DIFFER is a non-determinism on the box itself and is the row to fix first. diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 8e162a2c9..60fae6e91 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -164,6 +164,24 @@ Sweep (5 October 2026, evening): stated. `site/litepaper.html`, "For miners", Ha --- +### M32. "Automatic anti-ASIC escalators" overstates what the era draw and the instruction reserve do +"You sell the era draw and the reserve unlock as anti-ASIC escalators, as if not knowing next era's parameters stops a chip. A chip that stores the dataset reads every drawn parameter as firmware: an address permute, a rotator, an immediate table. The families, the reserve order, the mixer, the dataset schedule and the class v4 shadow are all public at genesis. So what does the draw actually defend against?" + +Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/algorithm.md` sections 5.4 and 8, lane 2): the era draw and the instruction reserve are automatic schedule changes against fixed datapaths and against human forks; against the stored-dataset chip every drawn parameter is firmware, and the defence against that chip is the latency-shadow work (class v4) and the price-per-joule model. Stated in `site/litepaper.html`, Mining section ("These are automatic schedule changes ... every drawn parameter is firmware") and the "A chip is impossible" item ("a chip wired for one program is a bad bet ... not the schedule"), the "Every six months" row of the comparison table, and `site/index.html`, the hourly-program note ("a chip wired for one program is useless"). The phrase "automatic anti-ASIC escalators" is withdrawn from public text; it stays in the internal design summary until that is next edited. + +Answer: Correct. The draw hides (M, R, pos, the op weights within +-2, the fold rotations) until 2 hours before each era, and none of those needs silicon. Biasing the draw is priced at 20 days of 100 percent of the network's hash for one more sample of the same space (lane section 5.4), so the draw is unbiasable at any price that matters and that is its whole job: it is a fairness device and a fork-free schedule, not a chip defence. What a chip wired for one program loses to is the hourly program itself; what the stored-dataset chip loses to is the latency shadow (class v4, 2.1x per joule at k = 1 against the 5090 bench row, 0.9x against the Apple M5 Max) and the price per joule, which is where the public claim now rests. + +Evidence: `docs/analysis/horizon/algorithm.md` sections 5.4 (the draw's randomness, the two routes priced) and 8 (the summary), 6 October 2026; the six-era hash-rate spread of 0.8 to 3.2 percent per card in bench-log "Counter ASIC 2.0, the numbers". + +### M33. The FPGA ceiling rests on a tFAW the JEDEC HBM2 table does not give +"Your chip model's HBM random-read ceiling takes 8 activates per 12 ns per channel from O'Connor and gets 10.7 G reads/s a stack; the epoch-length page's bank-bound row gets 11.4 and a 12.2 ceiling. JEDEC HBM2 tFAW is 28 ns with 4 activates per channel per window: 2.3 G. The one measured HBM2 FPGA random-read rate (Shuhai, FCCM 2020) is 2.4 G, right on the JEDEC ceiling. Your 1.9x FPGA ceiling is arithmetic on a timing the part does not have." + +Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/algorithm.md` section 5.1, the FPGA lane): the public FPGA line carries only the measured row, 2.4 G reads/s per card and 0.30x to 0.39x of the RTX 5090 per watt (Shuhai, FCCM 2020 Fig 7; the tFAW arithmetic from ICCAD 2021 Table I), and the 11.4 G bank-bound row and the 12.2 G ceiling are marked unmeasured until an AWS F2 hour measures them. Stated in `docs/analysis/chip-model-v3.md` section 5.3 (the activate-bound row marked UNMEASURED with the JEDEC figure beside it, and the FPGA paragraph after the table). The epoch-length analysis's 12.2 row is not on master yet and is corrected when it lands. + +Answer: Correct. The measured 2.4 G/s had been read on 6 October as a mapping artefact ("the paper's point is that this mapping is the wrong one for random access"); the activate window says it is the DRAM's own limit, and a bank-interleaved mapping does not lift it because tFAW is enforced per channel by the die. The measurement that settles it is one AWS F2 hour (f2.6xlarge, Virtex UltraScale+ VU47P, 16 GB HBM2 in 2 stacks, 32 pseudo-channels, USD 1.98 an hour on demand): the chase kernel of `docs/benchmarks/repro.md` 2.2 ported to a Vitis HLS AXI master over the HBM IP at 1 GiB across all 32 pseudo-channels, 256 to 4,096 lanes in flight, board power at 1 Hz; pass line 15 to 25 M reads/s/W (0.3x to 0.5x of the 5090), alarm 27 (0.5x), over 54 (1.0x) a Counter ASIC 4.0 item. Consequence per tier: none today (no FPGA mines); on the measured row a soft-overlay FPGA mines at an RX 9070 XT's rate per watt for about 7x the price (approximate), so no home or rig tier is displaced. + +Evidence: `docs/analysis/horizon/algorithm.md` section 5.1 (the ceiling table: measured 2.4, tFAW-bound 2.3, tRRD-bound 2.8, bank-bound 11.4, O'Connor 10.7 G reads/s, and the F2 measurement plan), 6 October 2026; JEDEC HBM2 timings as carried by ICCAD 2021 Table I; Shuhai, FCCM 2020, Fig 7. + ## 2. Finality and attacks ### F1. Finality is attackable for the first month @@ -296,6 +314,15 @@ Evidence: design doc, "Proving speed on consumer GPUs" risk item and "Who needs" --- +### F26. "No stake" needs its one sentence: what is at stake, and what strips it +"You write 'no stake' and then run a vote whose weight can be stripped. Either nothing is at stake, in which case equivocation costs nothing, or something is, in which case say what it is and who can take it. One sentence, in the finality section and the summary, not an argument." + +Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/frontier.md` section 4.1 and item I13 of its incremental list): `site/litepaper.html`, the finality section's "What is not here" paragraph and the "Igneum at a glance" Finality row carry the sentence verbatim: "No coin is staked. The only thing at stake is 30 days of public work: a vote key's weight is its blue blocks over the window, and equivocation strips it for 30 days." The spec sentence for 03 and 05 (I13) follows with the lane's commit. + +Answer: Correct. The weight is a quantity that is at stake, earned by work alone over 30 days, not transferable, not purchasable, and already stripped in full for equivocation (spec 3.6). That is a slashable bond made of blocks, with no coin and no stake class; the "then it is stake" objection and its answer (the weight cannot be bought, borrowed or bridged, so capture by capital is removed; the last-days attack is bounded by the 30-day re-earn) are in the lane file, section 4.1. Extending the strip to execution-layer faults (the lane's 3.2) is an idea, not a rule, and the public text does not claim it. + +Evidence: `docs/analysis/horizon/frontier.md` sections 3.2, 4.1 and the incremental list (I13), 6 October 2026; spec 3.6 (the equivocation strip). + ## 3. Proving and the zkEVM ### P1. The 20-second shard is a number you made up @@ -502,6 +529,15 @@ Evidence: litepaper "Liquidity from the people who are there". --- +### E19. "Proving: a second income" without the arithmetic of how small it is +"You sell proving for other chains as the income that keeps cards on after the subsidy fades. Put a number on it. All of Ethereum L1's proving today costs tens of dollars a day. Your year-1 emission is tens of thousands a day at any price you dare print. Say which one pays the bills." + +Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/frontier.md` section 3.11, `frontier_model.py` section 7): `site/litepaper.html`, "For miners", under the three-streams table: all of Ethereum L1's proving is about USD 36 a day at the September 2026 tracker cost (USD 0.005 a block x 7,200 blocks; the tracker figure is a secondary source) against about USD 13,700 a day of Igneum's year-1 emission at USD 0.005 per IGN (31.688 IGN a block x 86,400; the price is an input, not a forecast), so external proving is a small second income at launch and the lottery pays the bills; paid demand would have to grow about 1,000x in dollars for proving to become the main income. Figures the lane labels approximate (all rollup proving spend, USD 8,200 to 27,400 a day; Boundless's trailing day, USD 2) are not on the page. + +Answer: Correct. The whole public proving market is three to four orders of magnitude under year-1 emission at any price input (the lane's table: Ethereum L1 at the Sep 2026 cost USD 36 a day, at the Dec 2025 cost 288; year-1 emission 13,700 at USD 0.005, 54,800 at 0.02, 273,800 at 0.10). The cost curve falls 3x to 30x a year, so dollars per proof fall as fast as volume rises. The design's own claim stays the defensible one: a second income that keeps cards on after the subsidy fades (spec 5.10.2), never the main one by 2030. + +Evidence: `docs/analysis/horizon/frontier.md` section 3.11 and the summary (section 7), 6 October 2026; the tracker (ethproofs, "sub-half-cent" fields, September 2026, secondary); the emission schedule (31.688 IGN a block in year 1). + ## 5. Governance and the founders ### G1. No cryptography team diff --git a/docs/plans/build-server.md b/docs/plans/build-server.md index 4a4f1f32e..0e6230d46 100644 --- a/docs/plans/build-server.md +++ b/docs/plans/build-server.md @@ -99,6 +99,16 @@ Also logged for context: the Mac's Linux cross-build with zig (`infra/cross/buil | The 0.3.15 prover pair for the PCs needs `--features igneum-prove-host/cuda` (the PCs run SP1_PROVER=cuda) | my first proving build named no feature | built on the box from master e1b5bc9: igneum-prove-host 73,161,528 B sha256 71bc2438856bb141f6cad3d18489f708568144fad5a06a002fbadefb9ce256f9, igneum-prove-export 3,609,360 B sha256 263bf4cef70af4a13a45b2e79b8dbab373282ea4c571f624d02ddb5791935361 (52 s warm, no CUDA needed at build time); handed to the shipper | | Let's Encrypt saw NXDOMAIN for build.igneum.network | the deSEC record was minutes old; Ubuntu's Caddy then fell back to ZeroSSL and failed with HTTP 422 for ever | issuer pinned to Let's Encrypt; the retry got the certificate | +## 5b. Reproducible builds (main's rule, 6 October 2026, from the 0.3.14 repro docs/evidence/reproduced/0.3.14.md) + +| Class | What differed | Standard fix, in every build path | +|---|---|---| +| prost's generated `protowire.rs` embeds `OUT_DIR` | two builds in differently named target dirs give different bytes | ONE fixed target path per target: `target` (or the name `--target-dir` gives) on the box, `$CARGO_TARGET_DIR` on the Mac's cross-build.sh, the persistent dir of the PC job; never a per-run name | +| libmimalloc-sys compiles mimalloc's C with `__DATE__`/`__TIME__` | two builds a minute apart differ when mimalloc recompiles | `SOURCE_DATE_EPOCH` = the node commit's author time and `TZ=UTC`, exported in lib.sh `bs_repro_env` (build-remote.sh, cross-remote.sh, workers-remote.sh), remote-run.sh (`BR_SDE`, logged in the JSONL line as `source_date_epoch`), proto-cuda/windows-node/cross-build.sh, and the PC job (push-build-inputs.sh writes `node.commit_time`, jobbuild.rs exports it before every cargo build of a stage; unit test asserts it) | +| sccache hid both | a cache hit returns the first build's object | the self-test runs with `RUSTC_WRAPPER=/usr/bin/env` (a pass-through; an EMPTY value is "unset" to cargo and would fall back to the configured sccache) | + +Self-test: `tools/build-remote.sh --self-test-repro [--full]` from a fork worktree. Run 6 Oct 20:02 UTC on the box (igneum-node-bs at 3bfe346f, epoch 1791120573): igneum-miner twice a minute apart, kaspa-grpc-core cleaned in between: MATCH 91e130f52438edf012466d3f1d3d634ab9263cd7858e67d2dd8d590b152f8a22; the same build into a per-run target path: 548671e7... (differs, the OUT_DIR class shown firing). `--full` (kaspad with libmimalloc-sys recompiled a minute later, with and without the epoch): run 6 Oct 20:04 to 20:08 UTC (247 s): kaspad with libmimalloc-sys recompiled a minute later, epoch set: MATCH 70219bc29cc98ac75da00702b9966f9f5d73cbf10efaca1c8841c00bb5aae7bf; without the epoch, a minute later: 45169e88... (differs, the __DATE__ class shown firing); the miner line again MATCH 91e130f5..., the per-run path 310383f5... (differs). The box is deterministic with the rule and shown non-deterministic without it + ## 5a. The GPU workers (added 6 October 2026, 19:10 UTC, for the class v4 rehearsal) | What | Fact | @@ -115,6 +125,158 @@ Also logged for context: the Mac's Linux cross-build with zig (`infra/cross/buil |---|---|---| | No zig / cargo-zigbuild | the devnet seed (Debian 12, glibc 2.36) takes the Mac's zig build; a native box build links glibc 2.39, which Debian 13 seeds accept and HiveOS (Ubuntu 18/20 base) does not | install zig 0.17 + cargo-zigbuild in provision.sh, add `--target x86_64-unknown-linux-gnu.2.36` mode to build-remote.sh | | No macOS target | agents who run nodes on the Mac still build there | out of scope (needs the macOS SDK on Linux); the fleet or the box's own Devnet 2 seed takes the test-network runs instead | -| No CI runner | GitHub `ci.yml` and `windows.yml` run on GitHub's machines | install a self-hosted runner as user build once R1 is in | +| No CI runner | DONE 6 October 2026, 19:19Z (section 7): the runner `igneum-build-1` is online under user `runner`, never build; the workflow change is proposed in docs/plans/ci-self-hosted.md | main flips `IGNEUM_CI_RUNNER=box` after the shipper's cut | | Byte identity with the Mac's exes | different C/C++ toolchain (Homebrew mingw vs Ubuntu GCC 13) and embedded source paths | not a goal; the box is identical with itself build to build, cross-remote.sh reports sha256 and the DLL list per exe | | Robot API | `~/.config/igneum/hetzner-token` is the Cloud token (hcloud); the dedicated box lives in Robot, a separate credential | main sets the Robot server name in the UI; a webservice user goes to `~/.config/igneum/robot-credentials` when needed | + +## 7. The box's second shift (6 October 2026, from 20:3x UK, the project lead: "what else can our building machine be working on?") + +Four items, each its own commit on branch `box-work` with its section here. Times UTC. + +### 7.1 The GitHub Actions runner (DONE 19:19Z) + +| Fact | Value | +|---|---| +| Runner | `igneum-build-1`, actions/runner 2.338.0 (tarball sha256 af4b794c... checked against the release note), registered on igneum-network/igneum at 19:19:49Z, online, labels `self-hosted, Linux, X64, igneum-build-1` | +| User | `runner` (uid 1001, own group, no sudo, not in `build`'s group; /home/runner 750). Never `build`, never root. The runner's credential (`/opt/actions-runner/.credentials`, mode 600) is the only thing it holds; it signs nothing and reaches no hand | +| Service | `actions.runner.igneum-network-igneum.igneum-build-1.service` (GitHub's `svc.sh install runner`), drop-in `igneum.conf`: Nice 10, IO best-effort 7, Restart on-failure. Agents' builds (nice 0 through build-remote.sh) win the CPU over a CI job | +| Toolchains | rustup 1.99.0 pinned like the box (`RUST_TOOLCHAIN`), targets x86_64-unknown-linux-gnu and x86_64-pc-windows-gnu, clippy, rustfmt; mingw-w64 GCC 13 posix, Node 22, python3 + numpy from the system (numpy added to APT for the simulators) | +| sccache | `/usr/local/bin/sccache` (the build user's binary copied; /home/build is 750), config `/home/runner/.config/sccache/config` with `rw_mode = "READ_ONLY"` on /srv/sccache, own server port 4227. Shown: a job-shaped `cargo test --release` of igneum-pow as `runner` (99 tests pass, 42 s cold) made 6 compile requests, 0 hits, 6 cache WRITE ERRORS (the refusal, as wanted), and /srv/sccache stayed at 5,880,836 KB | +| Jobs | `.env`: RUSTC_WRAPPER, SCCACHE_CONF, SCCACHE_SERVER_PORT 4227, CARGO_INCREMENTAL 0, CARGO_BUILD_JOBS 48 (half the box); `.path`: the runner's cargo bin, /usr/local/bin, /usr/bin, /bin. A CI job takes NO build slot today (ci-self-hosted.md, open row) | +| Ephemeral | no. `--ephemeral` is for autoscaled fleets that register a fresh runner per job; one standing runner on a private repository keeps its registration and cleans `_work` per job (approximate: GitHub's docs host answered 404 to both fetches tonight, so this is the rule as remembered, labelled so) | +| Registration | `infra/build-server/runner/register.sh`: gh as igneum-labs (fails on any other active account, checks the login is igneum-labs), `POST repos/igneum-network/igneum/actions/runners/registration-token`, the token as the first stdin line to `provision.sh` on the box (never an argument, never a file, never logged; the output is filtered for it as a belt). `--status` lists the repository's runners and the unit | +| Idempotent | provision.sh runs 3 and 4 after the registration: `runner: ok`, no restart (`ActiveEnterTimestamp` unchanged). Run 2 had said `changed` because GitHub's `svc.sh install` runs `env.sh`, which rewrites `.env` and `.path`; the step now writes them AFTER the install | +| Workflows | NOT changed (the shipper owns them tonight). The proposed diff and the fallback (repository variable `IGNEUM_CI_RUNNER`; GitHub has no "else" in `runs-on`) are in `docs/plans/ci-self-hosted.md`. `windows.yml` cannot move to a Linux box (MSVC, WebView2, Inno Setup, PowerShell 5.1) | + +Consequences: ci.yml's `pow` and `sims` jobs would run on a pinned 1.99.0 (GitHub's `ubuntu-latest` ships whatever stable it has), with 48 jobs; GitHub-hosted minutes on a private repository are the thing saved. A CI job on the box reads only what the checkout gives it; the mirrors and `/srv/builds` belong to `build` and are not readable by `runner` (git's safe.directory is set for the runner so a future job may clone a mirror read-only if main wants it). + +### 7.0 The slots ruling (main, 20:3x UK; DONE 19:28Z, live on the box) + +| Change | Where | Shown by | +|---|---|---| +| 2 build slots (`/srv/builds/_locks/slots` = 2) | provision.sh `SLOTS` default 2, applied 19:28:18Z | `dirs: changed (... slots=2)` | +| CARGO_BUILD_JOBS 90 when a build holds the only taken slot, 45 when it sees the other slot held (one second of settling after taking the slot, then a `flock -n` probe of the other file); a `-j` on the cargo line wins | remote-run.sh; tools/build-remote.sh and tools/cross-remote.sh pass `-j` only when `--jobs` is given | `remote-run.sh --self-test-slots` on the box: two concurrent fake builds get 45 each, a lone one 90 | +| A measurement (`BR_MEASURE=1`) takes the `measure` file exclusively; builds hold it shared for their whole run, so a measure waits for the running builds and blocks new ones, as with-lock.sh's `measure` on the Mac | remote-run.sh; `infra/build-server/prover/cpu-trial.sh` is its first user | the self-test: a measure blocks a build, a build blocks a measure; JSONL carries `"jobs"` and `"measure"` | +| Lock files opened in APPEND mode | remote-run.sh | the first version's `exec {fd}>build-k` truncated a BUSY slot's holder line each time another build probed it (the dashboard read empty lines for held slots); the self-test's case 5 keeps a holder line through a probe. The OLD script under the same cases: `JOBS=none JOBS=none`, FAIL (the known-failed run, 19:25Z) | +| An environment IGNEUM_BUILD_SLOTS_DIR or IGNEUM_BUILD_LOG_DIR wins over the profile | remote-run.sh | the first self-test run let the profile reset the scratch dir and took the box's REAL slot for 7 s (19:24Z, box idle) | + +Open: a worktree whose remote-run.sh predates this keeps the old behaviour until it has master with it (the script is piped from each Mac worktree per build), so until every agent rebases, a build from an old worktree still asks `-j 90` beside a new one at 45. The build-server agent was told at 19:28Z. + +### 7.2 The night battery (DONE 19:42Z installed, dry run 19:45 to 19:49Z) + +`infra/build-server/night/night-battery.sh`, run by `igneum-night-battery.timer` at 02:00 Europe/London (the box's clock is +Europe/Berlin, so the unit names the zone: next run Wed 2026-10-07 03:00 CEST = 02:00 BST; not Persistent, a missed night is +not run by day) through `igneum-night-battery.service` (User build, Nice 19, idle IO, 8 h limit), whose ExecStart is +`remote-run.sh` with the battery as BR_CMD, so ONE build slot spans the whole invocation and one JSONL line records it. +Installed by provision.sh `step_night` from the mirror at `NIGHT_REF` (box-work tonight, master once merged); the battery +re-execs itself from master's checkout at run time. Every row: `cargo test --release --no-fail-fast` per crate (the repo's +five crates and the proving workspace's host, core and export; every fork workspace member, kaspad with `igneum-pow`), +igneum-pow's two fuzz tests at 2,000 programs (10x), the three simulators in full, the fast-time harnesses +(`tools/finality-attacks/run.mjs --fast-time`, `tools/harness/run.mjs s3 s4 --fast-time --no-bench-log`, +`tools/exec-sync/reorg.mjs`) on igneumd, igneum-miner, igneum-harness-sim and igneum-p2p-probe built into the night +checkout's `target-integration`, clippy per crate dir, `cargo audit` per Cargo.lock; then `docs/benchmarks/night/.md` +(pass/fail table, "new since last night" against the newest earlier report, commits moved), committed as igneum-labs on +branch `night-battery` (rebuilt on master each night, earlier unmerged reports carried over) and force-pushed to +`/srv/igneum.git` only. Main merges: `git fetch build night-battery` from the main checkout. The fork branch defaults to the +newest `release-*-node` on the mirror (tonight release-0.3.15-node 713ef876). + +Dry run (`NIGHT_SUBSET=1`, the second slot while the repro held the first, so CARGO_BUILD_JOBS 45): **3 min 54 s** wall, +10 pass, 1 FAIL, 1 skip; report `docs/benchmarks/night/2026-10-06-dryrun.md` on the mirror's night-battery branch (fbb72e5). + +| Row | Result | Time | Detail | +|---|---|---|---| +| suite igneum-pow | pass | 51 s | 99 passed | +| suite fork/kaspa-pow | pass | 1 min 04 s | 7 passed | +| suite fork/igneum-miner | pass | 49 s | 18 passed | +| fuzz igneum-pow x200 | pass | 11 s | 200 mx8 programs and 200 scratch programs, 800 units each | +| sim finality_sim.py, finality_v2.py --quick, difficulty/sim.py --quick | pass | 3 s, 41 s, 5 s | 249, 117, 8 table lines | +| clippy igneum-pow | pass | 3 s | 28 warnings | +| audit igneum-pow | pass | 3 s | 0 vulnerabilities | +| audit vendor/igneum-node | **FAIL** | 2 s | 22 advisories in the fork's lock file: h2 (RUSTSEC-2026-0258, unbounded empty DATA frames), quinn-proto (2026-0185, remote memory exhaustion), rustls (2026-0285, TLS 1.3 handshake across encryption levels), ruint (2026-0220), crossbeam-epoch, anyhow (2026-0190), event-listener, faster-hex (2026-0306, AVX2 read past src), lru (2026-0253), tracing-subscriber (2025-0055), chacha20, spin; 17 unmaintained-crate warnings (async-std discontinued, atty, bincode, derivative, instant, mach, paste, proc-macro-error, rustls-pemfile) | +| harness | skip | | not in the subset; its first run is the 02:00 battery, so the first full report will show whether the Node harnesses run on Linux unchanged (c4, fud and v3.mjs default IGNEUM_NODE_ROOT to /Users/joshm/Projects/igneum/; the battery sets it) | + +What the FAIL means and what follows: every node binary shipped so far (and the 0.3.15 one tonight) links h2, quinn-proto and +rustls at versions with published advisories; h2 and quinn-proto are in the gRPC and QUIC paths a peer can reach, so these are +the remote ones. The fix is a dependency bump in the fork (`cargo update -p h2 -p quinn-proto -p rustls -p ruint -p +crossbeam-epoch -p anyhow -p event-listener -p faster-hex -p lru -p tracing-subscriber`, then the suites), a consensus +engineer's hour on a quiet branch, and the row goes green by itself the next night. Until then the row stays FAIL every night +and "new since last night" stays quiet about it. The unmaintained-crate warnings are upstream rusty-kaspa's and do not fail +the row. + +Expected full-run time (not measured yet): the three suites above compile the fork's test targets once (about 1 min each for +the first crates, seconds after), so 75 fork members plus the repo crates are estimated at 40 to 70 min; the full sims about +10 min (finality_v2.py is 5 min on the Mac); the harnesses 15 to 30 min; clippy and audit under 10 min. Under 2 h, inside +the 8 h limit; the first report at 02:00 BST writes the real number. + +### 7.3 Reproducible builds (DONE 19:52Z; A vs B MATCH on all four, DIFFER against the shipped bytes, both explained) + +`tools/repro/rebuild-release.sh ` (the Mac) reads the pins from `docs/plans/release-.md` (the heading +"(node , app )" and the bold hashes of the Linux and Windows rows), makes sure both commits are on the mirrors, and +runs `infra/build-server/repro/rebuild-on-box.sh` on the box: a clean clone of the fork at the node commit on a branch under +a clean clone of the repo at the app commit, two clean passes per target in ONE target path each, no sccache, under build +slots through remote-run.sh, `SOURCE_DATE_EPOCH` = the node commit's time, `TZ=UTC`; the shipped hashes come token-free from +the public downloads (the HiveOS tarball for the Linux pair; the installer for the exes, when innoextract can open it) with +the plan's hashes as the fallback; the evidence goes to `docs/evidence/reproduced/.md`. The 0.3.14 run (node +4c6b129d, app a90f6a5): four passes of 70 to 78 s, whole run 5 min 06 s. + +| Artefact | A vs shipped | A vs B | Why the shipped bytes differ (read off the binaries) | +|---|---|---|---| +| igneumd (box 03f35e05..., 49,600,096 B) | DIFFER | **MATCH** | shipped 934f393c... was the Mac's zig build for glibc 2.36; the box's needs GLIBC_2.39 (native clang and lld). Commit string 4c6b129d in the box's: 1 hit | +| igneum-miner (box 900c1f0b..., 9,842,168 B) | DIFFER | **MATCH** | the same toolchain difference | +| igneumd.exe (box 166e604e..., 51,758,592 B) | DIFFER | **MATCH** | shipped 44fa74c0... came from the Mac's Homebrew mingw at 16:52Z, before the --no-insert-timestamp fix (17:48Z) and from a worktree (the empty-commit class); the box's is Ubuntu GCC 13 posix with a zero PE timestamp and the commit string (1 hit). innoextract 1.9 cannot open the Inno Setup 6 installer (setup loader revision 2), so the shipped exe's own header was not read | +| igneum-miner.exe (box fefd266c..., 10,994,688 B) | DIFFER | **MATCH** | the same | + +Two non-determinisms found on the way, both in the SHIPPED builds too (first run 19:43Z, passes A and B differed on all four): + +| Class | Fact | Fix | +|---|---|---| +| OUT_DIR path in the binary | prost's generated `protowire.rs` (kaspa-grpc-core, kaspa-p2p-lib) embeds its OUT_DIR path; a pass in a target dir of another NAME differs (igneum-miner matched byte for byte once the path was the same) | one target path per target in the repro; for cross-machine identity a `--remap-path-prefix` of the target dir and the home (not done: the Mac and the box differ in every path anyway) | +| Build clock in the binary | libmimalloc-sys compiles mimalloc's C with `__DATE__` and `__TIME__` ("Oct 6 2026", "21:38:15" sat in libmimalloc.a, next to the mimalloc option names); two builds a minute apart differ | `SOURCE_DATE_EPOCH` exported for every pass (GCC and clang take the date and time from it); PROPOSED for build-remote.sh, cross-remote.sh, cross-build.sh and the PC job: export it from the commit time so two builds of one commit give one hash. The earlier "byte-identical across three builds" on the box was under sccache, which returns the first build's object and hides this class | + +0.3.15 as well (run 19:56 to 20:00Z, the moment it reached dl/public; node 713ef876, app 563485b; four clean passes of 63 to +76 s): A vs B **MATCH on all four** again (igneumd 1f1b6eee..., igneum-miner a34e0a56..., igneumd.exe 9b377455..., +igneum-miner.exe 65b30edd...). Against the shipped Linux pair in `igneum-hive-0.3.15.tar.gz` (igneumd 1e51bfb6..., +igneum-miner c5b48910...): DIFFER, and the binaries say why: the shipped pair needs GLIBC_2.34 and embeds +`/Users/joshm/.cargo/registry` and the clock string 11:05:57, so the HiveOS package carries the Mac's zig build, not the +box's 06211d55... of 19:00Z (the box build needs GLIBC_2.39, which HiveOS cannot run; the zig lane is right for that +package). The Windows exes have no shipped hash yet (the public installer is still 0.3.14). `docs/evidence/reproduced/0.3.15.md`. + +What it means: the box is deterministic for a given commit and path, so a release built on it can be checked by anyone with the +same toolchain by rebuilding and comparing; the shipped 0.3.14 and 0.3.15 Linux bytes came from the Mac's zig lane with a +build clock inside and cannot be reproduced anywhere, and the Windows 0.3.14 exes carried a PE timestamp. The reason to ship +every target from the box from 0.3.16 (R2) is this table, with SOURCE_DATE_EPOCH exported in every build script; for HiveOS +(glibc 2.36 and under) the box needs zig + cargo-zigbuild first (section 6, row 1), or the package keeps the Mac's build and +stays unreproducible until then. Open: a `--reuse` re-report of 0.3.15 once its Windows installer is public, and +`rebuild-release.sh 0.3.16` the moment it ships. + +### 7.4 The CPU prover trial (DONE 19:30Z; verdict: the box is NOT a prover) + +`infra/build-server/prover/cpu-trial.sh` on the box under the measure hold (builds excluded), `igneum-prove-host` from master +7483fb37 (the 0.3.15 prover pair, sha256 71bc2438...; its `cuda` feature changes nothing under `SP1_PROVER=cpu`), fixture +`proving/fixtures/block-56-transfers.json` (the v0 block: 3 transfers, 600 pgas, one shard, 556,369 SP1 cycles), `--mode shard +--shard 0`, `RAYON_NUM_THREADS=96`, nice 19, box otherwise idle (load 2.6 at start). Log and results JSON: +`/srv/builds/_log/prover-trial/trial-20261006T192824Z.{log,json,txt}`; JSONL line kind `measure`. + +| Stage | Box, 96 threads (EPYC 9454P) | Mac, same statement class (bench-log) | +|---|---|---| +| setup (prover client, shard and aggregator keys) | 14.4 s (client 12.6, keys 1.8) | 9.3 s per invocation in the v0 loop (4 Oct, "nearly all SP1 setup") | +| execute | 0.28 s, 556,369 cycles, 927 cycles per pgas | 0.19 s for block 78 (3 Oct) | +| core proof | **34.2 s**, 7,317,561 B, verify 0.34 s | 83 s for the 200-pgas shard on a Mac at load 40 (4 Oct); 71.7 s is main's Mac figure for this fixture (its stage not recorded here, labelled approximate) | +| compressed proof (what a record carries) | **85.9 s**, 1,272,897 B, verify 0.07 s | 272 s for the 200-pgas shard on the loaded Mac (4 Oct); 61 s for the smallest shard in the 3-node v0 loop | +| whole run, wall | 136.9 s | | +| peak RSS | 28.2 GB (VmHWM) | | +| CPU use | 64 of 96 threads busy on average (6,408 percent in `ps`) | | + +What the numbers mean, per tier, and what follows: + +| Number | Means | Done or proposed | +|---|---|---| +| core 34.2 s under 60 s, compressed 85.9 s over it | the proof a record carries is the compressed one, so the shard that matters takes 120 s of proving on 96 CPU threads for the SMALLEST shard the chain has (600 pgas, 0.56 M cycles); a shard at `S_p` is 60 M cycles (bench-log 4 Oct), about 100x, so hours per shard on this CPU against the 60 s proof lag the litepaper states | the 60 s test of the ask is NOT met on the stage that counts; NO standing CPU prover unit is written, nothing joins the devnet from the box (R6 holds: the box is never a node host for the live devnet) | +| 28.2 GB peak for the smallest shard | a CPU prover needs 32 GB of RAM for a toy shard; every home tier (8, 12, 16, 24 or 32 GB CARDS, 16 to 64 GB of RAM) is out of CPU proving, and the rented 4090 boxes' CPUs are not a fallback either | the app keeps "proving on the CPU (slow)" as a correctness lane only; the prover tiers are the real cards (docs/analysis, 6 Oct rented-card measurement) | +| 64 of 96 threads busy | SP1's CPU prover does not scale to the whole box; a second trial with `RAYON_NUM_THREADS=48` would show whether half the box proves as fast (then two shards side by side) | not run tonight (one slot of the box's evening); the script takes `--threads` | +| 14.4 s setup per invocation | the same per-process cost the Mac pays; a resident prover would pay it once | already the design of the app's prover loop | + +The box stays a build and test machine. If main wants a CPU prover anyway for coverage (a prover that is always on, never fast), +the shape is a systemd unit as `build` with `SP1_PROVER=cpu`, a throwaway devnet key (never the OTA key, never a hand's key), +`--threads 48`, Nice 19 and the measure hold taken for the whole run, which would exclude builds for minutes at a time: that +is why it is not written. diff --git a/docs/plans/ci-self-hosted.md b/docs/plans/ci-self-hosted.md new file mode 100644 index 000000000..10e0d1471 --- /dev/null +++ b/docs/plans/ci-self-hosted.md @@ -0,0 +1,75 @@ +# CI on the box: the self-hosted runner and the workflow change (proposal, 6 October 2026) + +The runner `igneum-build-1` (labels `self-hosted, linux, x64, igneum-build-1`) is installed by `infra/build-server/provision.sh` +step_runner and registered by `infra/build-server/runner/register.sh` (docs/plans/build-server.md section 7). The workflows are +NOT changed here: the shipper owns `.github/workflows` tonight. This is the proposed diff for main. + +## 1. The shape: one repository variable decides, GitHub-hosted is the fallback + +GitHub has no "try this runner, else that one" in `runs-on`: a list of labels means ALL of them must match one runner, so +`[self-hosted, igneum-build-1, ubuntu-latest]` would never schedule. The fallback is therefore a repository variable read in +the expression. `IGNEUM_CI_RUNNER` = `box` sends the job to the box; unset or anything else keeps `ubuntu-latest`. Flipping it +back is one click in Settings > Secrets and variables > Actions > Variables (or `gh variable set IGNEUM_CI_RUNNER --body box` +and `gh variable delete IGNEUM_CI_RUNNER` as igneum-labs), with no commit and no queue lost: a job already queued for the box +stays queued; the next push goes to GitHub's machines. + +## 2. ci.yml (the two jobs that compile or compute; the `site` job stays on GitHub's machines) + +```diff + jobs: + pow: + name: igneum-pow tests, igneum-census build +- runs-on: ubuntu-latest ++ runs-on: ${{ vars.IGNEUM_CI_RUNNER == 'box' && fromJSON('["self-hosted", "linux", "x64", "igneum-build-1"]') || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v4 + - name: toolchain + run: rustc --version && cargo --version +@@ + sims: + name: simulators, quick modes +- runs-on: ubuntu-latest ++ runs-on: ${{ vars.IGNEUM_CI_RUNNER == 'box' && fromJSON('["self-hosted", "linux", "x64", "igneum-build-1"]') || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 ++ if: vars.IGNEUM_CI_RUNNER != 'box' # the box has python3 and numpy from provision.sh; setup-python would download a second Python + with: + python-version: '3.12' +- - run: python3 -m pip install --quiet numpy ++ - run: python3 -m pip install --quiet numpy ++ if: vars.IGNEUM_CI_RUNNER != 'box' +``` + +What the box gives these two jobs: rustc 1.99.0 pinned (GitHub's `ubuntu-latest` carries whatever stable it ships; the box +is the Mac's version, so CI compiles what the agents compile), sccache hits from the agents' cache (read-only), 48 cargo +jobs. The `site` job is Node and shell checks and takes under a minute on GitHub's runners; moving it buys nothing and would +put `tools/ci/public-api-check.mjs` (a live HTTPS check) behind the box's egress for no reason. + +Why the toolchain line still runs: on the box `rustc --version` must print 1.99.0; a mismatch means provision.sh and the +runner's rustup disagree (R5 in build-server.md) and the job should say so in its first step. + +## 3. windows.yml: no change possible on this box + +Every job of `windows.yml` runs on `windows-latest` for a reason the box cannot answer: the engine builds on the MSVC +target, the window host needs the Windows SDK and WebView2, the installer needs Inno Setup, the smoke run executes the exes +and the launcher under Windows PowerShell 5.1. A Linux runner has none of that. The only self-hosted option for this +workflow is a Windows runner on PC 1 or PC 2 (`actions/runner` for Windows under a service account), which conflicts with +the rule that the PCs keep only GPU and Windows-runtime JOBS through the signed job system, and is not proposed tonight. + +What the box already does for Windows is upstream of this workflow: `tools/cross-remote.sh` builds `igneumd.exe` and +`igneum-miner.exe` (the payload inputs) in 1 min 44 s, and the night battery rebuilds them for the reproducibility record. + +## 4. What to check after the flip (main, the first run on the box) + +| Check | Where | Pass | +|---|---|---| +| the job landed on the box | the run's "Set up job" log says `Runner name: 'igneum-build-1'` | yes | +| the toolchain | the `toolchain` step prints `rustc 1.99.0` | yes | +| sccache hits | add `sccache --show-stats` as a step once, or read `/srv/sccache` size before and after: the runner's config is READ_ONLY, so the size must NOT change | size unchanged | +| the agents were not starved | `/srv/builds/_log/builds.jsonl` `secs` of the builds during the run against the same crate's earlier lines | within the usual spread | +| the fallback | `gh variable delete IGNEUM_CI_RUNNER`, push a no-op commit: the job runs on `ubuntu-latest` again | yes | + +Open: a CI job on the box does not take a build slot (`/srv/builds/_locks/build-`), it runs at Nice 10 with 48 jobs; if a +CI job ever delays a release build visibly, the fix is a step at the top of the job that takes a slot through +`infra/build-server/remote-run.sh`'s flock, the same file the agents use. diff --git a/docs/plans/site-ui-3-audit.md b/docs/plans/site-ui-3-audit.md new file mode 100644 index 000000000..268a81ff0 --- /dev/null +++ b/docs/plans/site-ui-3-audit.md @@ -0,0 +1,364 @@ +# Site UI 3 audit: the website and litepaper through the miner app's lens + +6 October 2026, 19:00 to 21:00 UK. Branch `site-ui-3`. the project lead's ask: "run the website and all pages and litepaper through the +same apple lens as the miner app", and "leave no stone unturned". The standard is `docs/plans/miner-ui-3-audit.md` and +`docs/plans/miner-ui-3.md` (branch `miner-ui-3`). The design that answers this audit is `docs/plans/site-ui-3.md`. + +## 1. Method + +| Input | How | +|---|---| +| Every page in `site/` | 15 pages: index, litepaper, live, miners, miner, wallet, bench, evidence, ledger, explorer, block, address, faucet, metamask, 404 | +| Screenshots | headless Chromium (Playwright's cached build, never Chrome.app) against `tools/site-serve.mjs` on a private port, reading the live API; full page at 1440 and 390, dark and light: `docs/plans/site-ui-3-shots/before/` | +| Live states | the same pages with `/api/*` blocked (failed fetch) and with the observer's reply rewritten stale (`state.stale: true`, 70 min old): `before-states/*-fail.jpg`, `*-stale.jpg`; the loading state read from each page's JS | +| Print | `/litepaper` printed to A4 in both themes: `before-states/litepaper-1440-{dark,light}.pdf` | +| Keyboard | Tab pressed 2, 3 and 8 times on the home page, the focused element and its outline recorded: `before-states/index-*-focus*.png` | +| Contrast | every text token on every surface token, both themes, computed (WCAG relative luminance) | +| Links | every href and src (914 attributes, 210 unique) followed; anchors against ids; externals with curl | +| Downloads | every installer fetched from dl.igneum.network and hashed against the host manifest and the page | +| Numbers | every number and dated claim traced to the bench log, the ledger, the spec, the analysis docs or the live API | +| Rating | the miner-ui-3 scale: "10 = nothing to change. The three questions per screen: what does it say in jargon, which number has no unit or no meaning, which 0 or blank has no reason word." | + +The pane in the desktop app was used to confirm the item 0 fix live (counters and legend) but its screenshots come back +black under a 1440 emulation, so every image here is from the headless run. + +## 2. Screen by screen + +Rating: 10 = nothing to change. The three questions per screen: what does it say in jargon, which number has no unit or +no meaning, which 0 or blank has no reason word. Screenshots: `docs/plans/site-ui-3-shots/before/--.jpg`. + +### Home, 6 + +Good: the hero says what it is in a sentence, the four facts are tiles with units, the light-client card verifies a real +certificate in the tab, the download buttons carry version and size, the economics bar reads at a glance. + +| Problem | Where | +|---|---| +| The lead paragraph runs 100 words and carries the chip model's numbers (5x to 9x per joule, about 2x), a model figure the plan says to word before any public push | hero, line 345 | +| Eight sections before the download; the one primary action ("See the miner") scrolls to the middle of the page | hero CTA | +| Two ember primaries on screen at once in the hero (the nav's "The miner" and "See the miner") plus every stat number in ember | hero, stats | +| Every section below the fold is invisible until scrolled (`.reveal` at opacity 0); a print, a screenshot, a slow scroller or a reader with JavaScript off gets blank sections | 37 `.reveal` elements | +| The live scene showed window counts as chain facts, grey nodes, and a simulation under a live-looking label when the fetch failed (fixed in item 0) | chain scene | +| The journey log's default eight entries are engineering shorthand with scrub artefacts ("the 12-node the cloud provider network", "00:4xZ", CLI flags, ledger ids) | journey | +| "vote keys active in 10 min (a card runs several)", "BLS aggregate, version 1", "final · cp 5", "igneum-proving-pool-v0" on the surface | strip, hero card, wallet, economics | +| The mine heading is 91 characters | section 6 | +| Horizontal overflow at 390 (395 px) | phone | +| No light mode | whole page | + +Apple would: one screen that says what it is, shows the chain alive, offers the download, and lets the sceptic check three things; everything else one link away. + +### Litepaper, 5 + +Good: a real table of contents with a sticky rail, numbered sections, "what we do not claim" as its own section, every +other-chain claim labelled approximate, the pager at the foot of each section. + +| Problem | Where | +|---|---| +| Light by default while every other page is dark; its own token set (ground, surface, quiet, tint) | :root | +| Accents as text (ember, molten) fail 4.5:1 in light mode everywhere they appear: eyebrows, links, the tile numbers | section 6 of this audit | +| File paths inline in the abstract and limits (`docs/analysis/chip-model-v3.md`, `asic-resistance-history.md`, `prover-tiers-real-cards.md`, which does not exist) | abstract, randomx, proving, limits | +| 92 sentences over 30 words; the longest 152 words (Ember status) and 136 (proving measurements) | mining, proving, ember | +| "One section at a time" is the default, so the print is one section and a search of the page finds one section | contents | +| The cover says updated 5 October; the body cites 6 October nine times | cover | +| Placeholders on the public page: "the entry lands tonight", "measurement tonight" | questions miners ask | +| Numbers in prose, not tables: the proving measurements, the swap figures, the prover tiers | proving, ember | +| Roadmap says the proof lag is "not yet measured on the live chain" while the API reports a median lag of 387 s | roadmap | +| Tint callouts (`--tint`) against the app's no-tint rule | callouts | + +Apple would: dark like the rest, a readable 68-character measure, every measured number in a table with its date and +source, the limits section set as callouts, the whole paper on one page with a sticky section nav, printable. + +### Live, 6 + +Good: the status tiles say what they measure and over what window, the lane scene is real data with a legend in the +ledger's words, the miners table and the events feed are honest, "observer offline" is said in words. + +| Problem | Where | +|---|---| +| "DEVNET V0" eyebrow (the chain is v4) | eyebrow | +| The fee sentence pins DAA 210,000 and the chain passes it tonight | intro | +| "proven 0/16" counted the on-screen window (fixed in item 0) | strip stats | +| Hash rate "n/a" when the estimate is missing; "n/a" in the proof lag panel | tiles, canvas panel | +| "DAA", "pgas", "gwei", "observer", "api unreachable" on the surface with no gloss | intro, tiles, notes | +| The scene is a lane chart with coloured squares, not a DAG; the selected chain is a spline through the squares | canvas | +| 2,000 px of miners table on one screen with every engine cell "not reported" | miners | +| Eight tiles before the scene; the scene is the page's job | layout | + +Apple would: the DAG first, the eight numbers under it as one row, the tables folded. + +### Miner, 5 + +Good: every feature is one line with its measurement and a link to the log entry, the fee section shows the fee and +the off switch, the recoveries table has units. + +| Problem | Where | +|---|---| +| The h1 is 96 characters and wraps to seven lines at 1440 | hero | +| 8,947 px tall; the download sits at 7,700 px | whole page | +| Buttons say v0.3.13, the Flight Sheet URL is 404 and its sha256 is the hash of a dead file (L2) | get | +| "every NVIDIA card from 8 GB proves" cites a file that is not in the repository and contradicts /evidence row 16 | hero, features | +| "Six levers" has no document; the "3 minutes / 30% in 10 minutes" update rules have no source | levers, updates | +| "until 0.3.6", "Ships in 0.3.6" at 0.3.13 | caption, lever 4 | +| Command lines and env strings as body text (`--dev-fee 0`, `DEV_FEE=1 IDENTITIES=8 WORKER=auto VOTE=1`) outside a code block | fee, hive | +| Three ember primaries on one screen (nav, "Downloads", band) | hero, band | + +Apple would: install, start, the card mines, download here; every feature behind a chevron with its number; the fee +as one sentence and a switch. (The copy and images are being redone by the site-miner agent today; this page is +styled through the shared CSS only.) + +### Wallet, 6 + +Good: the three states are three cards with a word each, the timed first run is a table with units, the checks before +"final" are four numbered sentences. + +| Problem | Where | +|---|---| +| "Your coins. Final means final." and "The miner pays this wallet." are aphorisms; "No confirmation counts, no trusting the node" is an antithesis | hero, band, lead | +| Every timed number has no row in the log or the repository ("The log entry ships with the wallet") against "every number has a row" | first run | +| 5,880 px tall; download at 4,800 px | whole page | +| The two screenshots are the same size as the text column and carry an example address | hero, transaction | +| Horizontal overflow at 390 | phone | + +(The content is being redone by the wallet-ui-3 agent today; styled through the shared CSS only.) + +### Miners (bench table), 5 + +Good: six measured rows with date and version, prototype rows say so, "no tune reports yet" says why. + +| Problem | Where | +|---|---| +| "3 entries, newest at the bottom" is the bench template's eyebrow on a page with three sections | eyebrow | +| "MH per watt: not measured" on every row while the 5090's watts are in the ledger (E17) and eleven rented cards were measured today | table | +| "Rows: 6. Source file: site/miner-bench.json", "tools/tuning.mjs --priors --site" on the page | notes | +| Two 40-word sentences | priors | + +Apple would: the table, the rate per watt where measured, "not measured" with the reason once. + +### Explorer, 7 + +Good: eight tiles with units and a sub-line each, a real table of real blocks, a legend in the ledger's words, the public +API card, the error sentences are words. + +| Problem | Where | +|---|---| +| "n/a" in the height, difficulty and hash-rate tiles and the Txs and Proof-records cells when a field is missing | tiles, table | +| "DAA" in two tiles and two notes with no gloss anywhere on the page | tiles, notes | +| "Older blocks" stops the 5 s refresh for good after the first click, silently | button | +| "cached 10 s" (the explorer endpoint is 5 s); "under check" names a field today's /api/supply does not carry | API card, note | +| "observer" six times as a word for the reader | intro, notes | + +Apple would: the same page with the state words and the glosses. + +### Block and address, 6 + +Good: every header field, the mergeset, the coinbase outputs and the proof records as labelled rows; a block that is a +checkpoint shows its weight; the error sentences name what a hash or an address is. + +| Problem | Where | +|---|---| +| "n/a" in twelve places (miner, vote key, difficulty, subsidy, selected parent, parent levels, balance, last block, subsidy and tx cells) | both pages | +| The address balance reads "n/a" for every address with the sentence "no EVM RPC configured on this deployment (EXPLORER_EVM_RPC)", an environment variable on a public page | address | +| The default balance sub-line is the raw RPC method name `eth_getBalance` | address | +| A never-seen address returns zeros with no sentence saying it has never mined | address | +| "E(DAA) of spec 2.5", "pgas", "needs an EVM RPC", "the proving feed" | block | +| The only way back is the eyebrow link | both | + +Apple would: "balance not shown on this deployment" once, "this address has not mined in the last day", the spec words +behind a tooltip. + +### Faucet, 7 + +Good: one job, one form, one button, the four rules as numbered sentences, the status words are sentences. + +| Problem | Where | +|---|---| +| "not yet open" notice and a form the reader can still submit, which answers "The faucet is not open yet" | form | +| "No account, no sign-in" (antithesis); "Mainnet starts from an empty genesis" stated as fact for a plan | intro, rules | + +### MetaMask, 6 + +Good: two cards, the numbers a wallet needs, a button with five state sentences, the by-hand steps. + +| Problem | Where | +|---|---| +| Canonical and share URL point at /wallet (L4) | head | +| "Explorer: none yet" while /explorer is live; "until the Igneum Wallet ships, MetaMask is the wallet" while 0.1.4 ships; "The Igneum Miner app" | devnet card, app section | +| Not in the nav; reachable from the footer and the faucet only | nav | + +### 404, 6 + +Good: short, three links, noindex. + +| Problem | Where | +|---|---| +| "These four pages are everything the site has" (fifteen pages); "in 17 sections" (nineteen) | copy | +| "Nothing is mined here." is an aphorism | h1 | +| No miner, wallet, explorer or ledger card; no canonical, OG or manifest | links, head | + +### Engineering log (bench), 5 + +Good: every measurement in one place, 83 entries with a contents rail, the scrub keeps machine names out. + +| Problem | Where | +|---|---| +| 189,472 px tall at 1440 (190 screens), 311,114 at 390: Chromium needs minutes to lay it out, and a phone reader scrolls for an hour | whole page | +| Headings carry commit hashes and internal names (by design of the generator) and run past 150 characters in the sticky contents | contents | +| The eyebrow "83 entries, newest at the bottom" is right here and wrong on the two pages that reuse the template | eyebrow | +| One plain-text GitHub Actions URL 404s to the public (L9) | entry 346 | + +Apple would: the log as a list of entries, each collapsed to its heading and date, opened on demand; a search box. + +### Evidence, 6 + +Good: 31 rows with five labels, the label counts as tiles, a sort on every column, "none yet" said in every verification cell. + +| Problem | Where | +|---|---| +| The page shows designed 6 where the source table says 5 (row 17 carries two labels and the build buckets the first) | tiles | +| Two scrub artefacts in the rows ("the Apple M5 Max M5 Max", "a an RTX 5090 on Windows with an RTX 5090") | rows 1, 30 | +| The "What moved on 4 and 5 October" tables of the source are not rendered anywhere | body | +| 23,031 px tall; the table scrolls sideways under 1,140 px with a one-line warning | table | +| Three file paths on the surface | notes | + +### Ledger, 5 + +Good: 167 criticisms with their status and the answer as first written, a search, the counts as chips, nothing deleted. + +| Problem | Where | +|---|---| +| 53,522 px tall at 1440, 113,082 at 390, with a 712 px horizontal overflow at 390 (a long id or path in a card) | whole page | +| 40 section headings with duplicate ids; the section links land on the first | sections | +| 165 "Evidence:" lines and the "Decision owner:" lines are dropped against the renderer's "nothing is dropped" | cards | +| The page's counts differ from the source's count table by 3, 2 and 2 | chips | +| `~/.config/igneum`, "pid 33114", `--rpclisten=0.0.0.0:26610`, "PC 2" fifteen times and "the Mac" nineteen times on a public page; the renderer skips the forbidden-strings hard stop | cards | +| "Nothing deleted, nothing softened." (antithesis) | meta | + +Apple would: the ledger as a filterable list with one card open at a time, the scrub applied, the ids unique. + + +## 3. The tick list: nothing lost + +Appendix A carries every claim, number, date, link and feature per page, with its source and whether the source still +says the same today. The build keeps every row; a row that moves gets its new place written beside it. + +## 4. Links, downloads, icons, 404 + +Every internal anchor resolves (268 fragment links, 0 missing ids). Every local asset exists. Every external link answers +200 except one plain-text GitHub Actions URL in the bench log (private repository, 404 to the public). All four downloads +hash-match the host manifest. The live 404 body is byte-identical to `site/404.html`. + +| # | Finding | Where | Consequence | +|---|---|---|---| +| L1 | `site/downloads.json` is two releases stale (miner 0.3.9 and 0.3.10, written 5 Oct 21:52Z); the host serves 0.3.14 | `site/downloads.json`; `site/build.mjs` 266 to 313 | any build whose 8 s fetch of the host manifest fails stamps dead versions, dead URLs and wrong hashes on every download button | +| L2 | `miner.html` carries v0.3.13 on all four buttons, a Flight Sheet URL that is 404 (`igneum-hive-0.3.13.tar.gz`) and the sha256 of that dead file | `site/miner.html` 462 to 471 | a HiveOS miner copying the repo page's URL gets nothing; the live deploy shows 0.3.14 because the build fetched the manifest, so only a failed fetch exposes it | +| L3 | the host publishes no checksum file beside any download; only the Hive button shows a hash; Windows, Mac and Wallet show none | dl.igneum.network; `index.html` 513 to 514, `wallet.html` 371 | a sceptic cannot verify three of four downloads from the page | +| L4 | `metamask.html` canonical and og:url point at `/wallet` while the sitemap lists `/metamask` | `site/metamask.html` 8, 14; `sitemap.xml` 10 | search folds the page into /wallet | +| L5 | sitemap omits /ledger, /explorer and /faucet; lastmod dates predate the 6 Oct changes | `site/sitemap.xml` | the three pages are found only by crawl | +| L6 | two Open Graph sets: seven pages send a 256 px square (`og-small.png`, `summary` card), seven send 1200 by 630 (`og.png`); `og-coin.png` duplicates `og.png` byte for byte; `og-square.png` is referenced nowhere | `site/partials/head.html`, page heads | a shared link shows a small square for the home page and the litepaper, the two pages most shared | +| L7 | icon links differ by page: address, block, explorer, faucet carry no SVG icon and no 192 or 512 link; ledger lacks 512; 404 lacks canonical, OG, manifest and favicon-32 | page heads | install and tab icons vary by page | +| L8 | `/404` answers 200 as a clean URL | Vercel `cleanUrls` | harmless, noindex | +| L9 | the bench log prints a GitHub Actions URL as text that 404s to the public | `site/bench.html` 346 | a reader following it hits a wall | + +## 5. Live elements and their states + +| Page | Element | Fresh | Loading | Failed fetch | Stale observer | Empty | +|---|---|---|---|---|---|---| +| index | hero strip, chain scene, light-client card | item 0: chain block, shards proven, last lock | "connecting to the devnet observer" (item 0) | "simulated preview · live feed unavailable" with a note (item 0); before item 0 the simulation ran under a live-looking label | "observer offline, last update N ago" (item 0) | not reached: the scene always has the window | +| live | the lane scene, finality strip, proving strip, events, miners table, blocks per minute | reads /api/live every 2 s | counters at 0, "n/a" in proven until the first reply (item 0 made it "pending") | after 3 failures: "api unreachable" in the status tile and "api unreachable, scene frozen" on the canvas; tiles keep their last numbers | "OFFLINE", "last update N ago", the scene frozen with "observer offline" | no empty words: an empty window draws nothing; the tables say "No blocks in the last 10 minutes." and "No events yet." | +| miners | the bench table | static | static | no change (static page) | no change | "No tune reports yet. The first rows appear once five machines with the same card model have reported." | +| explorer | tiles, latest blocks | /api/stats, /api/supply, /api/explorer | "Loading." in the table, tile values at their defaults | tiles keep defaults, the table shows the fetch error text or "The API did not answer." | "OFFLINE", "last update N ago", "observer offline, last known" over the table | "No blocks in the last 24 hours." | +| block, address | the detail pages | /api/explorer | h1 "Block" / the address, cells empty | "The API did not answer: " | no stale word: the detail is the stored block | "Not found." / zeros with no "never seen" sentence | +| faucet | the form | /api/faucet on submit | the form | "The faucet did not answer. Try again in a minute." | not applicable | the not-open notice | +| wallet, miner | download buttons, product names | build-time stamps | static | no change | no change | not applicable | + +Rule for the design: every live element names its state in words with the reason (section 2.5 of the design); no counter +shows `n/a`, `--` or a bare `0`. + +## 6. Contrast + +Computed for every text token on every surface token. Dark passes everywhere (lowest: ember text on the litepaper's +`--surface-2`, 4.79:1). Light fails for both accent colours as text: + +| Theme | Text | On | Ratio | Body 4.5:1 | +|---|---|---|---|---| +| light (site tokens) | ember #D9430F | page #F4F1EC | 3.92 | fail | +| light (site tokens) | ember #D9430F | card #FFFFFF | 4.41 | fail | +| light (site tokens) | molten #B9741C | page #F4F1EC | 3.34 | fail | +| light (site tokens) | quiet #6E6B65 | surface-2 #ECE8E0 | 4.35 | fail | +| light (app tokens) | ember #E04A14 | page #F4F1EC | 3.61 | fail | +| light (app tokens) | molten #B8731F | page #F4F1EC | 3.38 | fail | +| light, proposed | ember-text #B8390C | page, card, row | 5.14, 5.79, 4.74 | pass | +| light, proposed | molten-text #8F5810 | page, card, row | 5.22, 5.88, 4.81 | pass | + +Today the litepaper (light by default) sets eyebrows, links and figures in ember and molten at body sizes: every one of +them is under 4.5:1. The design splits the accents into a fill token and a text token (design 2.1). + +## 7. Keyboard and focus + +Focus is visible: a 2 px ember outline at 3 px offset on every link and button (`site/partials/head.html` 23), confirmed at +Tab 2, 3 and 8 in both themes and at 390 px. The skip link appears on the first Tab. The burger menu at 390 is reachable. +What is missing: the canvas scenes have no keyboard alternative and no text summary for a screen reader beyond the +counters; the litepaper's section pills are buttons without `aria-pressed`; the theme has no control at all on 14 of 15 +pages (the litepaper offers one). + +## 8. Phone width + +| Page | 390 px | Finding | +|---|---|---| +| index | horizontal overflow, page 395 px wide | the livestrip's `nowrap` tiles and the hero grid | +| wallet | horizontal overflow, page 395 px wide | same class | +| ledger | horizontal overflow, page 712 px wide | a long id or path in a card without `overflow-wrap` | +| the other twelve pages | no overflow | | + +## 9. Print + +`/litepaper` printed to A4: three pages in dark mode (the page colours print as set), the nav and footer print, and only +the open section prints because the paper opens in "one section at a time" mode. A reader who prints the litepaper gets +the abstract and the footer. The design adds a print stylesheet and prints the whole paper (design 4). + +## 10. Top ten findings + +Ranked by reach (who sees it) and by what it costs a reader. + +| # | Finding | Consequence per reader | +|---|---|---| +| 1 | The home live scene showed window counts as chain facts and grey blocks (fixed in item 0, commit 84a6de2) | every visitor read a dead chain; fixed before this audit shipped | +| 2 | Fifteen pages carry fifteen stylesheets with three token sets (home, litepaper, chrome) and no light mode on fourteen of them; the litepaper is light by default, the rest dark | a reader crossing from the paper to the home page changes world; a light-mode user gets dark pages everywhere but one | +| 3 | Light-mode accents fail body contrast everywhere they are used as text | the litepaper's links, eyebrows and figures are hard to read in light mode | +| 4 | Scroll-reveal hides every section below the fold until it scrolls into view (`.reveal` at opacity 0) | a slow scroller, a print, a screenshot or a reader with JavaScript off gets blank sections | +| 5 | The print of the litepaper is one section, dark, with nav and footer | the paper cannot be printed | +| 6 | The repo's download snapshot and the miner page are stale against the host (L1, L2) | a failed manifest fetch ships dead links and a wrong hash | +| 7 | Developer text on user surfaces: the litepaper's abstract cites `docs/analysis/chip-model-v3.md` and other repo paths inline; DAA numbers appear without the word for them | a reader who is not in the repo sees file paths | +| 8 | Horizontal overflow at 390 on index and wallet | the phone page scrolls sideways | +| 9 | Three of four downloads show no hash and the host publishes no checksum file (L3) | a sceptic cannot verify the installer | +| 10 | Two Open Graph sets, a wrong canonical on /metamask, three pages missing from the sitemap (L4 to L6) | shared links and search see a smaller, inconsistent site | + +Also found and fixed in item 0 without a row: the scene's fixed 16 ms frame step (double speed on 120 Hz displays), and +polling that stopped for good after one failed fetch. + +## Appendix A. The tick list per page + +`docs/plans/site-ui-3-ticklist.md`: 502 rows (home 88, litepaper 151, nav 11, footer 24, live 22, miners 19, miner 66, +wallet 29, bench 5, evidence 12, ledger 8, explorer 23, block 11, address 9, faucet 8, metamask 9, 404 7), each with its +source and today's verdict (MATCH, STALE, UNSOURCED, APPROX), the ledger's stated sentences with their presence on each +page, the nine "what we do not claim" sentences and the four "what Ember does not claim" sentences verbatim, and the +scrub rules. The build keeps every row; the design's per-page notes (section 5 of `site-ui-3.md`) say where a row moved. + +## Appendix B. The stones + +| # | Stone | Turned | Where | +|---|---|---|---| +| 1 | every page in site/, including API-backed ones and 404 | yes, 15 pages | section 2, `before/` | +| 2 | every state of every live element: loading, empty, failed fetch, stale | yes: failed and stale captured for 10 pages; loading and empty read from each page's JS | section 5, `before-states/` | +| 3 | every link followed, internal and external | yes: 914 attributes, 210 unique, 268 anchors, every external with curl | section 4 | +| 4 | every number traced to its source and checked against the live API or the bench log today | yes, appendix A | appendix A | +| 5 | both themes | yes, dark and light for every page | `before/` | +| 6 | 1440 and 390 | yes | `before/` | +| 7 | keyboard focus | yes, Tab 2, 3, 8, both themes, both widths | section 7, `before-states/*focus*` | +| 8 | contrast | yes, every token pair, both themes | section 6 | +| 9 | the litepaper's every section and footnote | yes, appendix A (L rows) | appendix A | +| 10 | the downloads' hashes against the host | yes, four files fetched and hashed | section 4 | +| 11 | the Open Graph and favicon set | yes, every meta and icon, sizes measured with sips | section 4, L6 and L7 | +| 12 | the 404 page | yes, live body byte-identical, `/404` answers 200 | section 4, L8 | +| 13 | print of the litepaper | yes, both themes, A4 | section 9 | +| 14 | the live API itself against the page | yes, item 0 (height, paid shards, lock index, lag) | commit 84a6de2 | diff --git a/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark.jpg new file mode 100644 index 000000000..8acbb3eac Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-light.jpg b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-light.jpg new file mode 100644 index 000000000..3f01d9818 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-dark.jpg b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-dark.jpg new file mode 100644 index 000000000..cd0132438 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-light.jpg b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-light.jpg new file mode 100644 index 000000000..4401e5f03 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/bench-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/bench-1440-dark.jpg new file mode 100644 index 000000000..fea6015a6 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/bench-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/bench-1440-light.jpg b/docs/plans/site-ui-3-shots/after/bench-1440-light.jpg new file mode 100644 index 000000000..94efcd3a1 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/bench-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/bench-390-dark.jpg b/docs/plans/site-ui-3-shots/after/bench-390-dark.jpg new file mode 100644 index 000000000..7065243d3 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/bench-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/bench-390-light.jpg b/docs/plans/site-ui-3-shots/after/bench-390-light.jpg new file mode 100644 index 000000000..4baf6bc8c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/bench-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-1440-dark.jpg new file mode 100644 index 000000000..1709de996 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-1440-light.jpg b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-1440-light.jpg new file mode 100644 index 000000000..27db8b23d Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-390-dark.jpg b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-390-dark.jpg new file mode 100644 index 000000000..aa5ce6178 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-390-light.jpg b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-390-light.jpg new file mode 100644 index 000000000..53915723c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/block_cc9d87b929b6404c-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/evidence-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/evidence-1440-dark.jpg new file mode 100644 index 000000000..b8907b32c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/evidence-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/evidence-1440-light.jpg b/docs/plans/site-ui-3-shots/after/evidence-1440-light.jpg new file mode 100644 index 000000000..466b00536 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/evidence-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/evidence-390-dark.jpg b/docs/plans/site-ui-3-shots/after/evidence-390-dark.jpg new file mode 100644 index 000000000..07f9cbfdb Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/evidence-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/evidence-390-light.jpg b/docs/plans/site-ui-3-shots/after/evidence-390-light.jpg new file mode 100644 index 000000000..63ed4d4fc Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/evidence-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/explorer-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/explorer-1440-dark.jpg new file mode 100644 index 000000000..c9be143ea Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/explorer-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/explorer-1440-light.jpg b/docs/plans/site-ui-3-shots/after/explorer-1440-light.jpg new file mode 100644 index 000000000..52bf46b63 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/explorer-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/explorer-390-dark.jpg b/docs/plans/site-ui-3-shots/after/explorer-390-dark.jpg new file mode 100644 index 000000000..f91a06cf8 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/explorer-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/explorer-390-light.jpg b/docs/plans/site-ui-3-shots/after/explorer-390-light.jpg new file mode 100644 index 000000000..dd5b5ff0c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/explorer-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/faucet-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/faucet-1440-dark.jpg new file mode 100644 index 000000000..c3219e1ac Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/faucet-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/faucet-1440-light.jpg b/docs/plans/site-ui-3-shots/after/faucet-1440-light.jpg new file mode 100644 index 000000000..c625577e6 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/faucet-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/faucet-390-dark.jpg b/docs/plans/site-ui-3-shots/after/faucet-390-dark.jpg new file mode 100644 index 000000000..ae48a7920 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/faucet-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/faucet-390-light.jpg b/docs/plans/site-ui-3-shots/after/faucet-390-light.jpg new file mode 100644 index 000000000..e7617a9bc Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/faucet-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/index-1440-dark-clip.png b/docs/plans/site-ui-3-shots/after/index-1440-dark-clip.png new file mode 100644 index 000000000..aae007e9a Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-1440-dark-clip.png differ diff --git a/docs/plans/site-ui-3-shots/after/index-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/index-1440-dark.jpg new file mode 100644 index 000000000..cc8ecbd8e Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/index-1440-light-clip.png b/docs/plans/site-ui-3-shots/after/index-1440-light-clip.png new file mode 100644 index 000000000..8a8b16277 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-1440-light-clip.png differ diff --git a/docs/plans/site-ui-3-shots/after/index-1440-light.jpg b/docs/plans/site-ui-3-shots/after/index-1440-light.jpg new file mode 100644 index 000000000..fee829343 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/index-390-dark-clip.png b/docs/plans/site-ui-3-shots/after/index-390-dark-clip.png new file mode 100644 index 000000000..44c234bbf Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-390-dark-clip.png differ diff --git a/docs/plans/site-ui-3-shots/after/index-390-dark.jpg b/docs/plans/site-ui-3-shots/after/index-390-dark.jpg new file mode 100644 index 000000000..d12bfb469 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/index-390-light-clip.png b/docs/plans/site-ui-3-shots/after/index-390-light-clip.png new file mode 100644 index 000000000..a81a4221a Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-390-light-clip.png differ diff --git a/docs/plans/site-ui-3-shots/after/index-390-light.jpg b/docs/plans/site-ui-3-shots/after/index-390-light.jpg new file mode 100644 index 000000000..1576a4694 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/index-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/ledger-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/ledger-1440-dark.jpg new file mode 100644 index 000000000..00af4f7a2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/ledger-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/ledger-1440-light.jpg b/docs/plans/site-ui-3-shots/after/ledger-1440-light.jpg new file mode 100644 index 000000000..00af4f7a2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/ledger-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/ledger-390-dark.jpg b/docs/plans/site-ui-3-shots/after/ledger-390-dark.jpg new file mode 100644 index 000000000..7decfa9f1 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/ledger-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/ledger-390-light.jpg b/docs/plans/site-ui-3-shots/after/ledger-390-light.jpg new file mode 100644 index 000000000..7decfa9f1 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/ledger-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/litepaper-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/litepaper-1440-dark.jpg new file mode 100644 index 000000000..08aea3d5e Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/litepaper-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/litepaper-1440-light.jpg b/docs/plans/site-ui-3-shots/after/litepaper-1440-light.jpg new file mode 100644 index 000000000..0465f63c0 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/litepaper-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/litepaper-1440-light.pdf b/docs/plans/site-ui-3-shots/after/litepaper-1440-light.pdf new file mode 100644 index 000000000..9557aa886 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/litepaper-1440-light.pdf differ diff --git a/docs/plans/site-ui-3-shots/after/litepaper-1440-light.png b/docs/plans/site-ui-3-shots/after/litepaper-1440-light.png new file mode 100644 index 000000000..a2823c518 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/litepaper-1440-light.png differ diff --git a/docs/plans/site-ui-3-shots/after/litepaper-390-dark.jpg b/docs/plans/site-ui-3-shots/after/litepaper-390-dark.jpg new file mode 100644 index 000000000..bd909e6e0 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/litepaper-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/litepaper-390-light.jpg b/docs/plans/site-ui-3-shots/after/litepaper-390-light.jpg new file mode 100644 index 000000000..ced3b2c2c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/litepaper-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/live-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/live-1440-dark.jpg new file mode 100644 index 000000000..04d70c109 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/live-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/live-1440-light.jpg b/docs/plans/site-ui-3-shots/after/live-1440-light.jpg new file mode 100644 index 000000000..f321e9082 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/live-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/live-390-dark.jpg b/docs/plans/site-ui-3-shots/after/live-390-dark.jpg new file mode 100644 index 000000000..f12f8e83c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/live-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/live-390-light.jpg b/docs/plans/site-ui-3-shots/after/live-390-light.jpg new file mode 100644 index 000000000..8f1d4667c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/live-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/metamask-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/metamask-1440-dark.jpg new file mode 100644 index 000000000..a5cd1d97a Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/metamask-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/metamask-1440-light.jpg b/docs/plans/site-ui-3-shots/after/metamask-1440-light.jpg new file mode 100644 index 000000000..3d065ea39 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/metamask-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/metamask-390-dark.jpg b/docs/plans/site-ui-3-shots/after/metamask-390-dark.jpg new file mode 100644 index 000000000..ebbced3d8 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/metamask-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/metamask-390-light.jpg b/docs/plans/site-ui-3-shots/after/metamask-390-light.jpg new file mode 100644 index 000000000..596f3fd77 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/metamask-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miner-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/miner-1440-dark.jpg new file mode 100644 index 000000000..b0bd183ef Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miner-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miner-1440-light.jpg b/docs/plans/site-ui-3-shots/after/miner-1440-light.jpg new file mode 100644 index 000000000..e3820e07b Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miner-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miner-390-dark.jpg b/docs/plans/site-ui-3-shots/after/miner-390-dark.jpg new file mode 100644 index 000000000..d4605f028 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miner-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miner-390-light.jpg b/docs/plans/site-ui-3-shots/after/miner-390-light.jpg new file mode 100644 index 000000000..ff8773bcd Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miner-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miners-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/miners-1440-dark.jpg new file mode 100644 index 000000000..974f6e66f Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miners-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miners-1440-light.jpg b/docs/plans/site-ui-3-shots/after/miners-1440-light.jpg new file mode 100644 index 000000000..980fa550b Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miners-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miners-390-dark.jpg b/docs/plans/site-ui-3-shots/after/miners-390-dark.jpg new file mode 100644 index 000000000..730400a24 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miners-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/miners-390-light.jpg b/docs/plans/site-ui-3-shots/after/miners-390-light.jpg new file mode 100644 index 000000000..459e045e5 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/miners-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/no-such-page-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/no-such-page-1440-dark.jpg new file mode 100644 index 000000000..0f4b22f69 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/no-such-page-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/no-such-page-1440-light.jpg b/docs/plans/site-ui-3-shots/after/no-such-page-1440-light.jpg new file mode 100644 index 000000000..7c44c82ac Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/no-such-page-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/no-such-page-390-dark.jpg b/docs/plans/site-ui-3-shots/after/no-such-page-390-dark.jpg new file mode 100644 index 000000000..afe56624c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/no-such-page-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/no-such-page-390-light.jpg b/docs/plans/site-ui-3-shots/after/no-such-page-390-light.jpg new file mode 100644 index 000000000..e3d48f5e4 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/no-such-page-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/wallet-1440-dark.jpg b/docs/plans/site-ui-3-shots/after/wallet-1440-dark.jpg new file mode 100644 index 000000000..afddf42cd Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/wallet-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/wallet-1440-light.jpg b/docs/plans/site-ui-3-shots/after/wallet-1440-light.jpg new file mode 100644 index 000000000..ecb4c5b8c Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/wallet-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/wallet-390-dark.jpg b/docs/plans/site-ui-3-shots/after/wallet-390-dark.jpg new file mode 100644 index 000000000..511694e09 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/wallet-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/after/wallet-390-light.jpg b/docs/plans/site-ui-3-shots/after/wallet-390-light.jpg new file mode 100644 index 000000000..6cee2e102 Binary files /dev/null and b/docs/plans/site-ui-3-shots/after/wallet-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark-fail.jpg new file mode 100644 index 000000000..b526e30e8 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/block_cc9d87b929b6404c-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/block_cc9d87b929b6404c-1440-dark-fail.jpg new file mode 100644 index 000000000..9a5022f21 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/block_cc9d87b929b6404c-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/block_cc9d87b929b6404c-1440-dark-stale.jpg b/docs/plans/site-ui-3-shots/before-states/block_cc9d87b929b6404c-1440-dark-stale.jpg new file mode 100644 index 000000000..c02325d76 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/block_cc9d87b929b6404c-1440-dark-stale.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/explorer-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/explorer-1440-dark-fail.jpg new file mode 100644 index 000000000..3ff25031c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/explorer-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/explorer-1440-dark-stale.jpg b/docs/plans/site-ui-3-shots/before-states/explorer-1440-dark-stale.jpg new file mode 100644 index 000000000..0162dea07 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/explorer-1440-dark-stale.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/faucet-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/faucet-1440-dark-fail.jpg new file mode 100644 index 000000000..dc899e959 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/faucet-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/faucet-1440-dark-stale.jpg b/docs/plans/site-ui-3-shots/before-states/faucet-1440-dark-stale.jpg new file mode 100644 index 000000000..dc899e959 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/faucet-1440-dark-stale.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-fail.jpg new file mode 100644 index 000000000..3bd4cff3a Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-1440-dark-focus3.png b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-focus3.png new file mode 100644 index 000000000..e51008e29 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-focus3.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-1440-dark-focus8.png b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-focus8.png new file mode 100644 index 000000000..c001b6ec0 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-focus8.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-1440-dark-stale.jpg b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-stale.jpg new file mode 100644 index 000000000..c398578bf Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-1440-dark-stale.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-1440-light-focus3.png b/docs/plans/site-ui-3-shots/before-states/index-1440-light-focus3.png new file mode 100644 index 000000000..706dd71bc Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-1440-light-focus3.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-1440-light-focus8.png b/docs/plans/site-ui-3-shots/before-states/index-1440-light-focus8.png new file mode 100644 index 000000000..5347dff5b Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-1440-light-focus8.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/index-390-dark-focus2.png b/docs/plans/site-ui-3-shots/before-states/index-390-dark-focus2.png new file mode 100644 index 000000000..9783a2e27 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/index-390-dark-focus2.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/litepaper-1440-dark.pdf b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-dark.pdf new file mode 100644 index 000000000..29afd3069 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-dark.pdf differ diff --git a/docs/plans/site-ui-3-shots/before-states/litepaper-1440-dark.png b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-dark.png new file mode 100644 index 000000000..f9b2d7a65 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-dark.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/litepaper-1440-light.pdf b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-light.pdf new file mode 100644 index 000000000..a58f6c772 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-light.pdf differ diff --git a/docs/plans/site-ui-3-shots/before-states/litepaper-1440-light.png b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-light.png new file mode 100644 index 000000000..447425a11 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/litepaper-1440-light.png differ diff --git a/docs/plans/site-ui-3-shots/before-states/live-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/live-1440-dark-fail.jpg new file mode 100644 index 000000000..69891690d Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/live-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/live-1440-dark-stale.jpg b/docs/plans/site-ui-3-shots/before-states/live-1440-dark-stale.jpg new file mode 100644 index 000000000..9d5e4e2a5 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/live-1440-dark-stale.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/miner-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/miner-1440-dark-fail.jpg new file mode 100644 index 000000000..91d0cdad2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/miner-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/miners-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/miners-1440-dark-fail.jpg new file mode 100644 index 000000000..a7992fdc2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/miners-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/miners-1440-dark-stale.jpg b/docs/plans/site-ui-3-shots/before-states/miners-1440-dark-stale.jpg new file mode 100644 index 000000000..a7992fdc2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/miners-1440-dark-stale.jpg differ diff --git a/docs/plans/site-ui-3-shots/before-states/wallet-1440-dark-fail.jpg b/docs/plans/site-ui-3-shots/before-states/wallet-1440-dark-fail.jpg new file mode 100644 index 000000000..be706fa3c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before-states/wallet-1440-dark-fail.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark.jpg new file mode 100644 index 000000000..bbe4ae0a2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-light.jpg b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-light.jpg new file mode 100644 index 000000000..85665d222 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-dark.jpg b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-dark.jpg new file mode 100644 index 000000000..f94781f32 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-light.jpg b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-light.jpg new file mode 100644 index 000000000..f94781f32 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/address_igneumdev:qz9hw3xy72g4guwfddvpxs-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/bench-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/bench-1440-dark.jpg new file mode 100644 index 000000000..4ed3ae62c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/bench-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/bench-1440-light.jpg b/docs/plans/site-ui-3-shots/before/bench-1440-light.jpg new file mode 100644 index 000000000..4ed3ae62c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/bench-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/bench-390-dark.jpg b/docs/plans/site-ui-3-shots/before/bench-390-dark.jpg new file mode 100644 index 000000000..16edcced1 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/bench-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/bench-390-light.jpg b/docs/plans/site-ui-3-shots/before/bench-390-light.jpg new file mode 100644 index 000000000..16edcced1 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/bench-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-1440-dark.jpg new file mode 100644 index 000000000..c02325d76 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-1440-light.jpg b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-1440-light.jpg new file mode 100644 index 000000000..c02325d76 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-390-dark.jpg b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-390-dark.jpg new file mode 100644 index 000000000..063a4028b Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-390-light.jpg b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-390-light.jpg new file mode 100644 index 000000000..063a4028b Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/block_cc9d87b929b6404c-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/evidence-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/evidence-1440-dark.jpg new file mode 100644 index 000000000..45dbfd655 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/evidence-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/evidence-1440-light.jpg b/docs/plans/site-ui-3-shots/before/evidence-1440-light.jpg new file mode 100644 index 000000000..45dbfd655 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/evidence-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/evidence-390-dark.jpg b/docs/plans/site-ui-3-shots/before/evidence-390-dark.jpg new file mode 100644 index 000000000..e5d61bb03 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/evidence-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/evidence-390-light.jpg b/docs/plans/site-ui-3-shots/before/evidence-390-light.jpg new file mode 100644 index 000000000..e5d61bb03 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/evidence-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/explorer-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/explorer-1440-dark.jpg new file mode 100644 index 000000000..8987d6595 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/explorer-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/explorer-1440-light.jpg b/docs/plans/site-ui-3-shots/before/explorer-1440-light.jpg new file mode 100644 index 000000000..d45788542 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/explorer-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/explorer-390-dark.jpg b/docs/plans/site-ui-3-shots/before/explorer-390-dark.jpg new file mode 100644 index 000000000..74d789637 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/explorer-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/explorer-390-light.jpg b/docs/plans/site-ui-3-shots/before/explorer-390-light.jpg new file mode 100644 index 000000000..d3f38a5e4 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/explorer-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/faucet-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/faucet-1440-dark.jpg new file mode 100644 index 000000000..dc899e959 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/faucet-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/faucet-1440-light.jpg b/docs/plans/site-ui-3-shots/before/faucet-1440-light.jpg new file mode 100644 index 000000000..dc899e959 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/faucet-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/faucet-390-dark.jpg b/docs/plans/site-ui-3-shots/before/faucet-390-dark.jpg new file mode 100644 index 000000000..ccbd0768f Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/faucet-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/faucet-390-light.jpg b/docs/plans/site-ui-3-shots/before/faucet-390-light.jpg new file mode 100644 index 000000000..ccbd0768f Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/faucet-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/index-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/index-1440-dark.jpg new file mode 100644 index 000000000..a1ee3d7da Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/index-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/index-1440-light.jpg b/docs/plans/site-ui-3-shots/before/index-1440-light.jpg new file mode 100644 index 000000000..7a1cb4ee9 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/index-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/index-390-dark.jpg b/docs/plans/site-ui-3-shots/before/index-390-dark.jpg new file mode 100644 index 000000000..45826abb2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/index-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/index-390-light.jpg b/docs/plans/site-ui-3-shots/before/index-390-light.jpg new file mode 100644 index 000000000..236998c81 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/index-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/ledger-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/ledger-1440-dark.jpg new file mode 100644 index 000000000..417ab0e18 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/ledger-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/ledger-1440-light.jpg b/docs/plans/site-ui-3-shots/before/ledger-1440-light.jpg new file mode 100644 index 000000000..417ab0e18 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/ledger-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/ledger-390-dark.jpg b/docs/plans/site-ui-3-shots/before/ledger-390-dark.jpg new file mode 100644 index 000000000..46eaca45c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/ledger-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/ledger-390-light.jpg b/docs/plans/site-ui-3-shots/before/ledger-390-light.jpg new file mode 100644 index 000000000..46eaca45c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/ledger-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/litepaper-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/litepaper-1440-dark.jpg new file mode 100644 index 000000000..f37a6f97b Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/litepaper-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/litepaper-1440-light.jpg b/docs/plans/site-ui-3-shots/before/litepaper-1440-light.jpg new file mode 100644 index 000000000..9992518eb Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/litepaper-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/litepaper-390-dark.jpg b/docs/plans/site-ui-3-shots/before/litepaper-390-dark.jpg new file mode 100644 index 000000000..881d6fb9f Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/litepaper-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/litepaper-390-light.jpg b/docs/plans/site-ui-3-shots/before/litepaper-390-light.jpg new file mode 100644 index 000000000..c7e8510fe Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/litepaper-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/live-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/live-1440-dark.jpg new file mode 100644 index 000000000..26bb2cc5b Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/live-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/live-1440-light.jpg b/docs/plans/site-ui-3-shots/before/live-1440-light.jpg new file mode 100644 index 000000000..80a6269ba Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/live-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/live-390-dark.jpg b/docs/plans/site-ui-3-shots/before/live-390-dark.jpg new file mode 100644 index 000000000..20d7773cd Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/live-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/live-390-light.jpg b/docs/plans/site-ui-3-shots/before/live-390-light.jpg new file mode 100644 index 000000000..814400974 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/live-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/metamask-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/metamask-1440-dark.jpg new file mode 100644 index 000000000..408913fa5 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/metamask-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/metamask-1440-light.jpg b/docs/plans/site-ui-3-shots/before/metamask-1440-light.jpg new file mode 100644 index 000000000..408913fa5 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/metamask-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/metamask-390-dark.jpg b/docs/plans/site-ui-3-shots/before/metamask-390-dark.jpg new file mode 100644 index 000000000..d119e2804 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/metamask-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/metamask-390-light.jpg b/docs/plans/site-ui-3-shots/before/metamask-390-light.jpg new file mode 100644 index 000000000..d119e2804 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/metamask-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miner-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/miner-1440-dark.jpg new file mode 100644 index 000000000..b04991df9 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miner-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miner-1440-light.jpg b/docs/plans/site-ui-3-shots/before/miner-1440-light.jpg new file mode 100644 index 000000000..b04991df9 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miner-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miner-390-dark.jpg b/docs/plans/site-ui-3-shots/before/miner-390-dark.jpg new file mode 100644 index 000000000..ec8ce2d64 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miner-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miner-390-light.jpg b/docs/plans/site-ui-3-shots/before/miner-390-light.jpg new file mode 100644 index 000000000..ec8ce2d64 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miner-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miners-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/miners-1440-dark.jpg new file mode 100644 index 000000000..a7992fdc2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miners-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miners-1440-light.jpg b/docs/plans/site-ui-3-shots/before/miners-1440-light.jpg new file mode 100644 index 000000000..a7992fdc2 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miners-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miners-390-dark.jpg b/docs/plans/site-ui-3-shots/before/miners-390-dark.jpg new file mode 100644 index 000000000..fef408dc0 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miners-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/miners-390-light.jpg b/docs/plans/site-ui-3-shots/before/miners-390-light.jpg new file mode 100644 index 000000000..fef408dc0 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/miners-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/no-such-page-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/no-such-page-1440-dark.jpg new file mode 100644 index 000000000..be66041eb Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/no-such-page-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/no-such-page-1440-light.jpg b/docs/plans/site-ui-3-shots/before/no-such-page-1440-light.jpg new file mode 100644 index 000000000..be66041eb Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/no-such-page-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/no-such-page-390-dark.jpg b/docs/plans/site-ui-3-shots/before/no-such-page-390-dark.jpg new file mode 100644 index 000000000..b48a75e06 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/no-such-page-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/no-such-page-390-light.jpg b/docs/plans/site-ui-3-shots/before/no-such-page-390-light.jpg new file mode 100644 index 000000000..b48a75e06 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/no-such-page-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/wallet-1440-dark.jpg b/docs/plans/site-ui-3-shots/before/wallet-1440-dark.jpg new file mode 100644 index 000000000..be706fa3c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/wallet-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/wallet-1440-light.jpg b/docs/plans/site-ui-3-shots/before/wallet-1440-light.jpg new file mode 100644 index 000000000..be706fa3c Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/wallet-1440-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/wallet-390-dark.jpg b/docs/plans/site-ui-3-shots/before/wallet-390-dark.jpg new file mode 100644 index 000000000..8eb169456 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/wallet-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/before/wallet-390-light.jpg b/docs/plans/site-ui-3-shots/before/wallet-390-light.jpg new file mode 100644 index 000000000..8eb169456 Binary files /dev/null and b/docs/plans/site-ui-3-shots/before/wallet-390-light.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-a-1440-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scene-a-1440-dark.jpg new file mode 100644 index 000000000..e42a2dd53 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-a-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-a-1440-dark.webm b/docs/plans/site-ui-3-shots/scenes/scene-a-1440-dark.webm new file mode 100644 index 000000000..13d8cf194 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-a-1440-dark.webm differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-a-390-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scene-a-390-dark.jpg new file mode 100644 index 000000000..160700725 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-a-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-b-1440-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scene-b-1440-dark.jpg new file mode 100644 index 000000000..37b32c6c4 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-b-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-b-1440-dark.webm b/docs/plans/site-ui-3-shots/scenes/scene-b-1440-dark.webm new file mode 100644 index 000000000..d6bfdedd4 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-b-1440-dark.webm differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-b-390-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scene-b-390-dark.jpg new file mode 100644 index 000000000..456acc600 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-b-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-c-1440-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scene-c-1440-dark.jpg new file mode 100644 index 000000000..8ca64e0a0 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-c-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-c-1440-dark.webm b/docs/plans/site-ui-3-shots/scenes/scene-c-1440-dark.webm new file mode 100644 index 000000000..11d1083b7 Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-c-1440-dark.webm differ diff --git a/docs/plans/site-ui-3-shots/scenes/scene-c-390-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scene-c-390-dark.jpg new file mode 100644 index 000000000..7fb76fe9a Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scene-c-390-dark.jpg differ diff --git a/docs/plans/site-ui-3-shots/scenes/scenes-1440-dark.jpg b/docs/plans/site-ui-3-shots/scenes/scenes-1440-dark.jpg new file mode 100644 index 000000000..2d6bb1f8d Binary files /dev/null and b/docs/plans/site-ui-3-shots/scenes/scenes-1440-dark.jpg differ diff --git a/docs/plans/site-ui-3-ticklist.md b/docs/plans/site-ui-3-ticklist.md new file mode 100644 index 000000000..a264dd52f --- /dev/null +++ b/docs/plans/site-ui-3-ticklist.md @@ -0,0 +1,617 @@ +# Site UI 3 audit, appendix A: the tick list + +Every visible claim, number, date, link and feature per page, in reading order, with its source and today's verdict. +Read 6 October 2026 at 18:16 UTC (API: height 140,681; 0.983 blocks/s; 2.66 GH/s; 71 vote keys in 10 min; last lock +6,795; proving active since DAA 84,100; 2,149 shards paid; median proof lag 387.5 s; verifier Off on the observer's node). +Verdicts: MATCH (source says the same today), STALE (source moved on), UNSOURCED (no source in the repository or the +API), APPROX (labelled approximate on the page or in the source). The build keeps every row; a row that moves gets its +new place written in the design's per-page notes. Rows marked "generated" mirror a markdown document and are kept by +keeping the generator. + +Row counts: home 88, litepaper 151, nav 11, footer 24, live 22, miners 19, miner 66, wallet 29, bench 5 hand-written, +evidence 12 hand-written, ledger 8 hand-written, explorer 23, block 11, address 9, faucet 8, metamask 9, 404 7. Total 502. + +## Home page (site/index.html) + +| id | section | text | kind | source and verdict | +|---|---|---|---|---| +| I-1 | nav | Litepaper, Live devnet, Engineering log, Miner, Wallet, Evidence, GitHub, "The miner" | links | all 200 | +| I-2 | hero | "GPUs are back · for good" | claim | | +| I-3 | hero | "Mined by GPUs. Proven by fire." | tagline | ledger row 820 allows it | +| I-4 | hero | "A new mining program every hour, compiled on the card" | claim | bench-log 4 Oct swap entry, MATCH | +| I-5 | hero | "strongest chip reaches 5x to 9x per joule against an RTX 5090" | number | docs/plans/morning-2026-10-06.md 35-40, evidence row 17; APPROX (model); the plan's line 55 says pick a wording before any public push | +| I-6 | hero | "about 2x once the lever now in its gates ships" | number | morning table row reads 2.7x; counter-asic-3-status.md not in tree; UNSOURCED here | +| I-7 | hero | "the numbers" to /bench#counter-asic-2-0-the-numbers | link | anchor exists | +| I-8 | hero | "Every NVIDIA card from 8 GB proves and is paid for it; 12 GB and up mine and prove; AMD and Apple cards mine" | claim | morning 107 (patched server ships in 0.3.14); litepaper 452 says not in the shipped app; live verifier Off; STALE wording (present tense) | +| I-9 | hero | "No premine, no stake, no foundation" | claim | spec 02, 05; MATCH | +| I-10 | hero | "See the miner" (#mine), "Read the litepaper" | links | | +| I-11 | hero card | "This tab · light client", badge PREVIEW / LIVE | feature, state | /verify/verify.js | +| I-12 | hero card | "Browser checks Igneum. A checkpoint certificate, verified in this tab. Voter list from the node." | claim | /api/checkpoint 200 | +| I-13 | hero card | BLOCK PROOF "not yet" (title: first off-chain GPU proof 4 Oct 2026) | state, date | bench-log 578; MATCH | +| I-14 | hero card | CHECKPOINT "checking" then the index | state | live | +| I-15 | hero card | PROOF SYSTEM "BLS aggregate, version 1" | claim | verify/core.js | +| I-16 | hero card | VERIFIED IN THIS TAB "checking" then the result | feature | | +| I-17 | live strip | vote keys in 10 min, blocks/s, hash rate, chain block (item 0) | feature | /api/live state | +| I-18 | stats | "1 / s blocks, rising to 10" | number | /api/live 0.983/s; MATCH | +| I-19 | stats | "~60 s to a proof at launch, the target" | number | roadmap gate 3; live lag 387 s not stated | +| I-20 | stats | "First GPU proof of a block: 1.4 s on an RTX 5090, 4 Oct 2026" | number, date | bench-log 590; MATCH | +| I-21 | stats | "0 premine" | number | MATCH | +| I-22 | stats | "4B IGN hard cap, ever" | number | spec 02 118; /api/supply; MATCH | +| I-23 | stats | "100% of emission to miners and provers; the protocol carries no fee" | number | spec 05 61; /api/stats split; MATCH | +| I-24 | prove | "Watch the chain prove itself" | heading | | +| I-25 | prove | "Blocks every second, proven in shards, locked every 30 seconds" | number | checkpointInterval 30; MATCH | +| I-26 | prove | "First live lock 4 Oct 2026: checkpoint 242, 77.4% of all weight, two hours after genesis" | number, date | bench-log 713; MATCH | +| I-27 | prove | chain scene with chain block, shards proven, last lock (item 0) | feature | /api/live | +| I-28 | prove | legends (simulated, live) | feature | | +| I-29 | prove | viz note "One node is read every 2 s ..." | feature | | +| I-30 | prove | "This hour's program", countdown, "64 instructions x 8 iterations", "seed from a locked checkpoint, through a 10 minute delay" | feature, numbers | spec 00 31; bench-log 150; MATCH | +| I-31 | prove | "A new program every hour. Last hour's chip is already obsolete." | claim | aphorism, copy law | +| I-32 | prove | "First live swap 4 Oct 2026: Apple, NVIDIA and AMD kept hashing through it, 0 rejected blocks." | number, date | bench-log 634, 644; MATCH | +| I-33 | prove | feed rows batch proof, state proof, fault proof "at testnet"; "IGN burned from jobs" "phase two" | state words | | +| I-34 | prove | "Jobs are paid on the customer's chain at launch; settlement in IGN with a 10% burn follows the proof bridge in phase two" | number | spec 05 47-48; evidence row 24; MATCH; ledger P10 sentence | +| I-35 | prove | "Live rows arrive with the public testnet, August 2027" | date | roadmap; ledger X3 sentence | +| I-36 | prove | "Read more in the litepaper" /litepaper#proving | link | exists | +| I-37 | randomx | "Monero's idea, finished for GPUs" | heading | ledger overclaim 68 asks "Monero's technique, applied to GPUs"; not applied | +| I-38 | randomx | "kept chips off Monero since 2019 (approximate)" | date | asic history row 16; ledger C2 sentence; MATCH | +| I-39 | randomx | table CPUs/GPUs; every hash/every hour; "2 GB, fixed" / "2 GB, growing (proposed schedule, fixed at the testnet genesis: 2 GB, doubling at years 4, 12 and 28)"; any CPU | numbers | evidence row 31 (schedule 4, 12, 28, 60, recommended); APPROX | +| I-40 | randomx | "The program keeps changing on a schedule fixed at genesis. Nobody touches it." | claim | aphorism | +| I-41 | randomx | /litepaper#randomx; "Built on the shoulders: Kaspa's GHOSTDAG and node, Monero's RandomX idea, Chia's class-group VDF, Ethereum's EVM, Succinct's SP1, BLS12-381 and Bitcoin's address format"; /litepaper#shoulders | claim, links | exist | +| I-42 | build | "One chain, three jobs" | heading | | +| I-43 | build | "Any 4 GB card at launch, 8 GB from about year 4 ... doubling at years 4, 12 and 28, approximate. 80% of each block to its finder." | numbers | spec 02 123; evidence row 31; MATCH, APPROX | +| I-44 | build | "The same card proves shards and sells proofs to other chains."; #prove | claim, link | | +| I-45 | build | "Ethereum bytecode, with the differences documented ... 20% of priority fees to the contracts that ran, stated at the fee levels that exist."; /litepaper#builders-ask | number, link | spec 05 25; MATCH; ledger overclaim 35 wording | +| I-46 | build | /litepaper#building | link | exists | +| I-47 | mine | "One click. The card mines; every NVIDIA card from 8 GB proves, 12 GB and up mine and prove." | heading | 91 characters; see I-8 | +| I-48 | mine | "Igneum Ember finds your GPU, makes a wallet for you and runs the node, the miner and the prover as one app." | claim | | +| I-49 | mine | screenshot; "Igneum Ember (the app is still labelled Igneum Miner until 0.3.6) on an Apple M5 Max, live devnet, 5 Oct 2026." | number, date | litepaper 400 says 0.3.13 still says Igneum Miner; STALE | +| I-50 | mine | "NVIDIA, AMD, Apple silicon. Found by itself. One worker per card, several identities each." | claim | | +| I-51 | mine | "Compiled ahead and swapped in 0.01 ms on the live devnet, 0 rejected blocks." | number | bench-log 644; MATCH | +| I-52 | mine | "Signed updates at a safe moment ... The old version comes back if the new one fails to start." | claim | | +| I-53 | mine | "Kernel variants raced every hour, hash per watt swept, every number in the bench table." | claim | sweep not yet run on a card (litepaper 612); overclaim | +| I-54 | mine | Windows "v0.3.14 · 45.4 MB" | link, number | host 0.3.14, 45,416,619 bytes; MATCH live; downloads.json snapshot 0.3.10 STALE | +| I-55 | mine | macOS "v0.3.14 · 41.9 MB" | link, number | host MATCH; snapshot STALE | +| I-56 | mine | "Linux · HiveOS" /miner#get | link | exists | +| I-57 | mine | "Devnet: coins have no value and the chain may be reset." | claim | | +| I-58 | mine | "Public testnet: not yet open; the devnet build is here for people who want to look." | state | ledger X2 sentence | +| I-59 | mine | /miner; "optional 1% dev fee, like other GPU miners, off with one flag. Download only from this domain. Nobody from Igneum will ask for your seed." | number, claim | bench-log dev fee entry; MATCH | +| I-60 | terms | "What you agree to when you run the testnet miner" | heading | 48 characters | +| I-61 | terms | "No value ... no airdrop, no points scheme ... Mainnet starts from an empty genesis." | claim | | +| I-62 | terms | "Every reset is announced at least seven days ahead on this page and in the app ... The devnet that runs today resets without notice." | number | testnet-go.md 75, PLACEHOLDER text; APPROX | +| I-63 | terms | "What the app sends home ... a service Igneum runs on Vercel ... Never your seed phrase ... Nothing is sold or shared." | claim | | +| I-64 | terms | /metamask; "optional 1% fee ... no fee to anyone" | link, number | | +| I-65 | wallet | "Your coins, your wallet"; "Igneum Wallet holds the key the miner makes for you and verifies finality itself. MetaMask works too." | claim | | +| I-66 | wallet | states "pending", "in a block", "final · cp 5" | feature | "cp 5" is an abbreviation | +| I-67 | wallet | "24 words, three typed back, a password. Argon2id and XChaCha20-Poly1305. Nothing leaves." | claim | app/igneum-wallet not in this tree; UNSOURCED here | +| I-68 | wallet | "Rewards in one history ... QR drawn locally"; "Reads your own node ... Nobody else sees your balance." | claims | | +| I-69 | wallet | /wallet, /wallet#metamask | links | exist | +| I-70 | wallet | "macOS first, Windows next. Public testnet first." | state | | +| I-71 | wallet | screenshot; "Igneum Wallet on a private test network, 5 Oct 2026. The address is an example." | date | | +| I-72 | journey | "Where Igneum is right now"; label from JSON "updated 6 Oct 2026" | state | | +| I-73 | journey | "Thirteen months, four public gates, each a measurement published pass or fail." | number | litepaper roadmap; MATCH | +| I-74 | journey | six phases with dates and gates (JSON) | dates, numbers | phase 2 gate text differs from the litepaper's gate 2; three phases active at once | +| I-75 | journey | "Day one was 3 October 2026" | date | bench-log 213 | +| I-76 | journey | log of 40 entries, 8 shown, "Show all 40 entries" | feature | bench-log headings; MATCH; the eight default entries carry raw shorthand and scrub artefacts | +| I-77 | journey | /litepaper#roadmap | link | exists | +| I-78 | economics | "Every coin, mined"; "Hard cap of 4 billion IGN, halving every two years for ever." | number | spec 02 121; MATCH | +| I-79 | economics | bar "80% miners", "20% provers", "0% anyone else in the protocol" | numbers | MATCH | +| I-80 | economics | tiles "0 premine", "0 stake, anywhere", "0 admin keys in consensus", "90% of blocks must signal to upgrade" | numbers | spec 00 61, 05 83; ledger G4 tile; MATCH | +| I-81 | economics | "Base fee burned. The one payment to the project is the Ember software's optional 1% dev fee ... coinbase's 20% output is burned under the tag igneum-proving-pool-v0 ... separate escrow ... same 20%." | numbers | ledger E5 sentence verbatim; evidence rows 20, 21; MATCH | +| I-82 | economics | /litepaper#economics | link | exists | +| I-83 | band | "Read what Igneum does not claim." "Proof lag, chip economics, the market size, and the one rule external review will try hardest to break." | claim, link | | +| I-84 | footer | tagline | claim | | +| I-85 to I-88 | footer | the 24 footer rows (see Footer below) | links, claims | | + +Ledger sentences required on the home page: E5 (yes, verbatim), G4 tile (yes), C2 hero chip sentence (no: hero now carries the model figures), C2 RandomX "since 2019 (approximate)" (yes), X2 notice (yes; the version differs from the ledger's v0.3.9 note), X3 (yes), X7 footer routes (yes), X8 phase 6 (yes), L2 "Half of all IGN" absent (yes), overclaim 68 (not applied), overclaim 57 "approximate" on card lifetime (yes). + +## Litepaper (site/litepaper.html) + +| id | section | text | kind | source and verdict | +|---|---|---|---|---| +| L-1 | cover | "Litepaper · version 0.2" | number | | +| L-2 | cover | tagline; "protected from specialised chips by a program that changes every hour" | claim | | +| L-3 | cover | "Published 3 October 2026 · updated 5 October 2026" | date | body cites 6 October in nine places; STALE | +| L-4 | cover | "Coin IGN · cap 4,000,000,000" | number | MATCH | +| L-5 | cover | "Status devnet live, pre-testnet" | state | | +| L-6 | cover | "Method one founder with AI systems · external review before gate 3" | claim | ledger G2 sentence | +| L-7 | cover | "This is not an offer to sell anything" | claim | | +| L-8 | contents | 19 sections; "One section at a time" / "Whole paper" (localStorage); "Latin igneum: fiery. A cupel ..." | feature | the single-section mode breaks print | +| L-9 | abstract | "NVIDIA cards also prove every block with zero-knowledge proofs and sell proving to other chains" | claim | | +| L-10 | abstract | "strongest recompute chip ... 256 MiB cache on-die, reaches under 1x per chip" | number | chip-model-v3.md 69, 82; MATCH (model) | +| L-11 | abstract | "memory-controller chip ... 1.2x per chip and, in our model, 5x to 9x per joule" | number | morning 39-40; APPROX; not in the file the page cites | +| L-12 | abstract | "Ethash chips of this class reached 2.1x to 4.8x" | number | asic history row 3; MATCH | +| L-13 | abstract | "brings the chip to about 2x" | number | plan table says 2.7x; UNSOURCED here | +| L-14 | abstract | sources: chip-model-v3.md section 5, 6 October 2026; asic history (Phoenix 2020, X4 2021, E9 2022); Counter ASIC 3.0 item 8 (5.6x to 2.1x, 0.2%, gates G1 to G6) | numbers, dates | chip-model-v3 has sections 1 to 4, dated 5 Oct; counter-asic-3 table has items 1 to 7; citation wrong, UNSOURCED | +| L-15 | abstract | "tested by paid independent cryptanalysis and the public benchmark" | claim | | +| L-16 | abstract | "included in about one second, proven within about a minute at launch, and locked by miners within about two" | numbers | spec 03; MATCH as design | +| L-17 | abstract | "no premine, no pre-sale, no treasury taken from emission, no stake anywhere in consensus, and no dependence on any other chain" | claim | MATCH | +| L-18 | abstract | "a chip for the whole program space is a GPU without the graphics parts" | claim | | +| L-19 | abstract | "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" | claim | ledger P7 sentence | +| L-20 | abstract | tiles 1/s, ~60 s, 0, 100% | numbers | MATCH (target); live lag not stated | +| L-21 | precedents | "We know of no chain that combines them ... corrected when shown wrong." | claim | ledger C11 sentence | +| L-22 | precedents | column "State, 5 Oct 2026" | date | | +| L-23 | precedents | RandomX since 2019; "ProgPoW, as KAWPOW on Ravencoin since 2020 (approximate)"; "Measured: hourly swaps on Apple, NVIDIA and AMD cards on the live devnet, 4 October 2026" | dates, state | ledger M4 sentence; bench-log 634; MATCH | +| L-24 | precedents | Primecoin 2013, Aleo (approximate); "Implemented: proving v0 on the live devnet since 5 October 2026. The job market ... Designed" | state, date | activation_daa 84,100; MATCH | +| L-25 | precedents | Conflux since 2020 (approximate); "Implemented in part ... aggregated block proof ... Designed" | state | | +| L-26 | precedents | Decred, Horizen, Kaspa (approximate); "Vote weight is 30 days of blocks per key"; "rule v2 live, first lock 4 October 2026. External review is owed at gate 3" | number, date | bench-log 713; MATCH | +| L-27 | precedents | "Kaspa's fair launch."; Zcash, Decred (approximate); "optional 1% dev fee ... off with one flag"; "80/20 coinbase on the devnet" | numbers | ledger C3; /api/stats split; MATCH | +| L-28 | precedents | sync committee (approximate); "The consensus proof that makes the checkpoint self-verifying is phase two"; "The home page's card verifies a devnet certificate in the browser today" | state | ledger P4 sentence | +| L-29 | precedents | "Claims about other chains are from memory until cited ... marked approximate" | claim | | +| L-30 | precedents | pull quote "GPU mining lost its largest home in 2022 ..." | claim | | +| L-31 | problem | "Ethereum left proof of work in 2022"; "Chips arrived, as on Kaspa, whose hash was designed to welcome them"; "Ergo, Ravencoin and Conflux ... fraction of the 2022 fleet (approximate)" | claims | ledger C3, C8 sentences; MATCH | +| L-32 | problem | "those proofs come from a few private GPU clusters" | claim | | +| L-33 | problem | "Ethereum Classic, Bitcoin Gold and Vertcoin were all hit this way" | claim | asic history rows 6, 7 | +| L-34 | problem | "a supplier whose marginal cost is close to power"; "earned over a month of public mining, not rented for an hour" | claims | ledger P6 sentence | +| L-35 | glance | five-layer figure (program hourly; one block a second; included in about a second; Solidity unchanged; shards within about a minute, paid from gas; checkpoint every 30 s, 30-day history; "Fresh rented hashrate has no vote") | numbers | spec 03; MATCH as design | +| L-36 | glance | "Live on the devnet, 5 October 2026"; "run since 3 October 2026 on several machines, cards from all three GPU vendors" | dates | devnet v0 3 Oct, live v4 chain 4 Oct; APPROX | +| L-37 | glance | Mining lottery row, "4 Oct 2026, first live swap" | date | MATCH | +| L-38 | glance | Blocks row "About one a second with the full fleet; 0.65 a second over the hour to 16:00 UTC on 6 Oct 2026 with one PC off (2,325 blocks)" | numbers | not in docs; API now 0.98/s; UNSOURCED and STALE | +| L-39 | glance | Difficulty "Rule v2, a 600-second reference window, switched on by height; DAA 33,000, 4 Oct 2026" | numbers | spec 02 58; bench-log 1041; MATCH | +| L-40 | glance | Finality row: 30 s, two thirds, checkpoint 242, 77.4%, 17 vote keys | numbers | MATCH | +| L-41 | glance | Proving row: v0 active, DAA 84,100, 5 Oct 2026 | number, date | MATCH | +| L-42 | glance | Ember "version 0.3.13 (6 Oct 2026); the app window still says Igneum Miner" | number, date | release-0.3.13.md; MATCH; contradicts I-49 | +| L-43 | glance | Wallet "Igneum Wallet 0.1.1 on macOS, 5 Oct 2026" | number | downloads.json 0.1.4; STALE | +| L-44 | glance | Measured line: three log entries; "the 0.3.6 release plan"; "evidence table, row 7" | claim | | +| L-45 | glance | "0.3.6 ships the verifier with the app"; "two outside laptops. Nothing here has been reproduced by anyone outside the project yet" | claims | verifier Off on the observer's node today; STALE; laptops bench-log 905, 1061 MATCH | +| L-46 | mining | "Every GPU chain that promised ASIC resistance shipped a fixed algorithm" | claim | | +| L-47 | mining | "seed from a locked checkpoint one epoch back ... ten-minute verifiable delay"; "32 lanes of a warp"; "multi-gigabyte dataset that changes daily" | numbers | bench-log 150; spec 01; MATCH | +| L-48 | mining | "Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes" | number | bench-log 80; ledger M10 sentence; MATCH | +| L-49 | mining | "memory footprint and instruction count are fixed and only the maths sequence is random" | claim | | +| L-50 | mining | "checks a hash on an ordinary CPU in under ten milliseconds by simulating one warp" | number | spec 01 gate | +| L-51 | mining | "Measured: 0.61 ms per warp ... class v2 and 2.1 ms for class v3 (mixer x8, 5 October 2026, load average 5.5, worst cold unit 2.15 ms), 3.4x; the 10 ms gate leaves 4.8x; a 2019-class laptop core is not yet measured" | numbers | spec 01 399 (v2 0.631); chip-model-v3 26 gives 2.79 ms at load 5.6; APPROX, two measurements disagree; ledger M9 quotes the older 0.41 to 0.58 | +| L-52 | mining | "The hash is a lottery, not a general-purpose cryptographic hash ... Open: no analysis of the lottery properties exists yet." | claim, state | ledger M7 sentences | +| L-53 | mining | clock table: 128 dataset addresses per nonce; hour; day; six months from a genesis reserve; "Ethereum's growing dataset ran Bitmain's E3 out of memory in 2020, approximate" | numbers | spec 01 1.4; asic history row 3; MATCH, APPROX | +| L-54 | mining | "Three ideas ... A 90% miner signal turns one on. No fork." | number | spec 05 81; MATCH | +| L-55 | mining | "No hash has stayed free of chips forever. Igneum does not claim to."; "the response takes a week"; /bench#counter-asic-2-0-the-numbers; "Monero ... since 2019 with no chip publicly shipped, approximate; that is precedent, not proof" | claims, link | ledger C2 (wording "Monero is precedent, not proof" differs) | +| L-56 | mining | "anyone could publish a new generator and miners would switch it on by signalling" | claim | | +| L-57 | randomx | "RandomX has kept chips off Monero since 2019" | date | asic row 16 | +| L-58 | randomx | "Bit-exact on Apple, NVIDIA and AMD, measured" | claim | evidence row 19; MATCH | +| L-59 | randomx | "Per hour, compiled to native GPU code. Per hash, the 128 dataset addresses change" | numbers | MATCH | +| L-60 | randomx | "About 2 GB, the same size since 2019, approximate" / "2 GB, growing ... doubling at years 4, 12 and 28; a 4 GB card mines about four years, an 8 GB card about twelve, approximate" | numbers | evidence row 31; APPROX | +| L-61 | randomx | "256 MB cache on a CPU (512 MB from year 4), one warp under 10 ms. Measured 2.1 ms (3.4x class v2's 0.61 ms); a 2019-class core not yet" | numbers | spec 01 210; see L-51 | +| L-62 | randomx | "unchanged for seven years" / "Nobody touches it"; "Closed by a verifiable delay" | claims | | +| L-63 | randomx | "Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md)" | numbers, path | file missing in worktree; UNSOURCED; path on a user surface | +| L-64 | randomx | "No chip publicly shipped in seven years, approximate" / "public now (github.com/igneum-network/spec). The node, the miner and the wallet are in a private repository until the public testnet" | claim, link | ledger X1 sentence; MATCH | +| L-65 | randomx | "192 of 192 across two programs"; "228 million ... 45 million"; "prototype figures, not mining rates" | numbers | bench-log 74-100; MATCH | +| L-66 | randomx | "111x faster ... The 256 MB cache construction replaced it on 3 October 2026 ... computing items on the fly runs 4.8x slower than loading them"; "Open: the same shortcut ratio on NVIDIA and on a discrete AMD card" | numbers, state | bench-log 115, 138; ledger M2 sentence; MATCH | +| L-67 | randomx | "Inside the 5090's 96 MB cache the same program ran nearly six times faster" | number | ledger M1 (5.8x); MATCH | +| L-68 | randomx | "On 4 October 2026 ... a Mac at 26.7 million, an RTX 5090 at 123 million, an integrated AMD chip at 2.7 million, every hash doing 128 distinct reads" | numbers | bench-log 644; MATCH | +| L-69 | proving | "a phone checks it in milliseconds; the wrapping cost is a phase two measurement" | claim | ledger P3 sentence | +| L-70 | proving | "one BLS aggregate signature over 16 keys and 21 header hashes, 139 to 155 ms cold and 58 to 68 ms warm in a phone-sized tab on a laptop core (5 October 2026). No phone has been measured, and no wrapped block proof exists yet" | numbers | ledger P3 328; MATCH | +| L-71 | proving | "assigned by lot to eight provers for ten seconds, then open to anyone; there is no bond"; "within about a minute at launch"; native-execution check (spec section 7); "the way Kaspa skips conflicting spends" | numbers, state | spec 07; ledger P13; MATCH | +| L-72 | proving | "Measured on eleven rented cards ... RTX 3060 (12 GB) 23.78 MH/s ... 8.9 GB peak in 37.5 s; RTX 4060 (8 GB) 7.4 GB in 18.4 s; RTX 4090 (24 GB) 5.6 s at 17.4 GB. The patched server ... is not yet in the shipped app" | numbers, path | file missing; none of the seven numbers in bench-log; UNSOURCED | +| L-73 | proving | "Measured on 5 October 2026 (RTX 5090, SP1 6.8.1, 30,000 proving gas, about 4.7 million prover cycles): one full shard proves in 4.3 seconds and needs 20.4 GB; floor 13.9 GB; 32 GB today (30.1 GB) and 24 GB once the adopted shard size is live (22.2 GB beside the miner, 13.2 seconds a shard)" | numbers | bench-log 1994; proving-v1.md; evidence row 16; MATCH (4.2 vs 4.3 rounding) | +| L-74 | proving | "old 12 GB gate withdrawn on 5 October; on 6 October a patched server proved the same shard at 7.4 to 8.0 GB alone on eleven rented cards" | numbers | morning 107 only; UNSOURCED (file missing) | +| L-75 | proving | "4 October 2026: RTX 5090 proved a small two-transaction block in 1.4 seconds (2.7 compressed), verified in 0.22 and 0.038 seconds; a laptop CPU proved a three-shard block end to end in 19 minutes" | numbers | bench-log 590; evidence row 15; MATCH | +| L-76 | proving | "6.75 million prover gas ... 60.8 million cycles: core proof 8.3 s, compressed 10.9 s, verified in 0.040 s; a four-shard block 44.5 s" | numbers | bench-log 857; MATCH | +| L-77 | proving | "Since 5 October 2026 shards are assigned and proven on the live devnet"; "the gate stands open"; "hash-based ... versioned interface" | state | MATCH | +| L-78 | proving | "The job market is permissionless and is Designed, not yet built"; "10% of each fee burned ... phase two"; "Boundless provers post ZKC and Succinct provers stake PROVE (approximate)"; "We know of no other proof-of-work chain selling proofs to other chains" | state, claims | spec 05 48; ledger C10 sentence; MATCH | +| L-79 | finality | GHOSTDAG, Kaspa since 2021 (approximate), rusty-kaspa; four and ten (approximate); one second vs Ethereum's twelve; two minutes vs thirteen (approximate); "Inclusion is not confirmation on either chain"; "paid at that rate, red or blue" | numbers | ledger C3, C5 sentences; node 2.1.0; MATCH | +| L-80 | finality | "Every 30 seconds of chain a checkpoint forms"; "at least 100 blocks in the last 30 days"; "two thirds of all the mining weight"; "In the chain's first 30 days no checkpoint locks at all (Implemented, the first-month gate, measured 4 and 5 October 2026)"; "12-hour finality depth"; "window two hours, first lock two hours after genesis at 77.4% from 17 vote keys (4 October 2026)" | numbers, dates | spec 03; spec 02 16; /api/live weightWindow 7200; ledger F1 sentence; MATCH | +| L-81 | finality | pull "The word sustained is the whole defence ... The right to lock history is earned." | claim | | +| L-82 | finality | "ten days ... a third ... twenty to hold two thirds. An attacker matching the honest network needs twenty days for a third and never reaches two thirds"; "same limit Bitcoin lives with, with a month's warning"; "Pools carry their hashers' votes, so vote concentration equals pool concentration, and it is public" | numbers | spec 03 25; ledger F5, F10 sentences; MATCH (model) | +| L-83 | finality | "finality pauses ... up to 30 days"; "reported as absent within two hours"; "forked more than 12 hours of median time back"; "Kaspa's one-hour merge depth"; "strips the key of its vote for 30 days" | numbers | spec 03 Q1; MATCH | +| L-84 | finality | "No stake. No coin-holder class votes ... No anchoring into Bitcoin or any other chain." | claim | CLAUDE.md decisions; MATCH | +| L-85 | building | "Anything that runs on Ethereum runs on Igneum unchanged ... a different chain id"; "one-second inclusion, finality in about two minutes" | claim | ledger overclaim 35 asks the bytecode wording; not applied | +| L-86 | building | three things no other EVM chain offers: proving primitive; light clients (consensus proof phase two); rollups settle here | claims | ledger C11 sentence | +| L-87 | building | "The first apps, a DEX and a lending market, ship at genesis"; "No bridge is official" | claim | | +| L-88 | building | "Not for speed ... Three things no L2 can offer. Keep your Ethereum deployment." | claim | copy law | +| L-89 | building | "base fee that rises with the backlog, published at the phase 4 job market" | claim | | +| L-90 | building | "20% of every priority fee ... per call frame"; "a million 100,000-gas calls a day at a 1 gwei tip pays about 7,300 IGN a year, 1 gwei as a billionth of an IGN (the base unit is Open)" | numbers | ledger P14 sentence; MATCH | +| L-91 | building | "a proof Ethereum verifies for about 250,000 gas. Igneum reads Ethereum's finality trustlessly from launch. Ethereum reads Igneum trustlessly in phase two" | number | no source; UNSOURCED | +| L-92 | building | "No stablecoin and no official bridge at genesis. Grants come from founders' mined coins"; "miner lock in about two minutes" | claims | | +| L-93 | economics | "part of every payment on Igneum is burned"; "10% burn ... phase two" | number | ledger P10 sentence | +| L-94 | economics | "Hard cap of 4 billion ... 1 billion a year, halves every two years for ever. Nearly a quarter in the first year and half in the first two. Ramps 10% to 100% over 30 days" | numbers | spec 02 118-122; /api/supply; ledger L2 sentence; MATCH | +| L-95 | economics | chart "Half of the 4 billion cap is mined in the first two years"; bars 1000 ... 31; caption "3,938M IGN in the first 12 years" | numbers | /api/supply year 12 = 3,900.5M with the ramp; ledger overclaim 76 on the caption; STALE/APPROX | +| L-96 | economics | 80% miner; 20% pool "unspendable script tagged igneum-proving-pool-v0, burned (Implemented, proving v0, since 5 October 2026). Open: the single coinbase payout that replaces the burn"; 0% treasury | numbers, state | evidence rows 20, 21; MATCH | +| L-97 | economics | base fee burned (Ethereum's rule); 80/20; 90/10 | numbers | spec 05; MATCH | +| L-98 | economics | routes 1 to 6; route 6 "1 block template in 100 ... off with one flag; Implemented, measured 4 October 2026"; rows 4, 5 Designed | numbers | bench-log dev fee; MATCH | +| L-99 | economics | "Sources: specification sections 2.5 and 5.1 to 5.4" | claim | | +| L-100 | economics | "no tail emission. The schedule is a bet, not a measurement"; Kaspa's reduction (approximate); "about 3,000 consumer cards"; "300 W card at 124 MH/s on USD 0.12 per kWh"; "under one fifth of the block subsidy over any 90-day window after year 5" | numbers | security-budget.md 54-61; ledger E6 sentence; MATCH | +| L-101 | economics | USD 0.005 to year 7, USD 500,000; USD 0.02 to year 11; USD 0.10 none in 14 years, USD 1,250,000 | numbers | security-budget.md 101; MATCH | +| L-102 | economics | "No fund, no foundation, no fee to the team"; the full list; "1 block in 100 pays the project" | claim | ledger E5 sentences; MATCH | +| L-103 | miners | streams table; "No, but the market is small today and is upside, not a promise" | claims | | +| L-104 | miners | "4 October 2026, three machines at 275 million hashes a second, a second of hashing paid about 4.9x a second of proving; at 10,000 cards ... about 930x, approximate" | numbers | ledger X14 arithmetic; bench-log 790; APPROX | +| L-105 | miners | "half a gigabyte a year"; 4 GB four years, 8 GB twelve, approximate; the 8 GB proves sentence (path); "Macs mine too, at about a fifth of a flagship card: Measured, 26.7 against 123 million, 4 October 2026"; "no CPU mining lane ... botnets" | numbers | ledger M13 sentence MATCH; path row UNSOURCED | +| L-106 | miners | "switches the card to proving for a few seconds"; "1% dev fee ... by a counter, not a random draw, exactly 1 in 100"; "--dev-fee 0" | numbers | MATCH | +| L-107 | miners | "Implemented, Ember 0.3.9 (5 October 2026): chain label reads devnet v4 ... NVIDIA capped at 80% of default power limit ... not yet measured on a card; no earnings in IGN or any currency; no hardware-wallet path. Roadmap, Designed"; "browser mining has meant malware since Coinhive" | claims | release-0.3.9.md; MATCH | +| L-108 | miners | "Launch date and miner software published a month ahead. Pools live on testnet. HiveOS support on day one. The founders mine from genesis ... disclosed addresses"; "first 30 days ... 12-hour depth" | claims | ledger F1 second sentence | +| L-109 | ember | "runs the node, mines the hourly program, proves shards and keeps your key, on Windows, macOS and Linux"; "since 4 October 2026"; "six levers set on 4 October 2026" | dates | "six levers" has no document; UNSOURCED | +| L-110 | ember | features: one click; CUDA/OpenCL/Metal; key shown once; proving switch; "8 on a large card and 2 on a small one"; manifest hourly, 3 minutes, one minute of the hour, rollback; signed remote jobs; watchdog 90 s / 60 s; dashboard token | claims, numbers | h-config.sh 11; bench-log 1214; MATCH; "3 minutes" UNSOURCED | +| L-111 | ember | Source: app/igneum-app/src, packaging/hive; "Design, not yet measured on a real card: the watchdog rules and the fault guards ... fake worker only (4 October 2026)" | state | paths on a user surface | +| L-112 | ember | lever 1: "up to 17 variants ... 2 s"; "Shipped in the Metal and CUDA workers"; "+17.3% ... +21.2%, Apple M5 Max, 14 variants, ratios only. The RTX 5090 race is built and not yet run" | numbers | bench-log 1122, 1130 (14 variants); "up to 17" UNSOURCED | +| L-113 | ember | lever 2: "Shipped. The fleet is small, so no table yet" | state | | +| L-114 | ember | lever 3: "100% to 50% in 10% steps, 60 s"; "AMD and Apple: not supported"; "The first sweep on a card is pending. The RTX 5090 drew 290 W at p95 under a 460 W cap" | numbers | miner-eff.md, ember-tune.md; MATCH | +| L-115 | ember | lever 4: "Target under 50 ms"; "In 0.3.6"; "p50 46 to 52 ms, p90 118 to 130 ms, 3-node fast-time network, CPU miners, 0 rejected" | numbers | release-0.3.6.md; MATCH; "In 0.3.6" STALE | +| L-116 | ember | lever 5: swap 0.01 / 0.00 ms; fake-worker guards trip 0.0 s, back in 2.0 s, silent worker restarted at 60 s | numbers | bench-log 644, 1199; MATCH | +| L-117 | ember | lever 6: "Live"; /miners | state, link | | +| L-118 | ember | "Levers 2 and 3 are shipped code with no fleet measurement yet" | state | | +| L-119 | ember | "1% software dev fee ... exactly 1 in 100"; "--dev-fee 0", "DEV_FEE=0"; "9 fee blocks in 785, 0 from the control" | numbers | bench-log 1226, 1252; MATCH | +| L-120 | ember | "What Ember does not claim": the race gain on NVIDIA; a measured sweep; HiveOS on a rig; a signed binary (four sentences, kept verbatim) | claims | kept | +| L-121 | wallet | "desktop wallet, macOS first ... checks finality with the node's own code" | claim | | +| L-122 | wallet | 24 words on the Ethereum path; XChaCha20-Poly1305, Argon2id (64 MiB, 3 passes); fee shown; local QR; history; BLS verified itself; MetaMask export; own node; signed OTA with rollback; "Touch ID and Windows Hello: In progress, not live. Windows build: next" | claims, numbers | app/igneum-wallet not in tree; UNSOURCED here | +| L-123 | wallet | "Igneum Wallet 0.1.1, 5 October 2026 (app/igneum-wallet). Verified: the over-the-air path end to end on one Mac. Not yet run: the Windows path, the rollback paths, a Developer ID signature" | number, date | downloads 0.1.4; STALE; path on a user surface | +| L-124 | governance | "top three vote keys held 34.5% of 8,090 blocks on 4 October 2026, measured" | number | difficulty-2026-10-04-oscillation.md; bench-log 790; MATCH | +| L-125 | governance | "at least three months ahead and activates only when 90% of blocks signal"; "60% of hashrate over two weeks" | numbers | spec 05 56, 81-83; MATCH | +| L-126 | governance | "Stratum v2 job declaration from day one ... Designed: spec section 9"; "no admin keys in consensus ... Designed, open item O-5.4. On the devnet the activation heights and one execution-state restart (6 October 2026) reach every node through the signed update manifest, so the release key acts as the operator"; "A second independent node client is the first priority after launch" | claims, date | ledger G4, G6 sentences; morning 103; MATCH | +| L-127 | roadmap | "Thirteen months ... four public gates"; "the combination is the risk the gates price" | number | ledger C6 sentence | +| L-128 | roadmap | six phases; phase 2 "So far: an RTX 5090 proves a shard in 10.9 s compressed; a CPU verifies a warp in 0.41 to 0.58 ms. A mid-range card has not been measured", gate "under 20 s ... 10 ms"; phase 3 "Live now: 1 block a second, difficulty v2, finality v2 locks, proving v0, Ember on every machine. Not yet measured on the live chain: the proof lag behind the tip", gate "proofs under 60 s behind the tip"; phase 5 gate "1,000 independent miners run 30 days"; phase 6 "No listing is arranged, promised or sought by the project" | dates, numbers | 0.41 to 0.58 is the retired v1 figure (spec 01 399): STALE; proof lag is measured (387 s): STALE; ledger X8 sentence present | +| L-129 | roadmap | "Dates slip. Gates do not. Phase two decides everything." | claim | ledger C6 sentence | +| L-130 | roadmap | "What ships next: Ember 0.3.6"; "none is on the fleet yet" | state, date | fleet on 0.3.13; STALE | +| L-131 | roadmap | items: verifier; Windows prover host (20-minute setup); tile shows verifier state; p50 46 to 52 ms; instant jobs "3 to 6 s expected, not yet measured"; testnet parameters adopted 5 October 2026 | numbers | release-0.3.6.md; STALE as "next" | +| L-132 | roadmap | "Source: the 0.3.6 release plan ... instant-jobs latency is an estimate" | claim | | +| L-133 | miners ask | "Kaspa was GPU-mined too, and IceRiver shipped a chip within two years."; "The benchmark tool ships in January 2027"; "more than 2x" | date, number | ledger M1; MATCH | +| L-134 | miners ask | "A renter with 60% of the network holds 0.0% of the vote on day one (the finality simulator, table B); a third on day 20 and never two thirds"; "median 1,018 ms behind the checkpoint"; "deepest honest reorganisation measured was 2, 3 and 7 blocks against a determination depth of 20 (ledger F7, round 2)"; "p50 343 ms and p99 666 ms (12-node cloud network, 4 October 2026)" | numbers | ledger F8; bench-log 433, 936 MATCH; "2, 3 and 7" not in the ledger: UNSOURCED | +| L-135 | miners ask | "IceRiver KS0 July 2023, 17 to 20 months; under 100 PH/s to over 700 PH/s (row 23, approximate)"; "Bitcoin's hash from two manufacturers (approximate)"; "85% of the hashrate vanished at the April 2018 fork ... over 85% again four months after the next fork (row 16)" | numbers | asic history rows 23, 16; MATCH | +| L-136 | miners ask | ETC (January 2019, August 2020), BTG (May 2018, January 2020), Vertcoin (October to December 2018, December 2019) (rows 6, 7; ETC approximate); Verge 2018 (approximate); "first 30 days ... 12-hour depth" | dates | asic history; MATCH | +| L-137 | miners ask | "Rented NVIDIA hash, 6 October 2026: 2 GH/s for USD 13 an hour; the entry lands tonight" | number | placeholder; morning 107 says USD 9 for the 11-card phase; UNSOURCED | +| L-138 | miners ask | "The devnet's hash the same afternoon: 282 MH/s; /api/stats, 6 October 2026, 16:40 UTC; 181 MH/s an hour earlier" | numbers | API now 2.66 GH/s; UNSOURCED and STALE | +| L-139 | miners ask | "0.0% (ledger M12)"; "1,018 ms median"; "A 50-miner wave against the devnet: measurement tonight" | numbers | placeholder cell; UNSOURCED | +| L-140 | miners ask | "The specification is public; reviewers will be named and paid before gate 3" | claim | ledger G1 sentence | +| L-141 | miners ask | "One founder, pseudonymous, working with AI systems ... the commit history says so"; DIFC address; "ledger is published with the repository at the public testnet"; "No cryptographer is hired yet"; "there is no team page" | claims | ledger G2, G3 sentences; /ledger is already published (the sentence is STALE) | +| L-142 | miners ask | "benchmark January 2027. Pools and the public testnet are August 2027"; #ember | dates, link | MATCH | +| L-143 | miners ask | "marginal cost close to power ... an edge over data-centre provers and nothing more" | claim | ledger P6 | +| L-144 | builders ask | "Proof of work, in 2027?"; "executes in about a second. A miner lock arrives in about two minutes" | numbers | MATCH as design | +| L-145 | builders ask | "The project will ask Circle for native USDC during the public testnet"; "DEX seeded at launch by the founders' own mined coins and by miners" | claims | | +| L-146 | builders ask | "20% of the priority fee ... small and stated as such above"; "wallet's Apps tab and the explorer from day one"; "Point Hardhat or Foundry ... The afternoon is the hard part." | claims | ledger overclaim 42 asks to delete the last sentence; not applied | +| L-147 | shoulders | "decided on 3 October 2026"; rusty-kaspa (ISC) v2.1.0; RandomX (BSD); ProgPoW/KAWPOW (approximate); LWMA; chiavdf (Apache 2.0); revm (MIT); SP1 (MIT or Apache 2.0); blst (Apache 2.0); bech32/CashAddr; BLAKE2b, BLAKE3, SHA-256, Keccak, ChaCha, SplitMix64, FNV-1a | claims | node_version 2.1.0; MATCH | +| L-148 | shoulders | "docs/provenance.md ... published at the public testnet. Licences stated from memory are marked approximate" | claim, path | path on a user surface | +| L-149 | limits | nine "does not claim" items (verbatim list below); numbers 100 to 200 GPUs; 0.92x with 3x allowance; under 1x; 1.2x; 5x to 9x; 2.1x to 4.8x; about 2x; 5.6x to 2.1x; 4.8x slower (3 October 2026); 12-hour depth; ten and twenty days; partition both sides (4 October 2026); up to 30 days | numbers | ledger P2 (100 to 200, approximate); chip-model-v3 69; evidence row 10; MATCH, APPROX | +| L-150 | limits | "subject to the gates"; "Nothing in it is an offer to sell anything"; mailto; spec issues; DIFC address | links | ledger X7 | +| L-151 | footer, pager | footer (24 rows) and the previous/next pager | links, feature | | + +"What Igneum does not claim" (kept verbatim in the build, every word): +1. "A proof in seconds. Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second." +2. "A chip is impossible. No. A chip is a bad bet, because the target moves before it ships." (then the model paragraph, ending "and that price is a cost model, not a measurement.") +3. "A guaranteed income floor. No. External proving is a small market today. Igneum's miners' marginal cost in it is close to power, which is an edge and nothing more." +4. "A memory-hard prototype on every vendor. Not yet. The 256 MB cache closed the shortcut on Apple silicon (computing items runs 4.8x slower than loading them, measured 3 October 2026). The same ratio on NVIDIA and on a discrete AMD card is Open." +5. "Finality in the first month. No. No checkpoint locks until the 30-day window has 30 days of history. The first month of mainnet is proof of work with a 12-hour depth, and the text above says so wherever a day count appears." +6. "A cryptography team. Not yet. One founder working with AI systems wrote the design and the code; external reviewers are named and paid before gate 3, and every security claim here is a design claim until then." +7. "Finality that no amount of hardware can break. No. A miner holding a third of the last 30 days of blocks can split finality during a network partition, and two thirds can lock a bad checkpoint for a double-spend bounded by the 12-hour finality depth. ..." (ends "(measured on a test network, 4 October 2026).") +8. "Finality that never pauses. No. A lock needs two thirds of all 30-day mining weight. Whenever less than two thirds of that weight is connected and signing, finality pauses until it returns or ages out of the window, up to 30 days. The chain keeps running on proof of work and the node reports the pause." +9. "A finished protocol. The sustained-mining finality rule is the newest piece and the one that external review will try hardest to break. The specification, the review and the benchmarks are published as they happen." + +"What Ember does not claim" (kept verbatim): the race gain on NVIDIA ("Unknown until the RTX 5090 job runs ..."); a measured sweep ("has not yet run on a card"); HiveOS on a rig ("self-tested with stub binaries ..."); a signed binary ("Releases are signed by the project's release key ... the first install asks you to allow the app"). + +Ledger sentences on the litepaper: present verbatim for M2, M4, M7, M10 (the Measured sentence), M13, F1, F5, F10, P3, P4, P6, P7, P10, P14, E5, E6, G1, G2, G3, G4, G6, C3, C5, C6, C8, C10, C11, L2, X1, X7, X8. Differ or absent: M9 (page now says 0.61 and 2.1 ms; the ledger's 0.41 to 0.58 survives only in the roadmap), P1 (the "Target: 12 GB card proves one shard in about 20 seconds" sentence is gone; the page says the gate was withdrawn), C2 second half ("that is precedent, not proof" for "Monero is precedent, not proof"). Overclaims not yet applied: 35, 42, 51, 68, 74, 76. The ledger's own count table lists 32 rows as "not yet stated" that the page carries: the ledger's table is stale, not the page. + +## Nav (site/partials/nav.html) + +| id | text | kind | note | +|---|---|---|---| +| P-nav-1 | "Skip to content" | feature | #main on every page | +| P-nav-2 | IGNEUM mark | link | / | +| P-nav-3 | Menu button | feature | under 941 px; closes on link, outside tap, Escape, resize | +| P-nav-4 to 9 | Litepaper, Live devnet, Engineering log, Miner, Wallet, Evidence | links | data-nav marks the current page; Live devnet also current on /explorer, /block, /address; Miner also on /miners | +| P-nav-10 | GitHub | link | spec repo, 200 | +| P-nav-11 | "The miner" CTA | link | /miner | + +No nav entry for /explorer, /ledger, /faucet, /miners, /metamask (footer only). + +## Footer (site/partials/footer.html) + +| id | text | kind | note | +|---|---|---|---| +| P-foot-1 | tagline | claim | | +| P-foot-2 to 8 | Read: Litepaper, What Igneum does not claim (/litepaper#limits), Igneum vs RandomX (#randomx), Built on the shoulders (#shoulders), Engineering log, Evidence, Ledger: every criticism | links | anchors exist | +| P-foot-9 to 13 | Run: The miner, The wallet, GPU bench table (/miners), The dev fee (/miner#fee), Testnet faucet | links | | +| P-foot-14 to 21 | Follow: Live devnet, Explorer, Journey (/#journey), Add Igneum to MetaMask (/wallet, no anchor), GitHub spec and vectors, Miner downloads: public testnet (/miner#get; label contradicts the not-open notice), Report a flaw mailto, spec issues | links | | +| P-foot-22 | "Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network" | claim | fud-ledger.md 154; MATCH | +| P-foot-23 | "© 2026 Igneum. Nothing on this page is an offer to sell anything." | claim | | +| P-foot-24 | "igneum.network" | text | | + +## Live (site/live.html) + +| id | text | kind | element, API field, states, verdict | +|---|---|---|---| +| P-live-1 | "read from a node every two seconds" | claim | poll 2,000 ms; MATCH | +| P-live-2 | "devnet v0" eyebrow | state | live chain is v4 since 4 Oct; STALE | +| P-live-3 | "Live devnet" | h1 | | +| P-live-4 | "A node is read every two seconds. Every block below is real ... A checkpoint locks when the finality rule's quorum signs it. Once the proving layer is activated, every chain block's shards show as they are planned, proven and paid." | claim | | +| P-live-5 | "Fees: the devnet meters with its prototype table until DAA score 210,000; from there the adopted table applies (300 pgas per transaction, 30,000-pgas shards, floors of 100 gwei per gas and 10,000 gwei per pgas) and the provers' program carries both." | number | fee-switch-devnet.md 3-4, 40, 52; MATCH, turns stale the moment DAA 210,000 passes (tonight) | +| P-live-6 | Status cell | API | #st-status OFFLINE/LIVE; #st-age "no observer update yet", "observer updated N ago", "observer N s behind, N queued", "api unreachable" after 3 failures | +| P-live-7 | Network | API | state.network or "igneum-devnet"; "node " | +| P-live-8 | Blocks / s over 60 s | API | blocks_per_second_60s | +| P-live-9 | Blue score, blocks | API | blue_score, block_count | +| P-live-10 | Difficulty | API | difficulty | +| P-live-11 | Hash rate | API | hashes_per_second_estimate; "n/a" when null | +| P-live-12 | Identities "vote keys active in 10 min, a card runs several" | API | miners_10m; h-config.sh 11; MATCH | +| P-live-13 | Peers, mempool | API | peers, mempool | +| P-live-14 | strip stats: on screen, chain, identities, last lock, proven | API | c-locked "none", "#N, N ago", "none yet", "n/a"; c-proven "pending", "A/B in 10 min" (item 0), "not active", "no proving layer" | +| P-live-15 | DAG canvas | feature | hover, tap pins, Escape, ?window=30..300, ?perf=1; canvas words listed in the audit's state table | +| P-live-16 | legend blocks: chain, included paid, pending, excluded, just arrived, selected chain, one lane per miner | feature | | +| P-live-17 | legend finality: final, locked, proposed, "reads paused whenever under two thirds of the weight is signing" | claim | spec floor; MATCH | +| P-live-18 | legend proving: planned, proving, verified, paid, where proofs land | feature | | +| P-live-19 | Miners table (last 10 min): Miner, Blocks, Share, Last seen, Engine | API | d.miners; empty "No blocks in the last 10 minutes."; "not reported" | +| P-live-20 | "The short id is the first 8 hex characters of the vote key hash ... the devnet miner writes nothing yet." | claim | api/explorer.mjs 21; MATCH | +| P-live-21 | Events newest first | API | d.events; empty "No events yet." | +| P-live-22 | Blocks per minute chart and note | API | blocks_per_minute; "no data yet" | + +## Miners (site/miners.html, generated by build.mjs from miner-bench.json and miner-priors.json) + +| id | text | kind | verdict | +|---|---|---|---| +| P-miners-1 | "3 entries, newest at the bottom" | number | the bench template's words; wrong for this page | +| P-miners-2 | "GPU bench table" | h1 | | +| P-miners-3 | note "Measured hash rates per card ..." | claim | | +| P-miners-4 | contents: The table, How a row gets here, Fleet tuning priors | feature | | +| P-miners-5 | "Integrated GPUs are not listed. Prototype rows say so in the miner column." | claim | | +| P-miners-6 | Apple M5 Max v1 45.2 MH/s, 2026-10-03 | number | evidence row 3; MATCH | +| P-miners-7 | Apple M5 Max v2 26.7, 2026-10-04 | number | bench-log 642; MATCH | +| P-miners-8 | Apple silicon laptop v2 24.3, 21.0 average over 7 min, 33 blocks | number | bench-log 911; MATCH | +| P-miners-9 | RTX 5090 v1 229, 2026-10-03 | number | evidence row 3; MATCH | +| P-miners-10 | RTX 5090 v1 185.3 | number | bench-log 98; MATCH | +| P-miners-11 | RTX 5090 v2 124.2, 2026-10-04 | number | evidence rows 4, 30; MATCH | +| P-miners-12 | "MH per watt: not measured" on all rows | state | ledger E17 has the 5090 at 326.6 W (0.40 Mhash/J); eleven rented cards with watts on gpu-fleet; STALE | +| P-miners-13 | "The app reads it on NVIDIA cards through the driver." | claim | | +| P-miners-14 | "There is no other Igneum miner to compare with yet" | claim | | +| P-miners-15 | "Rows: 6. Source file: site/miner-bench.json in the repository." | dev text | | +| P-miners-16 | priors: "within 1% of its top rate", "A model needs 5 reports" | number | ember-tune.md; miner-priors.json; MATCH | +| P-miners-17 | "No tune reports yet. The first rows appear once five machines with the same card model have reported." | empty state | | +| P-miners-18 | "Rows: 0. Source file: site/miner-priors.json, written from the fleet records by tools/tuning.mjs --priors --site." | dev text | | +| P-miners-19 | "Generated from the repository at build time. Times are UTC. Machine names are model names." | claim | | + +## Miner (site/miner.html; copy owned by the site-miner agent today) + +| id | text | kind | verdict | +|---|---|---|---| +| P-miner-1 | meta "every NVIDIA card from 8 GB proves ... a visible 1% software fee" | claim | see P-miner-12 | +| P-miner-2 | "Igneum Ember · one click" | eyebrow | | +| P-miner-3 | h1 "Install. Start. The card mines. Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove." | claim | 96 characters | +| P-miner-4 | lead: finds your GPU, makes a wallet, compiles the next program while the current one mines | claim | | +| P-miner-5, 6 | "Downloads: public testnet" #get; "Every feature" #features | links | | +| P-miner-7 | Windows, macOS, Linux, HiveOS, "NVIDIA · AMD · Apple silicon" | claim | | +| P-miner-8 | screenshot caption "the app is still labelled Igneum Miner until 0.3.6 ... 5 Oct 2026" | date | STALE (0.3.13 still says Igneum Miner) | +| P-miner-9 | "Hash, prove, get paid": 80% of each block to the finder; PROVE; GET PAID | claim, number | /api/stats split; MATCH | +| P-miner-10 | "Every feature, one line each"; "Each number links to its engineering log entry." | claim | not true for P-miner-12, 27, 45 | +| P-miner-11 | "Five steps: drag to Applications, open, Get started, Make me an address, Start mining." | claim | bench-log 908 (Open Anyway step); APPROX | +| P-miner-12 | "every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, 6 October 2026, docs/analysis/prover-tiers-real-cards.md); the patched server is not yet in the shipped app." | claim, path | file missing; no bench-log entry; contradicts /evidence row 16; UNSOURCED | +| P-miner-13 | "Finds your GPU by itself ... NVIDIA through the driver, AMD and Intel through OpenCL, Apple silicon through Metal" | claim | | +| P-miner-14 to 17 | wallet made for you; earnings in IGN; three OSes; HiveOS package "Hive itself is untested" | claims | | +| P-miner-18 | "First outside machine ... 33 accepted blocks in 7 minutes, 0 rejected, 21.0 MH/s average" (log, 4 Oct) | number | bench-log 911; MATCH | +| P-miner-19 | "First card on the app ... 117 to 119 MH/s, 34 accepted blocks in the first minute" | number | bench-log 781; MATCH | +| P-miner-20 | h3 "Hashing and proving, switched by the client" | heading | 43 characters | +| P-miner-21 | "assigned, proving, submitted, paid" | claim | | +| P-miner-22 | "8 suits a big card, 2 a small one, 1 an integrated GPU" | number | h-config.sh 11 (8 from 8 GB else 2); "1" APPROX | +| P-miner-23 | "Hourly program, no pause" | claim | | +| P-miner-24 | swap table 4 Oct 2026: M5 Max 82 ms, 0.01 ms, 26.7/26.7, 0; RTX 5090 1,285 ms, 0.00 ms, 121.8/123.4, 0; AMD integrated no restart, 2.74/2.74, 0; "epoch boundary at DAA 3,600" | numbers | bench-log 636, 642-644; MATCH | +| P-miner-25 | h3 "Signed, over the air, at a safe moment" | heading | 38 characters | +| P-miner-26 | "Signed over the air ... Ed25519" | claim | | +| P-miner-27 | "Installed at a safe moment: node synced, no hourly boundary within 3 minutes, no worker starting ... never while the network lost over 30% of its identities in 10 minutes." | number | UNSOURCED | +| P-miner-28 | "Mining continues through an update ... fails to start twice, the previous one comes back" | claim | | +| P-miner-29 | "Urgent ... within 1,800 blocks or below the minimum supported" | number | difficulty-v2-rollout-devnet.md 42; MATCH | +| P-miner-30 | "The fleet tunes itself. Nothing here changes the hash." | claim | | +| P-miner-31 | "Variant racing every hour ... 2 seconds" | number | bench-log 1103; MATCH | +| P-miner-32 | "256-thread groups ran 17.3% and 21.2% faster ... The NVIDIA race has not yet run on a GPU." | number | bench-log 1130; MATCH | +| P-miner-33 | "Fleet tuning manifest" | claim | | +| P-miner-34 | "Ember Tune ... 60 seconds a step ... within 1% ... the first measured tune is owed." | number | ember-tune.md 42 (75 s per step); APPROX | +| P-miner-35 | "Latency work ... In progress, no number published yet." | claim | | +| P-miner-36 | "Remote signed jobs, opt in ... Our own fleet only" | claim | | +| P-miner-37 | h3 "Watchdog, restart, clock" | heading | | +| P-miner-38 | "Watchdog per card: no status line for 90 seconds, or a hash rate of 0 for 60 seconds" | number | bench-log 1214-1219; MATCH | +| P-miner-39 | "Watchdog per node: 120 seconds ... silent node to mining again in 160.0 s" | number | MATCH | +| P-miner-40 | "Restart in order" | claim | | +| P-miner-41 | "A clock 60 seconds slow kept a node silently dead for 12 minutes ... over 5 s a warning, over 10 s Start is blocked" | number | bench-log 780; evidence row 30 says 62 s; APPROX | +| P-miner-42 | recoveries table 4 Oct 2026: 91.0 s, 75.4 s to faulted, 101.4 s, 160.0 s; "a fake worker, no real GPU" | number | bench-log 1214-1219 (101.4 is a sum); MATCH | +| P-miner-43 | "The log and the bench table. Every number on this page has a row." | claim | not true, see above | +| P-miner-44 | Engineering log /bench; GPU bench table /miners; "Your rows, from your machine ... once a minute under a per-install id" | link, claim | | +| P-miner-45 | "Why Igneum Ember stays ahead. Six levers, set on 4 October 2026." | number, date | no document lists six; UNSOURCED | +| P-miner-46 | lever 1: "five to ten kernel variants ... two seconds each ... +17.3% ... +21.2%" | number | bench-log 1101 (no count); APPROX | +| P-miner-47 | lever 2: "Shipped. The fleet is still small, so no fleet table yet" /miners#priors | state, link | | +| P-miner-48 | lever 3: NVIDIA and AMD built, measured only on Apple | claim | | +| P-miner-49 | lever 4: "within 50 ms ... Approximate, from the 0.3.6 release plan: p50 46 to 52 ms, 5 Oct 2026. Ships in 0.3.6." | number | release-0.3.6.md 73; "Ships in 0.3.6" STALE | +| P-miner-50 | lever 5: swap 0.01 / 0.00 ms, 0 rejected | number | MATCH | +| P-miner-51 | lever 6: "Live at /miners" | link | | +| P-miner-52 | "The dev fee is the software's 1% ... The protocol carries no fee." #fee | claim | | +| P-miner-53 | "The fee, in full view; no dev fund, no fee to any team, foundation or fund" | claim | | +| P-miner-54 | "1% dev fee ... one block template in 100 ... Igneum Labs LTD ... a template counter, never a random draw" | number | MATCH | +| P-miner-55 | off table: Settings switch, --dev-fee 0, DEV_FEE=0 | feature | | +| P-miner-56 | "Measured on a test network, 4 Oct 2026: 9 fee blocks in 785 (1.146%); the control paid none" | number | bench-log 1226, 1252; MATCH | +| P-miner-57 | switch mock "Dev fee 1% (1 block in 100)" | feature | | +| P-miner-58 | start lines; "igneum-miner payouts lists blocks per payout address" | dev text | | +| P-miner-59 | "Get the miner. Download only from this domain. Nobody from Igneum will ask for your seed." | claim | | +| P-miner-60 | "Public testnet: not yet open; the devnet build is here for people who want to look." | state | ledger X2 | +| P-miner-61 | "Devnet: coins have no value and the chain may be reset." | claim | | +| P-miner-62 | Windows, macOS, Linux, HiveOS buttons "v0.3.13 · 45.4 / 41.9 / 24.6 / 24.6 MB" | number | host 0.3.14; STALE (repo copy) | +| P-miner-63 | Hive Flight Sheet: URL igneum-hive-0.3.13.tar.gz (404), miner igneum, wallet 0x<40 hex>.%WORKER_NAME%, pool grpc://:26610 or local, extra DEV_FEE=1 IDENTITIES=8 WORKER=auto VOTE=1, sha256 65ea4260... | number, dev text | URL 404, hash of a dead file; port 26610 fork-divergence.md 17 MATCH | +| P-miner-64 | "the faucet sends 10 IGN per address per day. Any 4 GB card at launch. The dataset starts at 2 GB and grows (2 GB, doubling at years 4, 12 and 28), so a 4 GB card mines for about four years, approximate." | number | api/faucet.mjs 8-9; evidence row 31; MATCH, APPROX | +| P-miner-65 | "Read more in the litepaper" /litepaper#miners | link | exists | +| P-miner-66 | band "Every number here has a row." + Engineering log, Bench table | claim, link | | + +## Wallet (site/wallet.html; content owned by the wallet-ui-3 agent today) + +| id | text | kind | verdict | +|---|---|---|---| +| P-wallet-1 | meta "24 words sealed ... MetaMask export. Reads your own node when the miner is installed." | claim | | +| P-wallet-2 | "Igneum Wallet · desktop" | eyebrow | | +| P-wallet-3 | h1 "Your coins. Final means final." | heading | aphorism; 30 characters | +| P-wallet-4 | lead "verifies every finality certificate itself with the node's own code. No confirmation counts, no trusting the node." | claim | antithesis | +| P-wallet-5 | "Download: public testnet" #get; "How final works" #finality | links | | +| P-wallet-6 | "macOS first", "Windows next", "MetaMask export" | state | | +| P-wallet-7 | screenshot "Igneum Wallet on a private test network, 5 Oct 2026. The address is an example." | date | | +| P-wallet-8 | "Three states, checked here": pending; "Chain block 8"; "final · cp 5 ... 30-second checkpoint ... aggregate BLS signature, two thirds of all weight" | claim, number | explorer.md 43; evidence row 10; MATCH | +| P-wallet-9 | second screenshot "1.5 IGN, final under checkpoint 5, certificate verified by the wallet" | number | | +| P-wallet-10 | four checks before "final" | claim | | +| P-wallet-11 | "The same steps the browser verifier on the home page runs ... The node's own 'locked' field is never read." | claim | | +| P-wallet-12 | "Every feature, one line each. Version 1, built on the miner's bones" | claim | | +| P-wallet-13 | h3 "Create or import, sealed on your disk" | heading | 37 characters | +| P-wallet-14 | "Create: 24 words ... 256 bits ... three typed back" | number | UNSOURCED in repo (wallet source elsewhere) | +| P-wallet-15 | "Import ... the miner's own payout key file" | claim | | +| P-wallet-16 | "Argon2id (64 MiB, 3 passes) ... XChaCha20-Poly1305 ... one file in your user folder" | number | UNSOURCED in repo | +| P-wallet-17 | "BIP-39 and BIP-44 at the Ethereum path" | claim | | +| P-wallet-18 | "Signing happens in the engine, in Rust." | claim | | +| P-wallet-19 | Balance; Send (EIP-1559, zero address and over-balance refused); Receive QR (SVG); History with rewards; Finality per transaction; Lock | claims | | +| P-wallet-20 | "Reads the miner's node first": 1 miner app's node, 2 public RPC, 3 bundled node; "Updates, signed ... Ed25519 ... checked an hour apart" | claim | evidence row 23; MATCH | +| P-wallet-21 | MetaMask: Add to MetaMask, Export the key, "Desktop first: macOS now, as a disk image. The Windows host is written and untested. No browser extension and no phone app yet." | claim, state | | +| P-wallet-22 | "The first run, timed. A private test network, 5 Oct 2026 ... The log entry ships with the wallet." | date, claim | | +| P-wallet-23 | table: 0.3 s; 0.4 to 0.5 s "word 1 is not right"; 3.5 s "10.14 IGN at block 4"; 4.5 s; 4.6 s "gas 25,380; base fee 1 gwei; tip 1 gwei; fee at most 0.00007614 IGN"; 5.6 s chain block 8; about 170 s index 5; 175.2 s "1 of 1 voters, 100% of total weight"; 175 s | numbers | not in docs or /bench; UNSOURCED in repo | +| P-wallet-24 | "Send to final: 170.6 s ... On the live devnet checkpoints lock every 30 seconds once the weight window is full. 13 unit tests cover ..." | number | UNSOURCED in repo | +| P-wallet-25, 26 | "Get the wallet. Download only from this domain ..."; the two notices | claim, state | | +| P-wallet-27 | macOS "v0.1.4 · 19.6 MB"; Windows "next" disabled; MetaMask #metamask | number, feature | host 0.1.4, 19,607,181 bytes; MATCH | +| P-wallet-28 | "reads this machine's node when the miner is installed" /miner; "Read more in the litepaper" /litepaper#miners | link | | +| P-wallet-29 | band "The miner pays this wallet." + The miner | claim, link | aphorism | + +## Bench (site/bench.html, generated from docs/bench-log.md through site/scrub.mjs) + +| id | text | kind | verdict | +|---|---|---|---| +| P-bench-1 | "83 entries, newest at the bottom" | number | 83 h2 in markdown, 83 on the page; MATCH | +| P-bench-2 | h1 "Engineering log" | heading | the markdown's own h1 is rendered and hidden by CSS | +| P-bench-3 | note "Every measurement the project has made, newest at the bottom, written by the people and agents who ran it, with the commands and hardware. Prototype numbers are not mining numbers and say so." | claim | | +| P-bench-4 | contents, 83 links | feature | TOC text keeps raw backticks; some headings over 150 characters | +| P-bench-5 | "Generated from the repository at build time. Times are UTC. Machine names are model names." | claim | | + +Heading comparison: every difference is a scrub rename ("Mac" to "Apple M5 Max" 9 times, "Windows PC" to "an RTX 5090 on Windows", "Hetzner" to "the cloud provider"); 18 h3 both sides; the newest 6 Oct entry is present. Rendered headings keep commit hashes and internal names (6c75dad, b970dda, revm, viem, SP1, PC 1, PC 2, DAA 33,000) by design of the generator. + +## Evidence (site/evidence.html, rows generated from docs/evidence.md) + +| id | text | kind | verdict | +|---|---|---|---| +| P-evid-1 | meta "Nothing has been reproduced or reviewed yet." | claim | | +| P-evid-2 | "31 claims · 5 labels · 6 Oct 2026" | number, date | 31 rows; the date is the build date and says so | +| P-evid-3 | h1 "Evidence" | heading | | +| P-evid-4 | the five label definitions; "Nothing on this chain has been reproduced externally or reviewed independently; every row says so"; "The 12-node cloud network of 4 October 2026 is the project's own" | claim | 70-word sentence | +| P-evid-5 | tiles designed 6, implemented 3, tested by the team 22, reproduced externally 0, reviewed independently 0; "None yet. The repository is private until the public testnet"; funding plan | number | evidence.md's own count table says 5 designed and sums to 30; the page buckets row 17 as designed | +| P-evid-6 | filter chips 31, 6, 3, 22, 0, 0 | feature | | +| P-evid-7 | "The table is wider than this screen. Scroll it sideways." | feature | under 1,140 px | +| P-evid-8 | columns #, Claim, Status, Version or commit, Reproducible test, Result date machine, Independent verification; sortable | feature | | +| P-evid-9 | 31 rows | generated | every row ends "none yet"; scrub artefacts "the Apple M5 Max M5 Max" (row 1), "a an RTX 5090 on Windows with an RTX 5090" (row 30) | +| P-evid-10 | note "Click a column heading to sort ... igneum-pow is the Rust crate at version 0.2.0 ... Source of every number: the engineering log. The source of this page is docs/evidence.md" | claim, path | | +| P-evid-11 | "What would move a row" table; "Funding for review is docs/plans/funding.md" | claim, path | mirrors evidence.md 94-101 | +| P-evid-12 | "Statuses are honest as of 6 October 2026, the day this page was generated from docs/evidence.md" | date, path | | + +Markdown headings not rendered: "What moved on 4 October 2026", "What moved on 5 October 2026" (two tables not shown anywhere on the site). + +## Ledger (site/ledger.html, generated by tools/ledger-page.mjs from docs/fud-ledger.md) + +| id | text | kind | verdict | +|---|---|---|---| +| P-ledger-1 | meta "167 entries. Nothing deleted, nothing softened." | number, claim | antithesis | +| P-ledger-2 | "Ledger · 167 entries · regenerated from the repository" | number | 167 ids both sides; MATCH | +| P-ledger-3 | h1 "Every criticism, answered or conceded" | heading | 37 characters | +| P-ledger-4 | intro: "167 entries since 3 October 2026 ... The founder mined through the GPU years. Ethereum's move to proof of stake in September 2022 ended that income ... one person building, with AI systems doing the engineering ... This ledger is the application form" + mailto | claim | | +| P-ledger-5 | counts Open 7, Conceded 53, Fixed or built 54, Closed by rule or decided 27, Answered with evidence 13, Answered by design 13, All 167; section links | number, feature | md table (17:30 UTC): Fixed 57, Conceded 53, Answered 28, Decided 29, Open 7; the page buckets on the status's first word | +| P-ledger-6 | search "Search the ledger", "N of 167 shown" | feature | | +| P-ledger-7 | 167 cards: id, title, date, quote, status, "The answer as first written" | generated | the renderer drops 165 "Evidence:" lines and the "Decision owner:" lines; 40 section h2 with duplicate ids (anchors land on the first) | +| P-ledger-8 | "Source: docs/fud-ledger.md in the repository, rendered by tools/ledger-page.mjs ... hello@igneum.network or an issue on the specification repository." | path, link | | + +Left on the public page by the ledger's own scrub list: "PC 2" 15 times, "the Mac" 19 times, `~/.config/igneum` 5 times, "pid 33114", `--rpclisten=0.0.0.0:26610`. The ledger renderer skips the forbidden-strings hard stop. + +## Explorer (site/explorer.html) + +| id | text | kind | element, states, verdict | +|---|---|---|---| +| P-expl-1 | "devnet, last 24 hours" | claim | api/explorer.mjs 87 keeps one day; MATCH | +| P-expl-2 | h1 "Explorer" | heading | | +| P-expl-3 | "Every block the devnet made in the last day, read from a node by the observer. Paste a block hash, a transaction hash, a chain block number or an address." | claim | | +| P-expl-4 | search form, placeholder | feature | | +| P-expl-5 | #msg | state | "Not a block hash, a transaction hash, a chain block number or an address." / "Looking." / API error or "Not found." / "The API did not answer." | +| P-expl-6 | Status | API | OFFLINE/LIVE; "no observer update yet", "last update N ago", ", node " | +| P-expl-7 | Height; "chain block number, N blocks in the DAG" | API | height or "n/a" | +| P-expl-8 | DAA score; blue score | API | | +| P-expl-9 | Difficulty; "target 1 s per block" or "N s per block over 60 s" | API | "n/a" when null | +| P-expl-10 | Hash rate | API | "n/a" when null | +| P-expl-11 | Block reward IGN; split | API | | +| P-expl-12 | Circulating; "of 4,000,000,000 by the rule" | API | MATCH | +| P-expl-13 | Next halving; ramp | API | | +| P-expl-14 | "Latest blocks", "newest first, every 5 s" or "observer offline, last known" | API | setInterval 5,000; MATCH | +| P-expl-15 | table Block, Number, DAA, Blue score, Miner, Txs, Proof records, Time | API | "Loading."; empty "No blocks in the last 24 hours."; "off chain"; "n/a"; "★" locked | +| P-expl-16 | legend chain block, blue merged and paid, red excluded, pending, ★ locked checkpoint | feature | | +| P-expl-17 | note "Number is the chain block number, the same number the EVM reports ... Miner is the payout address the coinbase names. Proof records is how many shard proofs the block carries for earlier blocks." | claim | | +| P-expl-18 | "Older blocks" | feature | loads 50 more; the 5 s refresh stops for good after the first click | +| P-expl-19 | "Public API, JSON, cached 10 s" | claim | stats and supply 10 s, explorer 5 s; APPROX | +| P-expl-20 | /api/stats field list | link | MATCH | +| P-expl-21 | /api/supply "circulating, cap, halving table, 30-day ramp, the observer's coinbase check" | link | no `check` field in today's payload; UNSOURCED today | +| P-expl-22 | /api/explorer?blocks=20 and its parameters | link | MATCH | +| P-expl-23 | note "Reward and supply come from the emission rule (section 2.5) ... the observer checks the chain's coinbase sums against it every hour and the result is in /api/supply under check." | claim | see P-expl-21 | + +Bad query: empty or unrecognised text shows the "Not a block hash ..." sentence; an address redirects to /address/ unchecked; a hash or number asks the API and shows its 404 text; network failure "The API did not answer." + +## Block (site/block.html) + +| id | text | kind | verdict | +|---|---|---|---| +| P-block-1 | noindex; "Explorer · block" | link | | +| P-block-2 | h1 "Block" then the hash, or "Chain block N" | API | | +| P-block-3 | chips: chain block or colour; "checkpoint N, "; "N proof records"; "N transactions" | API | | +| P-block-4 | #msg API error, "Not found.", "The API did not answer: " | state | | +| P-block-5 | summary: Number or "none, not a chain block"; Time; DAA; Blue score; Miner or "n/a"; Coinbase address; Vote key id and hash ("n/a"); Engine; Difficulty or "n/a"; "Declared subsidy N IGN E(DAA) of spec 2.5, paid when a later chain block merges this one" or "n/a"; "Coinbase paid N IGN"; Merged by "itself" / link / "not yet"; Selected parent or "n/a" | API | /api/stats source; MATCH | +| P-block-6 | header: Hash, Version, Bits, Nonce, Blue work, merkle roots, UTXO commitment, Pruning point, Parent levels | API | raw header fields, an explorer's job | +| P-block-7 | Parents "N at level 0" or "Genesis has no parents."; Children "seen within 10 min" or "No child seen yet." | API | | +| P-block-8 | Mergeset or "Empty."; note on red blocks | claim | | +| P-block-9 | Transactions "N EVM, 1 coinbase"; coinbase outputs "proving pool (burns on the UTXO side, credited on the EVM side)"; "N proof records, a key reveal, certificate N"; tx table ("needs an EVM RPC"); "No EVM transactions in this block." | API | | +| P-block-10 | Proof records: "N shards planned for this chain block" / "not a chain block"; "carries N proof records for earlier chain blocks (274 bytes each, in the coinbase extra data)"; shard table; "No shard plan recorded (the proving feed was not reading this block)." | API, number | spec 07 112; MATCH | +| P-block-11 | Finality: "checkpoint N" / "carries a certificate" / "not a checkpoint"; State, Signed weight "N of N (X% of all weight, X% of active)", Votes, Locked; "Verify: /api/checkpoint serves the newest certificate"; "Checkpoints are every 30 blue score; a lock needs two thirds of all 30-day weight." | API, claim | explorer.md 43; MATCH | + +Bad query: /block with no id asks ?block=block, the API answers 400 "A block hash is 64 hex characters."; unknown hash: 404 "No block with that hash in the last 24 hours. The explorer keeps one day; older blocks live in the node."; unknown number: "No chain block numbered N in the last 24 hours." + +## Address (site/address.html) + +| id | text | kind | verdict | +|---|---|---|---| +| P-addr-1 | noindex; "Explorer · address"; h1 the address | API | | +| P-addr-2 | chips "EVM payout address" / "coinbase address"; "mining now" | API | | +| P-addr-3 | #msg | state | | +| P-addr-4 | Balance "n/a" then IGN or "n/a"; sub-line default "eth_getBalance", then source or reason ("no EVM RPC configured on this deployment (EXPLORER_EVM_RPC)") | API | today every address shows "n/a" and the env-var sentence | +| P-addr-5 | "Blocks, 24 h"; "N in 10 min, N blue, N red, N on the chain" | API | | +| P-addr-6 | "Earned, 24 h" IGN; "80% of each blue block's subsidy" | API, claim | MATCH | +| P-addr-7 | "Last block" "n/a" then relative or "none in 24 h"; "first in the window N ago" | API | | +| P-addr-8 | identity: EVM address or "none seen"; coinbase address; vote keys or "none"; earned; note "A miner names its EVM payout address in every coinbase (the IGNA tag) ... a card runs several." | API, claim | | +| P-addr-9 | "Blocks mined, newest 50 of the last 24 hours"; table; "off chain"; "n/a"; empty "No blocks from this address in the last 24 hours." | API | | + +Bad query: /address with no address sends ?address=address, the API answers 400 "An address is 0x plus 40 hex characters, or an igneum bech32 address."; an unseen well-formed address returns zeros with no distinct "never seen" sentence. + +## Faucet (site/faucet.html) + +| id | text | kind | verdict | +|---|---|---|---| +| P-fauc-1 | title "Igneum testnet faucet. 10 IGN a day for testing"; meta | number | api/faucet.mjs 8-9; MATCH | +| P-fauc-2 | "Testnet faucet"; h1 "10 IGN a day, for testing." | number | | +| P-fauc-3 | "Paste an address. The faucet sends 10 testnet IGN and shows the transaction hash. Once per address per day, once per connection per day. No account, no sign-in." | claim | | +| P-fauc-4 | "Public testnet: not yet open. The faucet is prepared on the devnet and answers 'not open yet' until the testnet starts." | state | API text "The faucet is not open yet. It opens with the public testnet."; APPROX | +| P-fauc-5 | "Ask for 10 IGN. An Ethereum-style address: 0x and 40 hex characters." | claim | | +| P-fauc-6 | form; "Send 10 IGN"; #status words: "That is not an address ...", "Sending…", "Sent 10 IGN. Transaction . It is in a block within a few seconds.", API error or "The faucet answered N.", "The faucet did not answer. Try again in a minute." | feature | | +| P-fauc-7 | rules 01 to 04: no value, "Mainnet starts from an empty genesis"; 10 IGN per address per day, resets 24 h after the last grant; resets at a consensus change; stored: address, IP, tx hash, time, 24 hours | claim, number | faucet.mjs 73, 77, 78; MATCH; "Mainnet starts from an empty genesis" APPROX (plan) | +| P-fauc-8 | "Chain id 4462 (testnet), 4463 (devnet)"; MetaMask /metamask; Get the miner /miner#get | number, link | spec 07 20; MATCH | + +## MetaMask (site/metamask.html; canonical set to /wallet) + +| id | text | kind | verdict | +|---|---|---|---| +| P-mm-1 | "Wallets · chain id · RPC"; h1 "Add Igneum to MetaMask" | heading | | +| P-mm-2 | note: EVM, chain id, RPC, symbol IGN, 18 decimals, wallet_addEthereumChain; "Nobody from Igneum will ask for your seed." | claim | | +| P-mm-3 | Testnet card: Igneum Testnet; 4462 (0x116e); rpc.testnet.igneum.network (published with the testnet); IGN; 18; button disabled; "switches on when the public RPC is live" | number, state | spec 07 20; MATCH as placeholder | +| P-mm-4 | Devnet card: Igneum Devnet (local node); 4463 (0x116f); http://127.0.0.1:26790; "Explorer: none yet" | number, state | bench-log 284 port MATCH; "none yet" STALE (/explorer is live) | +| P-mm-5 | button states: no wallet found; waiting; added; cancelled; refused | feature | | +| P-mm-6 | "Add it by hand", four steps | claim | | +| P-mm-7 | "For builders" code block; EIP-155, EIP-1559, legacy; eth_gasPrice, eth_estimateGas; /litepaper#builders-ask | claim, link | exists | +| P-mm-8 | "The app and the Igneum Wallet": "The Igneum Miner app makes an address ... An Igneum Wallet ... is in the roadmap; until it ships, MetaMask is the wallet." | claim | STALE (wallet 0.1.4 ships; the app is Ember) | +| P-mm-9 | "10 IGN per address per day. Chain ids 4461 (mainnet), 4462 (testnet), 4463 (devnet) fixed in the node. The testnet RPC URL above is a placeholder" | number, claim | spec 07 20, 60; MATCH | + +## 404 (site/404.html) + +| id | text | kind | verdict | +|---|---|---|---| +| P-404-1 | title "Page not found. Igneum"; noindex | | | +| P-404-2 | "404"; h1 "Nothing is mined here." | heading | aphorism | +| P-404-3 | "That address is not on igneum.network. It may have moved, or the link had a typo. These four pages are everything the site has." | claim | STALE: fifteen pages | +| P-404-4 | "Litepaper: How the chain works, in 17 sections" | number | 19 sections; STALE | +| P-404-5 to 7 | Live devnet; Engineering log; Evidence | links | no miner, wallet, explorer or ledger card | + +## Scrub rules (site/scrub.mjs, site/forbidden-strings.txt), applied to bench, miners and the evidence rows + +| rule | what changes | why | +|---|---|---| +| scrub 12-17 | PC and Windows PC wording becomes RTX 5090 wording | machine names become model names | +| 18-20 | the Mac becomes Apple M5 Max | same | +| 21-22 | the project lead becomes the maintainers | identity | +| 23 | " Not deployed to Vercel tonight." removed | host name | +| 25-27 | private IPs and DESKTOP- hostnames become placeholders | private addresses | +| 28-30 | igneum-seed-N, Hetzner, hcloud become generic words | provider names | +| 31-33 | server paths and dl.igneum.network become placeholders | server paths | +| 34-35 | intake ids removed | upload identifiers | +| 36-39 | home paths become ~ and %USERPROFILE% | user names | +| 41-43 | docs/fud-ledger.md becomes "the break ledger (kept by the maintainers, not yet published)"; CLAUDE.md becomes "the design document" | the ledger is now published at /ledger: this rewrite is STALE | +| 45-50 | BST times to UTC | the log is written in UTC+1 | +| forbidden-strings 1-25 | build fails on any survivor (hostnames, private IPs, BST, home paths, intake, Tailscale, the project lead, Hetzner, seed names, server paths, dl host, CLAUDE.md, hcloud) | hard stop | + +Side effects today: "the Apple M5 Max M5 Max" (evidence row 1), "a an RTX 5090 on Windows with an RTX 5090" (evidence row 30), "the 12-node the cloud provider network" (journey log). The ledger page uses its own list and skips the hard stop. diff --git a/docs/plans/site-ui-3.md b/docs/plans/site-ui-3.md new file mode 100644 index 000000000..c1e13b8eb --- /dev/null +++ b/docs/plans/site-ui-3.md @@ -0,0 +1,215 @@ +# Site UI 3: the website and litepaper through the miner app's lens + +6 October 2026. Branch `site-ui-3`. The audit is `docs/plans/site-ui-3-audit.md`; this is the design the build follows. +The standard is the miner app's third redesign (`docs/plans/miner-ui-3.md` on branch `miner-ui-3`): one job per screen, +one primary control, hierarchy by type not boxes, no developer text on a user surface, no n/a cells, plain state words with +reasons, light and dark, phone width, nothing lost. + +## 1. What changes and what does not + +| Stays | Changes | +|---|---| +| Every claim, number, date, link and feature in the audit's tick list (appendix A of the audit) | Fifteen pages each carrying their own ` + @@ -102,10 +51,9 @@ p{margin:0;color:var(--ink-2);max-width:52ch} @@ -135,9 +95,9 @@ p{margin:0;color:var(--ink-2);max-width:52ch}
404

Nothing is mined here.

-

That address is not on igneum.network. It may have moved, or the link had a typo. These four pages are everything the site has.

+

That address is not on igneum.network. It may have moved, or the link had a typo. The pages below are where most readers want to go; the footer lists every page.

    -
  • LitepaperHow the chain works, in 17 sections
  • +
  • LitepaperHow the chain works, in 19 sections
  • Live devnetBlocks, miners and finality as they happen
  • Engineering logEvery measurement, with the commands
  • EvidenceEvery claim and how far it is tested
  • @@ -149,7 +109,7 @@ p{margin:0;color:var(--ink-2);max-width:52ch}
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -185,10 +145,23 @@ p{margin:0;color:var(--ink-2);max-width:52ch}
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + diff --git a/site/address.html b/site/address.html index 640a8121d..bca765066 100644 --- a/site/address.html +++ b/site/address.html @@ -29,9 +29,10 @@ + + @@ -168,10 +99,9 @@ main{padding-bottom:var(--sec)} @@ -222,7 +164,7 @@ main{padding-bottom:var(--sec)}
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -258,10 +200,23 @@ main{padding-bottom:var(--sec)}
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + @@ -141,10 +87,9 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
    -
    88 entries, newest at the bottom
    +
    90 entries, newest at the bottom

    Engineering log

    Every measurement the project has made, newest at the bottom, written by the people and agents who ran it, with the commands and hardware. Prototype numbers are not mining numbers and say so.

    - +

    Igneum bench log

    Append-only. Every number here was measured on the machine named, on the date given.

    2026-10-03 proto-metal / igneum-bench, first run

    @@ -227,9 +184,9 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    3 October 2026, igneum-node devnet v0: 3-node igneum-devnet at 1 BPS with the 80/20 coinbase and vote_key_hash (consensus-engineer)

    Machine: Apple M5 Max (18 logical cores), rustc 1.99.0, fork vendor/igneum-node at commit "Build: forward the igneum-pow feature" on top of rusty-kaspa v2.1.0 01b532e8. Release build of kaspad and igneum-miner; the kHeavyHash stub engine (default feature set); cargo check -p kaspad --features igneum-pow also builds. Network: three kaspad --devnet --nodnsseed --disable-upnp --enable-unsynced-mining nodes, P2P 26611/26621/26631, gRPC 26610/26620/26630, nodes 2 and 3 --connect to node 1 and node 3 also to node 2; network name igneum-devnet, k 18, merge depth 3,600 blocks, DAA 661 samples x 4 blocks, genesis bits 0x1e020000 (2^23 expected hashes per block). Miners: three igneum-miner mine processes, 6 threads each, one per node, 960 s, each with its own vote-key label: 2.21 MH/s each (6.63 MH/s total), found 253 + 284 + 270 = 807 blocks, 0 rejected. Blocks per second: 0.84 on all three nodes over the 901.9 s watch window (755 blocks each); expected 0.79 from hash rate over genesis difficulty, then the DAA lowered difficulty from 4,194,304 to 3,444,348 after its 600-block minimum window (block 600 to 711), still converging to 1.00 when the run ended. Propagation: block count, DAA score and sink hash identical on all three nodes at 90 of 90 ten-second samples; 1.11 parents and 1.11 mergeset per block on average, tips stayed at 1 (three serial CPU miners rarely collide). vote_key_hash: igneum-miner inspect 40 read the same 40 selected-chain blocks from all three nodes over gRPC and found the header's vote_key_hash identical on every node for 40 of 40 blocks, with the three miners' distinct hashes (17 + 17 + 6 blocks) all present, so the field round-trips through the template RPC, submit, p2p relay and the header hash. Emission: 80/20 exact on 39 of 39 single-payee coinbases (the 40th merged two blues, three outputs, pool share still 0.2000); at DAA 806 the payload subsidy was 317,767,704 units (launch ramp day 0, 10.03%), split 254,213,284 to the miner and 63,553,320 to the OP_RETURN igneum-proving-pool-v0 output. Unit tests, release profile: kaspa-consensus-core igneum 8 pass (subsidy table, ramp, split, cap), params window test 1 pass, kaspa-pow 5 pass (stub) and 6 pass with --features igneum-pow (engine smoke, one 256 MiB cache, 0.39 s), kaspa-consensus coinbase 8 pass. Per-second subsidy, 8 decimals: 3,168,808,781 units (31.68808781 coins) for years 0 to 2, 1,584,404,390 for years 2 to 4, 792,202,195 for years 4 to 6, 1 unit in period 31, 0 from period 32; ramp day 0 is 316,880,878; the sum is under the 4,000,000,000-coin cap by less than 100 coins. Not done: the devnet ran on the kHeavyHash stub, not the lottery engine (the miner has no igneum-pow path yet and the lane hash does not absorb the header); no VDF seed, no finality, no prover payout; 8 versus 18 decimals open (docs/fork-divergence.md).

    3 October 2026, first devnet blocks on the real lottery hash: CPU, then Metal GPU, three worker implementations (consensus-engineer)

    -

    Machine: Apple M5 Max (18 logical cores, 40 GPU cores), rustc 1.99.0, Swift 5.8.1, fork vendor/igneum-node at "PoW: header-bound lottery engine, real-hash miner modes, genesis bits 0x1e400000" plus the overnight genesis commit; igneum-pow at "igneum-pow: header binding ...". Release builds with --features igneum-pow. Binding (spec 01 section 1.6, O-1.9, igneum-pow/src/bind.rs): I = seed_words_from_bytes("igneum-block/" || H || nonce_hi_le32), lane nonce = low 32 bits of the 64-bit header nonce, H = header hash with the nonce zeroed and the timestamp kept, pow256 = lane hash in the top 64 bits with zero low bits (pow <= target is exactly lane <= target >> 192). Interim day seed "igneum-day/" || day_le64 (day = timestamp_ms / 86,400,000); epoch seed = the 32 bytes of the epoch block hash (genesis for epoch 0). 8 bound vectors in igneum-pow/README.md; 29 crate tests pass; the 288 pack vectors and the pack files are unchanged, program_bound.metal, kernel_bound.cu and kernel_bound.cl are new pack files. CPU rate on the real hash: 0.44 ms per 32-lane warp on one core (crate bench); 0.142 MH/s with one 6-thread miner (1.35 ms per warp per thread); 0.294 MH/s with three 6-thread miners at once (2.0 ms per warp per thread, memory-latency bound), 0.37 MH/s later in the run. Genesis bits for the CPU devnet: 0x1e400000 = 2^18 expected hashes per block. CPU devnet, 3 nodes (node 1 RPC and p2p on 0.0.0.0, ports 26610/26611, 26620/26621, 26630/26631), three 6-thread igneum-miner mine --engine igneum-pow, 660 s: found 252 + 309 + 272 = 833 blocks, 0 rejected; watch window 641 s: 825 blocks on all three nodes = 1.29 blocks/s; sink identical on all nodes at 61 of 64 samples (tips 1 or 2, twice 3). DAA: 1.43 blocks/s over the first 600 blocks at difficulty 131,072, then difficulty 184,000 to 187,000 (1.41x) and 1.03 blocks/s over blocks 610 to 816. Each node logged "PoW accepted <hash> by igneum-lottery-v1-bound" 833 times, 0 rejections during the run. igneum-miner bad-nonce: Reject(BlockInvalid) and a "PoW rejected ... by igneum-lottery-v1-bound" line. inspect 30: vote_key_hash identical on all 3 nodes for 30 of 30, 80/20 exact on 19 of 19 single-payee coinbases. Epoch 0 seed = devnet genesis hash 03115da0...d86b, day 20729, program 104 loads/hash. Metal GPU worker (proto-metal/igneum-bench --serve, runtime-compiled igneum_hash_bound, init words in buffer 3, 2^22 nonces per dispatch, CPU-side scan of the 64-bit outputs) driven by igneum-miner --worker on node 1 of the same devnet, 300 s: 506 jobs of 2^24 nonces, 5,636 blocks found and accepted, 0 rejected, 0 CPU/GPU mismatches (every found nonce is re-hashed on the CPU before submit); nodes 833 -> 5,073 blocks on all three (14.57 blocks/s over the 291 s watch window), sink identical at 28 of 29 samples; difficulty 180,562 -> 7,134,312 (39x) and still rising at the end. Epoch change crossed live at DAA 3,600: new seed 76c39fcf..., 128-load program compiled by the worker in 129 ms (first program 6.5 ms), no rejected blocks across the change. Rate through the worker: 32.4 MH/s inside jobs, 28.2 MH/s wall, against 45.2 MH/s raw bench (igneum-bench 2^22 x 4 batches): the gap is the read-back and CPU scan per dispatch, one command buffer per dispatch, and the template round trip per job. Early in the run one job found about 45 sibling blocks of one template; the miner now submits one block per job. Overnight devnet (started 19:07 UTC): genesis bits 0x1d100000 = 2^28 expected hashes per block, sized for RTX 5090 229 + M5 Max 45 + gfx1036 4 = 278 MH/s (1.04 blocks/s); genesis hash edc4fa84...fb07; epoch 0 program 136 loads/hash compiled in 69.5 ms on Metal; node 1 alone (0.0.0.0:26610/26611, caffeinate -dims, logs /tmp/igneum-devnet/node1.log) with the Metal worker (/tmp/igneum-devnet/metal-worker.log): 31 blocks in 273 s = 0.11 blocks/s at 31.1 MH/s, as expected for 2^28 until the RTX 5090 machine joins. Worker implementations, all bit-exact with igneum-pow hash-bound for a 96-nonce job across the 2^32 lane boundary (nonces 4294967264 to 4294967359, prehash ab x 32, devnet seeds): Metal (M5 Max GPU), OpenCL (proto-opencl/host.c --serve, Apple OpenCL 1.2 on the M5 Max, local-memory exchange, --vendor device filter added), CUDA (proto-cuda/host.cu --serve with the pack's kernel_bound.cu, through the clang emulation shim: bench PASS on the Rust-exported devnet pack, serve job bit-exact, seed-mismatch error exercised). CUDA and OpenCL are built ahead of time per pack; the Windows launcher re-exports and rebuilds at each epoch or day change (miner exit 42). igneum-miner.exe cross-compiled for x86_64-pc-windows-gnu with Homebrew mingw-w64 (9.4 MB; no rocksdb in the miner's closure). Not done: no NVIDIA or AMD run of the bound kernels yet (the Windows package igneum-mine-test.zip is the next step); NVRTC and runtime OpenCL rebuilds inside the workers; the block level for pruning proofs on a lane-only pow value; 8 vs 18 decimals; the VDF seeds and finality.

    +

    Machine: Apple M5 Max (18 logical cores, 40 GPU cores), rustc 1.99.0, Swift 5.8.1, fork vendor/igneum-node at "PoW: header-bound lottery engine, real-hash miner modes, genesis bits 0x1e400000" plus the overnight genesis commit; igneum-pow at "igneum-pow: header binding ...". Release builds with --features igneum-pow. Binding (spec 01 section 1.6, O-1.9, igneum-pow/src/bind.rs): I = seed_words_from_bytes("igneum-block/" || H || nonce_hi_le32), lane nonce = low 32 bits of the 64-bit header nonce, H = header hash with the nonce zeroed and the timestamp kept, pow256 = lane hash in the top 64 bits with zero low bits (pow <= target is exactly lane <= target >> 192). Interim day seed "igneum-day/" || day_le64 (day = timestamp_ms / 86,400,000); epoch seed = the 32 bytes of the epoch block hash (genesis for epoch 0). 8 bound vectors in igneum-pow/README.md; 29 crate tests pass; the 288 pack vectors and the pack files are unchanged, program_bound.metal, kernel_bound.cu and kernel_bound.cl are new pack files. CPU rate on the real hash: 0.44 ms per 32-lane warp on one core (crate bench); 0.142 MH/s with one 6-thread miner (1.35 ms per warp per thread); 0.294 MH/s with three 6-thread miners at once (2.0 ms per warp per thread, memory-latency bound), 0.37 MH/s later in the run. Genesis bits for the CPU devnet: 0x1e400000 = 2^18 expected hashes per block. CPU devnet, 3 nodes (node 1 RPC and p2p on 0.0.0.0, ports 26610/26611, 26620/26621, 26630/26631), three 6-thread igneum-miner mine --engine igneum-pow, 660 s: found 252 + 309 + 272 = 833 blocks, 0 rejected; watch window 641 s: 825 blocks on all three nodes = 1.29 blocks/s; sink identical on all nodes at 61 of 64 samples (tips 1 or 2, twice 3). DAA: 1.43 blocks/s over the first 600 blocks at difficulty 131,072, then difficulty 184,000 to 187,000 (1.41x) and 1.03 blocks/s over blocks 610 to 816. Each node logged "PoW accepted <hash> by igneum-lottery-v1-bound" 833 times, 0 rejections during the run. igneum-miner bad-nonce: Reject(BlockInvalid) and a "PoW rejected ... by igneum-lottery-v1-bound" line. inspect 30: vote_key_hash identical on all 3 nodes for 30 of 30, 80/20 exact on 19 of 19 single-payee coinbases. Epoch 0 seed = devnet genesis hash 03115da0...d86b, day 20729, program 104 loads/hash. Metal GPU worker (proto-metal/igneum-bench --serve, runtime-compiled igneum_hash_bound, init words in buffer 3, 2^22 nonces per dispatch, CPU-side scan of the 64-bit outputs) driven by igneum-miner --worker on node 1 of the same devnet, 300 s: 506 jobs of 2^24 nonces, 5,636 blocks found and accepted, 0 rejected, 0 CPU/GPU mismatches (every found nonce is re-hashed on the CPU before submit); nodes 833 -> 5,073 blocks on all three (14.57 blocks/s over the 291 s watch window), sink identical at 28 of 29 samples; difficulty 180,562 -> 7,134,312 (39x) and still rising at the end. Epoch change crossed live at DAA 3,600: new seed 76c39fcf..., 128-load program compiled by the worker in 129 ms (first program 6.5 ms), no rejected blocks across the change. Rate through the worker: 32.4 MH/s inside jobs, 28.2 MH/s wall, against 45.2 MH/s raw bench (igneum-bench 2^22 x 4 batches): the gap is the read-back and CPU scan per dispatch, one command buffer per dispatch, and the template round trip per job. Early in the run one job found about 45 sibling blocks of one template; the miner now submits one block per job. Overnight devnet (started 19:07 UTC): genesis bits 0x1d100000 = 2^28 expected hashes per block, sized for RTX 5090 229 + M5 Max 45 + gfx1036 4 = 278 MH/s (1.04 blocks/s); genesis hash edc4fa84...fb07; epoch 0 program 136 loads/hash compiled in 69.5 ms on Metal; node 1 alone (<listen address>/26611, caffeinate -dims, logs /tmp/igneum-devnet/node1.log) with the Metal worker (/tmp/igneum-devnet/metal-worker.log): 31 blocks in 273 s = 0.11 blocks/s at 31.1 MH/s, as expected for 2^28 until the RTX 5090 machine joins. Worker implementations, all bit-exact with igneum-pow hash-bound for a 96-nonce job across the 2^32 lane boundary (nonces 4294967264 to 4294967359, prehash ab x 32, devnet seeds): Metal (M5 Max GPU), OpenCL (proto-opencl/host.c --serve, Apple OpenCL 1.2 on the M5 Max, local-memory exchange, --vendor device filter added), CUDA (proto-cuda/host.cu --serve with the pack's kernel_bound.cu, through the clang emulation shim: bench PASS on the Rust-exported devnet pack, serve job bit-exact, seed-mismatch error exercised). CUDA and OpenCL are built ahead of time per pack; the Windows launcher re-exports and rebuilds at each epoch or day change (miner exit 42). igneum-miner.exe cross-compiled for x86_64-pc-windows-gnu with Homebrew mingw-w64 (9.4 MB; no rocksdb in the miner's closure). Not done: no NVIDIA or AMD run of the bound kernels yet (the Windows package igneum-mine-test.zip is the next step); NVRTC and runtime OpenCL rebuilds inside the workers; the block level for pruning proofs on a lane-only pow value; 8 vs 18 decimals; the VDF seeds and finality.

    3 October 2026, Windows node package: igneumd cross-compiled for x86_64-pc-windows-gnu, two-peer sync test (consensus-engineer)

    -

    Machine: Apple M5 Max, load average 60 to 110 (three other agents building), rustc 1.99.0, Homebrew mingw-w64 (gcc 16.2.0), Homebrew llvm (libclang). Worktree vendor/igneum-node-win, branch windows-node at 352495f6 (the rename commit d62708a8 plus one miner change: watch prints blue= and synced= after sink=). Cross-compile: cargo build --release -j 6 -p kaspad -p igneum-miner --features igneum-pow --target x86_64-pc-windows-gnu at nice -n 19, 8 min 25 s from a clean target directory (recipe in proto-cuda/windows-node/cross-build.sh). librocksdb-sys (bindgen plus the bundled rocksdb and snappy C++) built with LIBCLANG_PATH=/opt/homebrew/opt/llvm/lib, BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu="--target=x86_64-w64-mingw32 --sysroot=<mingw sysroot> -I<mingw include>" and CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++; zstd, lz4, bzip2, zlib, secp256k1 and mimalloc built with the mingw gcc. igneumd.exe 43,172,352 bytes, igneum-miner.exe 9,391,104 bytes. The exe imports libstdc++-6.dll: -static-libstdc++ is ignored by the gcc driver rustc links with, and -C link-arg=-static (second full build, 8 min) does not cover a library rustc passes as -Bdynamic; the package ships libstdc++-6.dll, libgcc_s_seh-1.dll and libwinpthread-1.dll next to the exe (fix for next time: empty CXXSTDLIB_x86_64_pc_windows_gnu plus -Wl,-Bstatic -lstdc++). Not run on Windows yet. Sync test (native build of the same worktree, 20:44 to 20:46 UTC, live node on 26610/26611 untouched): node A on 27000/27001 with START-NODE.bat's flags (--addpeer=<lan-ip>:26611 --listen=0.0.0.0:27001 --nodnsseed --disable-upnp --nologfiles) connected and started IBD within 20 ms, had 5,144 headers and 1,386 blocks at 7 s, and from 17 s on matched the live node's block count, DAA score, blue score and sink at every 10-s sample over 60 s (5,157 to 5,175 blocks, sink identical 5 of 6 samples, synced=true); every header checked by igneum-lottery-v1-bound. Live node peers 1 -> 2 -> 1. Node B on 27010/27011 dialled A's listener, synced to the same sink within 25 s and learnt the live node from A (outbound 2): a node with --addpeer plus --listen accepts inbound connections (--connect would set the inbound limit to 0, kaspad/src/daemon.rs). SIGINT stopped both cleanly. Package: igneum-node-windows.zip from proto-cuda/windows-node/make-package.sh (exe, miner exe, src.zip snapshot of the worktree HEAD plus igneum-pow/, scripts, README). Build on the RTX 5090 machine (BUILD-NODE.bat) estimated at 15 to 25 minutes on the 9800X3D, approximate, untested.

    +

    Machine: Apple M5 Max, load average 60 to 110 (three other agents building), rustc 1.99.0, Homebrew mingw-w64 (gcc 16.2.0), Homebrew llvm (libclang). Worktree vendor/igneum-node-win, branch windows-node at 352495f6 (the rename commit d62708a8 plus one miner change: watch prints blue= and synced= after sink=). Cross-compile: cargo build --release -j 6 -p kaspad -p igneum-miner --features igneum-pow --target x86_64-pc-windows-gnu at nice -n 19, 8 min 25 s from a clean target directory (recipe in proto-cuda/windows-node/cross-build.sh). librocksdb-sys (bindgen plus the bundled rocksdb and snappy C++) built with LIBCLANG_PATH=/opt/homebrew/opt/llvm/lib, BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu="--target=x86_64-w64-mingw32 --sysroot=<mingw sysroot> -I<mingw include>" and CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++; zstd, lz4, bzip2, zlib, secp256k1 and mimalloc built with the mingw gcc. igneumd.exe 43,172,352 bytes, igneum-miner.exe 9,391,104 bytes. The exe imports libstdc++-6.dll: -static-libstdc++ is ignored by the gcc driver rustc links with, and -C link-arg=-static (second full build, 8 min) does not cover a library rustc passes as -Bdynamic; the package ships libstdc++-6.dll, libgcc_s_seh-1.dll and libwinpthread-1.dll next to the exe (fix for next time: empty CXXSTDLIB_x86_64_pc_windows_gnu plus -Wl,-Bstatic -lstdc++). Not run on Windows yet. Sync test (native build of the same worktree, 20:44 to 20:46 UTC, live node on 26610/26611 untouched): node A on 27000/27001 with START-NODE.bat's flags (--addpeer=<lan-ip>:26611 --listen=<listen address> --nodnsseed --disable-upnp --nologfiles) connected and started IBD within 20 ms, had 5,144 headers and 1,386 blocks at 7 s, and from 17 s on matched the live node's block count, DAA score, blue score and sink at every 10-s sample over 60 s (5,157 to 5,175 blocks, sink identical 5 of 6 samples, synced=true); every header checked by igneum-lottery-v1-bound. Live node peers 1 -> 2 -> 1. Node B on 27010/27011 dialled A's listener, synced to the same sink within 25 s and learnt the live node from A (outbound 2): a node with --addpeer plus --listen accepts inbound connections (--connect would set the inbound limit to 0, kaspad/src/daemon.rs). SIGINT stopped both cleanly. Package: igneum-node-windows.zip from proto-cuda/windows-node/make-package.sh (exe, miner exe, src.zip snapshot of the worktree HEAD plus igneum-pow/, scripts, README). Build on the RTX 5090 machine (BUILD-NODE.bat) estimated at 15 to 25 minutes on the 9800X3D, approximate, untested.

    3 October 2026, R3.26 / M15: PoW checked after the cheap checks, cache-build cap, attack before and after (consensus-engineer)

    Machine: Apple M5 Max (18 logical cores), load average 60 to 110 (three other agents building at the same time), rustc 1.99.0. Worktree vendor/igneum-node-r3, branch r3-fixes at 5166ee26 on top of the rename commit d62708a8. Release builds; the real engine needs --features igneum-pow. Fix: validate_header now runs version, timestamp-not-in-future, parent, vote-key, parents-exist, GHOSTDAG, pruning, DAA-score, difficulty, blue-score, blue-work and past-median checks before the PoW engine; the engine (the one 256 MiB cache per day seed) is the last check that chooses seeds. The engine is process-wide, holds KEEP = 4 (epoch seed, day) caches, keeps the chain's current and next day resident, runs at most one build per seed pair and at most 2 at once with a queue of 4 (then PowCacheQueueFull, retryable, not a peer fault). A per-peer p2p guard counts an off-day cold build or a rejected-before-PoW header as a strike; more than IGNEUM_POW_STRIKES (default 2) in an hour disconnects the peer and bans its IP for an hour. Cache build time: one 256 MiB ChaCha12 program-plus-cache build in 222 ms on one core under this load (the engine smoke test on an idle machine earlier the same day measured about 0.2 s; proto-metal reported 273.6 ms for the CPU reference fill under the same load). The honest 20-to-60 s proving lag and the 10 ms CPU verify gate are unaffected. Attack, before and after (ignored test measure_m15_attack_before_and_after, release, --features igneum-pow, validate_and_insert_block, the path submit_block and block relay call into): an honest 10-block chain builds 1 cache (genesis epoch, genesis day). Then 50 headers with bogus timestamps (50 distinct past days) and bogus DAA scores.

    • Before (the pre-fix order, replayed by calling the engine with the header's own unvalidated day seed): 50 cold 256 MiB builds, 10,595 ms, and the honest day's entry is evicted (KEEP was 3).
    • After (the new order): 0 builds, all 50 rejected (TimeTooOld or UnexpectedHeaderDaaScore) in 14 ms total. The live day stays resident.
    @@ -348,30 +305,30 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    4 October 2026, first finality lock on the live devnet: checkpoint 242 at 77.4% of all weight, two hours after genesis

    Live devnet v4 (genesis 09:05 UTC). The weight window and min_daa are 7,200 DAA seconds, so no checkpoint could lock before DAA 7,200. The first checkpoint past it, index 242 (block 59b4a314, blue score 7,261), locked at 11:03:44 UTC with 77.4% of total weight and 77.4% of active weight signed, 12 aggregated votes from 17 vote keys (two RTX 5090 machines with 8 identities each, the Apple M5 Max's Metal miner, the integrated AMD chip's identities), floor 2/3. The certificate (23 headers) was stored and carried in block 1e2439a1; observer.mjs logged checkpoint_locked 0.7 s after the miner's own LOCK line. The floor was raised to 2/3 this morning (O-3.15); this is its first live lock. Difficulty at the moment of the lock was mid-oscillation (93M to 99M, see the oscillation finding), which did not affect voting.

    4 October 2026, the gfx1036 worker fault and what the Apple M5 Max could and could not reproduce

    -

    PC 2 (RTX 5090 plus the Ryzen's integrated gfx1036), package 0.3.0 prebuilt workers. The CUDA worker compiled the pack with NVRTC (after -default-device) and mined at 124.2 MH/s, equal to the nvcc-built worker, 0 rejected, CPU re-check clean. The OpenCL worker (igneum-worker-opencl.exe --pack, path prebuilt-generic) self-tested PASS and mined correctly at 3.3 MH/s for 577 s (8 accepted blocks), then from about 600 s every job "completed" in 0.5 ms with no hash: 906 jobs became 56,384 within 30 s, the miner reported 4.3 GH/s inside jobs and the dashboard over 1 GH/s, with no error line, no exit and no restart. PC 1's cl.exe-built worker on the same host.c serve loop ran over an hour without this.

    +

    the RTX 5090 Windows rig (RTX 5090 plus the Ryzen's integrated gfx1036), package 0.3.0 prebuilt workers. The CUDA worker compiled the pack with NVRTC (after -default-device) and mined at 124.2 MH/s, equal to the nvcc-built worker, 0 rejected, CPU re-check clean. The OpenCL worker (igneum-worker-opencl.exe --pack, path prebuilt-generic) self-tested PASS and mined correctly at 3.3 MH/s for 577 s (8 accepted blocks), then from about 600 s every job "completed" in 0.5 ms with no hash: 906 jobs became 56,384 within 30 s, the miner reported 4.3 GH/s inside jobs and the dashboard over 1 GH/s, with no error line, no exit and no restart. the three-card Windows rig's cl.exe-built worker on the same host.c serve loop ran over an hour without this.

    Root cause, as far as it can be stated: the AMD runtime kept answering clEnqueueNDRangeKernel, clWaitForEvents and the blocking clEnqueueReadBuffer with CL_SUCCESS while running nothing, so the loop walked its chunks at memory speed and reported the stale output buffer as a finished job. What flipped the runtime into that state at 600 s is not visible in the logs and the job path itself leaks nothing (one event per chunk, created and released; verified below). The two plausible triggers are a device reset of the integrated GPU with the runtime swallowing it (the generic path is the only one that self-tests, which reads 256 MiB back and runs the three vector warps at start; an hourly prepare would do the same work again on a second queue while jobs run) and a runtime limit reached after about 900 jobs. Neither reproduces on Apple OpenCL:

    Run on the M5 Max (Apple OpenCL 1.2, pack-a, 2^22 nonces per job)JobsJob time ms (mean, min, max)FaultsLive objects at the end
    20-minute soak of the shipped generic worker3,365412 / 305 / 5910not counted (that build had no counters)
    1,200-job soak of the hardened worker (events and buffers counted)1,200411 / 315 / 54900 events, 4 buffers (cache, dataset, out, init words); 1,200 events created and released
    the same worker with IGNEUM_FAULT_TEST=6 (the dispatch skipped from chunk 6 on, the runtime "succeeding")6 real + 11: the output buffer is unchanged since the previous dispatch, exit 3

    So the fix is defensive at three levels (commit 112acf6 and vendor devnet-v4 f9392600): the worker treats every OpenCL error in the job path as fatal, requires CL_COMPLETE on the dispatch event, refuses a chunk 20x faster per nonce than the running mean or an output buffer unchanged since the previous dispatch, prints live object counts every 200 jobs and exits 3 on any of these; the miner kills and restarts a worker whose job time per hash drops under 1/20 of the mean or whose interval rate exceeds 10x the mean before it, rolls its counters back to the last report and prints WORKER FAULT; the launcher shows worker fault and restarting for that card instead of a rate. The next gfx1036 run says which guard fires first; that line is the diagnosis the Apple M5 Max cannot give.

    -

    4 October 2026, a node 60 s behind the clock is silently dead (PC 2's first app install)

    -

    PC 2 came back from a power cut with its clock 60 s slow. igneumd connected, then logged HandleRelayInvsFlow flow error: the block timestamp is too far into the future: block timestamp is ... but maximum timestamp allowed is ... for every relayed block, processed 0 blocks and the app sat on "waiting for a peer" with nothing to say. The consensus rule is right (a header may not be ahead of the node's clock by more than the tolerance, check_block_timestamp_in_isolation); the reporting was not. The node prints one WARN per relayed block with two millisecond numbers and never the one line a person needs.

    +

    4 October 2026, a node 60 s behind the clock is silently dead (the RTX 5090 Windows rig's first app install)

    +

    the RTX 5090 Windows rig came back from a power cut with its clock 60 s slow. igneumd connected, then logged HandleRelayInvsFlow flow error: the block timestamp is too far into the future: block timestamp is ... but maximum timestamp allowed is ... for every relayed block, processed 0 blocks and the app sat on "waiting for a peer" with nothing to say. The consensus rule is right (a header may not be ahead of the node's clock by more than the tolerance, check_block_timestamp_in_isolation); the reporting was not. The node prints one WARN per relayed block with two millisecond numbers and never the one line a person needs.

    WhatWhereNow
    The app reads that WARN, takes block timestamp - maximum allowed as a lower bound and shows "Your clock is at least N seconds behind the network; mining cannot start until it is fixed" on the node card with a Sync clock button (macOS sntp -sS time.apple.com under an administrator prompt, Windows w32tm /resync elevated, Linux chronyc makestep / timedatectl) and the manual stepsapp/igneum-app/src/engine.rs node_line, resolve_clock; platform.rs sync_clockdone
    Independent of the node: once blocks arrive the engine samples the latest block's timestamp through the node's Ethereum JSON-RPC every 10 s and takes the median of local minus block time over the last 9 (behind only; a stalled chain reads as ahead); and an HTTPS Date header from the downloads host at start and every 10 min (either direction, 1 s resolution). Over 5 s: a warning. Over 10 s (the consensus bound): the Start button is blocked and running miners are heldengine.rs watch_line, update.rs latest_block_time, https_timedone
    The node itself should log one clear line at WARN, once, not per block: clock skew: local time is N s behind the median peer block time (and the same for ahead, when its own templates are refused by peers). Filed for the devnet-v4 worktree owner; the app does not patch the nodedocs/plans/node-changes.mdfiled

    Checked on the Apple M5 Max with a fake 60 s skew (IGNEUM_APP_FAKE_SKEW=-60): the banner, the node card, the blocked Start button and the held miner all showed; with the real clock the HTTPS source read +0.4 s and the block source agreed.

    -

    4 October 2026, first machine on the Igneum Miner app: PC 2's RTX 5090 at 118 MH/s, via Setup.exe

    +

    4 October 2026, first machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe

    the maintainers' second PC (a clone of the first; the app's per-install machine id 1ccfe586 keeps its keys apart), installed from the runner-built Igneum-Miner-Setup-0.3.0.exe (unsigned, SmartScreen "run anyway"), the one-click package: prebuilt NVRTC worker, no toolchain on the machine. First attempt sat at "waiting for peer": the RTX 5090 machine's clock was 62 s slow after a power cut and igneumd rejected every relayed block ("the block timestamp is too far into the future"; the 10-s skew bound from the hardened timestamp rule) and processed 0 blocks for 12 minutes with no visible reason. Clock set by hand; the node caught up (46 blocks in the next 10 s at 11:27:53 UTC), the 5090 started inside the app and ran at 117 to 119 MH/s with 34 accepted blocks in the first minute, CPU re-check OK on every share, the integrated AMD chip at 3.3 MH/s beside it. Two defects from the run, both fixed in the app the same hour: no clock-skew warning (now detected from the node's warning, block timestamps and an HTTPS Date header; Start is blocked above 10 s), and the node card stayed on "syncing" after the late catch-up while the miner was already accepted (state now re-derived every poll).

    4 October 2026, difficulty rule v2: the live oscillation, its cause, the DAG replay, the fix behind a height switch (consensus-engineer)

    -

    Machine: Apple M5 Max shared with four other agents' builds (load average 7 at the start, 184 to 442 from 11:40 UTC on); every simulation and build at nice 19, cargo at 4 jobs; the live devnet (26610/26611, 26640/28640, observer.mjs, the Metal miner) untouched, read through the observer node's wRPC only. Worktree vendor/igneum-node-v4, branch devnet-v4, built in its own target/. Everything in docs/analysis/difficulty-2026-10-04-oscillation.md; ledger M24; spec 2.3 revised. Live finding (devnet v4, UTC): PC 1 (RTX 5090, 122 MH/s, 8 identities through its own node) with the Apple M5 Max (26.7 MH/s) and a Radeon (2.8) from 09:11; PC 2 (RTX 5090, 124 MH/s, 8 identities through the Apple M5 Max node) from 10:12:17, off 10:31:25 to 10:35:19; both PCs restarted at 11:00 for the machine-id package (they are clones with one computer name and had signed with the same vote keys). Difficulty (node convention): flat 56.7M to 67M within 1% per minute from 09:24 to 10:04; 70M to 144M in 90 s after the join; then 101.8M to 164.3M from 10:17 to 10:32 (5 peaks of 1.33x spaced 132 chain blocks, std of log difficulty 0.123, 54 to 81 blocks a minute) and 103M to 150M from 10:37 to 10:54 (4 peaks of 1.35x, std 0.072, a floor rising 110M to 127M) against a true 139M; after the epoch boundary at DAA 7,200 (11:01:52) 69.0M to 72.7M within 1.3% per minute. Stacked clamps in the observer's 2-s polls: "up 15.9%" = five 3% hardens, "down 24.3%" = three 10% eases. DAG: 6,741 blocks to 10:54, 38% of chain blocks merging two or more blues, every merged block blue. Records sim/difficulty/records/live-2026-10-04.csv (8,090 headers, pull_live.py) and live-2026-10-04-hashrate.csv (587 worker STATUS lines from the log intake, by run id and node). Cause: spec 2.3's reference lane is the whole epoch, so a step 7 minutes into the hour left it polluted for the hour; the short lane read 11 to 25% above it; the 25% trigger flipped on the short lane's noise; the clamps turned each flip into a ramp. The DAG's bursts widen the short lane's noise and the stacked clamps steepen each flip; neither starts it. The 3 October simulator stepped at epoch boundaries, so it never saw it. Replay: sim.py --live, a DAG model (miners on two nodes with igneum-miner's template staleness, templates stamped by the node, GHOSTDAG, the rule as igneum_difficulty_bits runs it, the sampled window per mergeset), one scale fitted to the merge fraction. Join window 10:20 to 10:31, 3 seeds: std of log difficulty 0.115 against the record's 0.134, 4.3 peaks of 1.31x against 4 of 1.37x, 110.7M to 167.2M against 101.8M to 164.3M, 56.7 to 73.7 blocks a minute against 59 to 72, 22 lane flips, the short lane ruling 38% of the time. Whole polluted window: 0.118 against 0.123, 5.3 peaks against 5. The chain-only simulator with a 1.85x step 10 minutes into an epoch: std 0.136 to 0.189 with 96 to 142 flips (v1). Candidates on the live replay (join window, 3 seeds, std of log difficulty / lane flips): v1 0.115 / 22; short lane 240 0.125 / 10; 360 0.107 / 11; ease clamp 3% 0.113 / 20; clamp once per DAA second 0.132 / 21; hysteresis leave at 10% 0.090 / 2 (short lane ruling 78%); median of three 0.124 / 15; soft trigger 0.110 / 13; reference window 1,200 0.108, 900 0.081, 720 0.055, 600 0.024 / 0, 480 0.021 / 0. Adopted: v2 = the reference lane is the epoch lane over the newest 600 DAA score of the epoch, the sampled long lane not consulted: 0.026 / 0, mean 142.6M against 139M true; rejoin window 0.031 / 0; chain-only 0.022 to 0.081. Cost (synthetic set seed 7, v1 / v2): x50 settled 61.7 / 65.5 s (standard under 90), /50 628 / 753 s (worst gap 32 / 62 s), epoch +-30% settled 144 / 143 s, hop10 211 / 200 s, polluted overshoot 0.180 / 0.089, warm-ups equal, steady std 0.038 / 0.049 with blocks-per-minute CV 0.135 / 0.130. Attacks (seeds 7 to 9, v1 / v2): greedy hopper at most +1.5% / +2.5%, with a 60 s dwell -4.0% / -1.5% at 100%; pulsed rental -96.4% / -96.3% with weight per hash 0.262 / 0.262; forger drift +0.4 to +1.1% / -0.8 to +0.5% (worst seed 2.7% / 1.5%); short-lane oscillation gain 3.75 / 3.29; epoch games 0.0 to +0.7% / 0.0 to +0.4%; polluted window settled 287 to 329 s / 288 to 331 s; base profiles 3-seed up50 154 / 150 s, down50 762 / 822 s, epoch30 88 / 88 s, hop10 245 / 233 s, polluted 75 / 76 s, steady std 0.042 / 0.053. Implementation (devnet-v4): difficulty_v2_activation_daa in Params (every network u64::MAX), OverrideParams, override_params, the daemon's file parser (prints the height), SampledDifficultyManager (new field, reference_window(daa_score, epoch_blocks, activation)), REF_WINDOW_V2 = 600, IgneumInputs.k_ref; infra/fast-time/override-60x.json carries the field as never. cargo test --release -p kaspa-consensus --lib difficulty: 15 pass (12 of 3 and 4 October plus reference_window_switches_at_the_activation_height, v2_reference_window_follows_a_step_inside_the_epoch_where_v1_eases_into_it, v1_and_v2_agree_in_a_steady_epoch); -p kaspa-consensus-core --lib params: 7 pass (override_params_carry_the_difficulty_v2_activation, the fast-time file test extended). Build 2 min incremental for igneumd and igneum-miner. Test network (sim/difficulty/testnet_v2.py, 3 nodes on 29600 to 29622, the 60x file with the devnet epoch, genesis bits 2^16, activation 900 on nodes 1 and 2, node 3 without it; CPU miners A from 0, B from minute 4, off at 19, back at 23): node 1 reached DAA 900 at 1,022 s; node 3 rejected the first v2 block ("difficulty of 520437997 is not the expected value of 520406991"), banned its peer and stayed at DAA 900 (901 headers, a prefix of node 1's 1,472); nodes 1 and 2 agreed on every header and the sink. Under v2 the leave eased 6,589 to 5,972 over 180 s (std 0.036, no peak), the rejoin hardened 6,154 to 8,312 within 60 s and held within 3%. The v1 phase is not readable: the load swung the CPU miners' delivered hash rate 2x on its own (difficulty fell 40% after B joined). Record records/testnet-v2-2026-10-04.csv. Repeat on a quiet machine, 30 minutes. Rollout: only igneumd changes (the Apple M5 Max build, infra/cross/build-linux.sh for the seed and the the cloud provider nodes, the Windows package for PC 1's node); every node of a chain needs the same "difficulty_v2_activation_daa": N in its override file before the height or it forks off there. First the 12 the cloud provider nodes on their own chain (N = current DAA + 1,800, restart one by one, a miner joins inside an epoch, no flips after the height), then the devnet with N about two hours ahead: observer node, seed, Mac node 1, PC 1's node, in that order, by the maintainers. A new network sets 0. Not done: a quiet-machine test-network run; the DAG model's red blocks and the Apple M5 Max's log series; v2 with +-500 ms stamp jitter.

    +

    Machine: Apple M5 Max shared with four other agents' builds (load average 7 at the start, 184 to 442 from 11:40 UTC on); every simulation and build at nice 19, cargo at 4 jobs; the live devnet (26610/26611, 26640/28640, observer.mjs, the Metal miner) untouched, read through the observer node's wRPC only. Worktree vendor/igneum-node-v4, branch devnet-v4, built in its own target/. Everything in docs/analysis/difficulty-2026-10-04-oscillation.md; ledger M24; spec 2.3 revised. Live finding (devnet v4, UTC): the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (RTX 5090, 122 MH/s, 8 identities through its own node) with the Apple M5 Max (26.7 MH/s) and a Radeon (2.8) from 09:11; the RTX 5090 Windows rig (RTX 5090, 124 MH/s, 8 identities through the Apple M5 Max node) from 10:12:17, off 10:31:25 to 10:35:19; both PCs restarted at 11:00 for the machine-id package (they are clones with one computer name and had signed with the same vote keys). Difficulty (node convention): flat 56.7M to 67M within 1% per minute from 09:24 to 10:04; 70M to 144M in 90 s after the join; then 101.8M to 164.3M from 10:17 to 10:32 (5 peaks of 1.33x spaced 132 chain blocks, std of log difficulty 0.123, 54 to 81 blocks a minute) and 103M to 150M from 10:37 to 10:54 (4 peaks of 1.35x, std 0.072, a floor rising 110M to 127M) against a true 139M; after the epoch boundary at DAA 7,200 (11:01:52) 69.0M to 72.7M within 1.3% per minute. Stacked clamps in the observer's 2-s polls: "up 15.9%" = five 3% hardens, "down 24.3%" = three 10% eases. DAG: 6,741 blocks to 10:54, 38% of chain blocks merging two or more blues, every merged block blue. Records sim/difficulty/records/live-2026-10-04.csv (8,090 headers, pull_live.py) and live-2026-10-04-hashrate.csv (587 worker STATUS lines from the log intake, by run id and node). Cause: spec 2.3's reference lane is the whole epoch, so a step 7 minutes into the hour left it polluted for the hour; the short lane read 11 to 25% above it; the 25% trigger flipped on the short lane's noise; the clamps turned each flip into a ramp. The DAG's bursts widen the short lane's noise and the stacked clamps steepen each flip; neither starts it. The 3 October simulator stepped at epoch boundaries, so it never saw it. Replay: sim.py --live, a DAG model (miners on two nodes with igneum-miner's template staleness, templates stamped by the node, GHOSTDAG, the rule as igneum_difficulty_bits runs it, the sampled window per mergeset), one scale fitted to the merge fraction. Join window 10:20 to 10:31, 3 seeds: std of log difficulty 0.115 against the record's 0.134, 4.3 peaks of 1.31x against 4 of 1.37x, 110.7M to 167.2M against 101.8M to 164.3M, 56.7 to 73.7 blocks a minute against 59 to 72, 22 lane flips, the short lane ruling 38% of the time. Whole polluted window: 0.118 against 0.123, 5.3 peaks against 5. The chain-only simulator with a 1.85x step 10 minutes into an epoch: std 0.136 to 0.189 with 96 to 142 flips (v1). Candidates on the live replay (join window, 3 seeds, std of log difficulty / lane flips): v1 0.115 / 22; short lane 240 0.125 / 10; 360 0.107 / 11; ease clamp 3% 0.113 / 20; clamp once per DAA second 0.132 / 21; hysteresis leave at 10% 0.090 / 2 (short lane ruling 78%); median of three 0.124 / 15; soft trigger 0.110 / 13; reference window 1,200 0.108, 900 0.081, 720 0.055, 600 0.024 / 0, 480 0.021 / 0. Adopted: v2 = the reference lane is the epoch lane over the newest 600 DAA score of the epoch, the sampled long lane not consulted: 0.026 / 0, mean 142.6M against 139M true; rejoin window 0.031 / 0; chain-only 0.022 to 0.081. Cost (synthetic set seed 7, v1 / v2): x50 settled 61.7 / 65.5 s (standard under 90), /50 628 / 753 s (worst gap 32 / 62 s), epoch +-30% settled 144 / 143 s, hop10 211 / 200 s, polluted overshoot 0.180 / 0.089, warm-ups equal, steady std 0.038 / 0.049 with blocks-per-minute CV 0.135 / 0.130. Attacks (seeds 7 to 9, v1 / v2): greedy hopper at most +1.5% / +2.5%, with a 60 s dwell -4.0% / -1.5% at 100%; pulsed rental -96.4% / -96.3% with weight per hash 0.262 / 0.262; forger drift +0.4 to +1.1% / -0.8 to +0.5% (worst seed 2.7% / 1.5%); short-lane oscillation gain 3.75 / 3.29; epoch games 0.0 to +0.7% / 0.0 to +0.4%; polluted window settled 287 to 329 s / 288 to 331 s; base profiles 3-seed up50 154 / 150 s, down50 762 / 822 s, epoch30 88 / 88 s, hop10 245 / 233 s, polluted 75 / 76 s, steady std 0.042 / 0.053. Implementation (devnet-v4): difficulty_v2_activation_daa in Params (every network u64::MAX), OverrideParams, override_params, the daemon's file parser (prints the height), SampledDifficultyManager (new field, reference_window(daa_score, epoch_blocks, activation)), REF_WINDOW_V2 = 600, IgneumInputs.k_ref; infra/fast-time/override-60x.json carries the field as never. cargo test --release -p kaspa-consensus --lib difficulty: 15 pass (12 of 3 and 4 October plus reference_window_switches_at_the_activation_height, v2_reference_window_follows_a_step_inside_the_epoch_where_v1_eases_into_it, v1_and_v2_agree_in_a_steady_epoch); -p kaspa-consensus-core --lib params: 7 pass (override_params_carry_the_difficulty_v2_activation, the fast-time file test extended). Build 2 min incremental for igneumd and igneum-miner. Test network (sim/difficulty/testnet_v2.py, 3 nodes on 29600 to 29622, the 60x file with the devnet epoch, genesis bits 2^16, activation 900 on nodes 1 and 2, node 3 without it; CPU miners A from 0, B from minute 4, off at 19, back at 23): node 1 reached DAA 900 at 1,022 s; node 3 rejected the first v2 block ("difficulty of 520437997 is not the expected value of 520406991"), banned its peer and stayed at DAA 900 (901 headers, a prefix of node 1's 1,472); nodes 1 and 2 agreed on every header and the sink. Under v2 the leave eased 6,589 to 5,972 over 180 s (std 0.036, no peak), the rejoin hardened 6,154 to 8,312 within 60 s and held within 3%. The v1 phase is not readable: the load swung the CPU miners' delivered hash rate 2x on its own (difficulty fell 40% after B joined). Record records/testnet-v2-2026-10-04.csv. Repeat on a quiet machine, 30 minutes. Rollout: only igneumd changes (the Apple M5 Max build, infra/cross/build-linux.sh for the seed and the the cloud provider nodes, the Windows package for the three-card Windows rig's node); every node of a chain needs the same "difficulty_v2_activation_daa": N in its override file before the height or it forks off there. First the 12 the cloud provider nodes on their own chain (N = current DAA + 1,800, restart one by one, a miner joins inside an epoch, no flips after the height), then the devnet with N about two hours ahead: observer node, seed, Mac node 1, the three-card Windows rig's node, in that order, by the maintainers. A new network sets 0. Not done: a quiet-machine test-network run; the DAG model's red blocks and the Apple M5 Max's log series; v2 with +-500 ms stamp jitter.

    4 October 2026, the observer stored nothing for 78 minutes, then 7,022 blocks in two minutes

    -

    Mac, load average 200 to 300 from other agents' simulations (uptime at 13:21 UTC: 83 / 224 / 206). The observer (tools/observer/observer.mjs, reading the Apple M5 Max's non-mining peer on wRPC 28640) kept writing live_state every 2 s, so the page said LIVE with age_s 0.1 while its newest stored block was 4,868 s old; the DAG panel showed "waiting for the first block" and one identity while PC 1 mined at 122 MH/s.

    +

    Mac, load average 200 to 300 from other agents' simulations (uptime at 13:21 UTC: 83 / 224 / 206). The observer (tools/observer/observer.mjs, reading the Apple M5 Max's non-mining peer on wRPC 28640) kept writing live_state every 2 s, so the page said LIVE with age_s 0.1 while its newest stored block was 4,868 s old; the DAG panel showed "waiting for the first block" and one identity while the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) mined at 122 MH/s.

    Measured from live_blocks (received_at minus the header timestamp, UTC):

    WindowBlocks storedMean lag sMax lag s
    11:30 to 11:55, five-minute slots150 to 451 each4 to 1112 to 61
    11:57 to 13:150
    13:15 slot (the restart at 13:18)7,0232,4874,911
    13:20 slot1351084

    The 7,022 catch-up blocks carried header times spread evenly over the gap (66 to 95 per minute by header time), and blocks_per_minute was bucketed by processing time, so the hour chart showed 3,762 and 3,260 for 13:18 and 13:19 against a true 76 and 63. The lag was already 4 to 11 s on average before the gap, and the observer's colour marking from this morning did a getBlock per chain block inline on the same timers as the block flush.

    What changed (commit "Observer: decoupled ingest, lag metric, per-minute by header time, feed self-check, restart loop"):

    ChangeWhereMeasured after
    Notifications only enqueue; a drain loop handles them in bounded batches; block flush, colour marking and certificate work on separate timers, none waits on anotherobserver.mjsqueue_depth 0
    Mergesets taken from each notification's verbose data (bounded cache of 4,000); getBlock only on a miss, four in flightobserver.mjs0 RPC fetch failures in the first 5 min
    live_state.observer_lag_s (now minus newest stored header time) and queue_depth; served by /api/live; the page shows "observer N s behind" past 30 s instead of "waiting for the first block"observer.mjs, site/api/live.mjs, site/live.htmllag 0.7 s at 13:27 UTC
    blocks_per_minute and blocks_60s bucketed by the block's own timestamp, reseeded from the table on startobserver.mjs13:18 = 76, 13:19 = 63; max in the hour 110
    Self-check: no blockAdded for 60 s while the node's block_count advances resubscribes; two failed attempts exit 2observer.mjsnot yet triggered
    tools/observer/run.sh: restart loop, same env and log (/tmp/igneum-devnet/observer-mjs-v4.out)newrunning since 13:26 UTC

    Open: the gap itself. Zero blocks for 78 minutes followed by every missed block arriving with its original header time is also what a stalled observer node delivering its own catch-up looks like; the lag metric now makes either case visible on the page within 30 s, and the self-check covers the dead-subscription case. Node logs for 11:57 to 13:18 UTC would settle which it was.

    -

    4 October 2026, PC 2 at the 14:20 boundary: a worker stuck on the previous epoch (root cause from the uploads)

    -

    Run win-1ccfe586-20261004-132055 (the Igneum Miner app, package 0.3.0 workers). Sequence from the node and miner uploads: the app reinstalled and its node restarted at 13:20:29 UTC in IBD from DAA 17,881, inside epoch 4 (seed 57ac7663...); the app exported packs\devnet from that node's template at once, so both workers started on 57ac. The boundary at DAA 18,000 passed about a minute later. The CUDA miner's first templates still carried next_epoch_seed c23e65dd... within lead: PREPARE sent at 14:20:57, prepared 0.9 s later (NVRTC 151 ms, cache 68, dataset 113, self-test 511 ms), switched to the prepared pair at 14:21:28, then 60 MH/s with 8 identities and 101 accepted blocks in 271 s. The OpenCL worker reported ready 43 s after the CUDA one (14:21:39); by then every template was on c23e as the current pair and no next epoch was within lead, so the miner never sent a prepare, and the worker answered 514 jobs in a row with epoch seed mismatch (one every 0.5 s, the miner's error back-off) for the rest of the run. The message text "holds prepared epoch 57ac..." is host.c's wording for a pack read at run time, which is why the stuck worker looked like a wrong prediction: PC 2's node announced the same next epoch (c23e) as the chain. No node on this PC predicted a different epoch, and the 57ac pack was simply the previous epoch's. Fixes: devnet-v4 miner 3bfe346f (prepare the current pair after a need line or three mismatches; exit 42 without prepare support; restart a ready worker with jobs queued and no job done for 60 s), workers emit need <epoch> <day> before the error. Not measured here: the swap time of the forced prepare on the RTX 5090 machine; the OpenCL run's "2 jobs in 154 s" were the two jobs before the first mismatch and are not a rate.

    +

    4 October 2026, the RTX 5090 Windows rig at the 14:20 boundary: a worker stuck on the previous epoch (root cause from the uploads)

    +

    Run win-1ccfe586-20261004-132055 (the Igneum Miner app, package 0.3.0 workers). Sequence from the node and miner uploads: the app reinstalled and its node restarted at 13:20:29 UTC in IBD from DAA 17,881, inside epoch 4 (seed 57ac7663...); the app exported packs\devnet from that node's template at once, so both workers started on 57ac. The boundary at DAA 18,000 passed about a minute later. The CUDA miner's first templates still carried next_epoch_seed c23e65dd... within lead: PREPARE sent at 14:20:57, prepared 0.9 s later (NVRTC 151 ms, cache 68, dataset 113, self-test 511 ms), switched to the prepared pair at 14:21:28, then 60 MH/s with 8 identities and 101 accepted blocks in 271 s. The OpenCL worker reported ready 43 s after the CUDA one (14:21:39); by then every template was on c23e as the current pair and no next epoch was within lead, so the miner never sent a prepare, and the worker answered 514 jobs in a row with epoch seed mismatch (one every 0.5 s, the miner's error back-off) for the rest of the run. The message text "holds prepared epoch 57ac..." is host.c's wording for a pack read at run time, which is why the stuck worker looked like a wrong prediction: the RTX 5090 Windows rig's node announced the same next epoch (c23e) as the chain. No node on this PC predicted a different epoch, and the 57ac pack was simply the previous epoch's. Fixes: devnet-v4 miner 3bfe346f (prepare the current pair after a need line or three mismatches; exit 42 without prepare support; restart a ready worker with jobs queued and no job done for 60 s), workers emit need <epoch> <day> before the error. Not measured here: the swap time of the forced prepare on the RTX 5090 machine; the OpenCL run's "2 jobs in 154 s" were the two jobs before the first mismatch and are not a rate.

    4 October 2026, shard proving on the RTX 5090: a full shard compressed in 10.9 s, a two-shard block aggregated in 2.2 s, all verified

    -

    Machine: the maintainers' PC 2 (RTX 5090, 32,607 MiB; WSL2 Ubuntu 24.04, SP1 v6.8.1 with the cuda feature, the toolchain of the 4 October morning run in ~/igneum-prove), the Igneum Miner app (machine id 1ccfe586) stopping its miners for the run. Delivered as the signed job shard-benchmark (app/igneum-app/src/jobrun.rs, packaging/ota/publish-jobs.sh), which runs prove-shard.sh block-338-shard1 "block-341-shards2 block-344-shards4" and reports every RESULT line to the intake as job-<id>-1ccfe586 (node tools/jobs.mjs <id>). The Mac CPU column is the 4 October entry above ("proving: devnet v4 shards"); the Apple M5 Max proved only the 200-pgas test cut, so its shard rows at S_p are the executor alone. S_p = 7,500,000 pgas provisional; the fixtures carry 6.75 M pgas per shard.

    +

    Machine: the maintainers' the RTX 5090 Windows rig (RTX 5090, 32,607 MiB; WSL2 Ubuntu 24.04, SP1 v6.8.1 with the cuda feature, the toolchain of the 4 October morning run in ~/igneum-prove), the Igneum Miner app (machine id 1ccfe586) stopping its miners for the run. Delivered as the signed job shard-benchmark (app/igneum-app/src/jobrun.rs, packaging/ota/publish-jobs.sh), which runs prove-shard.sh block-338-shard1 "block-341-shards2 block-344-shards4" and reports every RESULT line to the intake as job-<id>-1ccfe586 (node tools/jobs.mjs <id>). The Mac CPU column is the 4 October entry above ("proving: devnet v4 shards"); the Apple M5 Max proved only the 200-pgas test cut, so its shard rows at S_p are the executor alone. S_p = 7,500,000 pgas provisional; the fixtures carry 6.75 M pgas per shard.

    StageApple M5 Max CPU (4 October, loaded)RTX 5090 (job id, UTC)
    shard at S_p (block-338-shard1, 6.75 M pgas): execute60.0 M cycles, 9 per pgas, 6.9 s (block-344 shard 0, the same size)60,759,590 cycles, 9 per pgas, 44 per EVM gas, 1.63 s (run-20261004-173115, 17:40:20)
    shard at S_p: core proof (prove s, bytes, verify s)not run at S_p (200-pgas shard: 83.1 s, 7,310,257 B, 0.368 s)8.3 s, 18,116,295 B, 0.564 s, VERIFIED (run-20261004-173115, 17:40:29)
    shard at S_p: compressed proof (prove s, bytes, verify s)not run at S_p (200-pgas shard: 272.3 s, 1,272,897 B, 0.075 s)10.9 s, 1,272,897 B, 0.040 s, VERIFIED (run-20261004-173115, 18:04:44)
    two-shard block (block-341-shards2): compressed proof per shardnot run11.7 s and 10.0 s, 1,272,897 B each, verify 0.039 and 0.038 s (run-20261004-173115, 18:06:50 and 18:07:00)
    two-shard block: aggregation (prove s, bytes, verify s)not run (three 200-pgas shards: 244.5 s, 1,272,909 B, 0.084 s)2.2 s, 1,272,909 B, 0.039 s, VERIFIED, shard program id and claim checked (run-20261004-173115)
    two-shard block: end to end, first shard proof to the verified block proofnot run (three 200-pgas shards: 1,139 s)24 s of GPU stages (setup 12.6 s, two compressed proofs, aggregation); 2 min 18 s wall with the proof saves (run-20261004-173115, 18:06:26 to 18:08:44)
    four-shard block (block-344-shards4, near B_p): compressed proof per shardnot run10.6, 10.7, 10.5 and 10.2 s, 1,272,897 B each, verify 0.037 to 0.039 s (run-20261004-r3-shards, 19:01:49 to 19:02:21)
    four-shard block: aggregation (prove s, bytes, verify s)not run (aggregator statement 1.66 M cycles)2.5 s, 1,272,909 B, 0.038 s, VERIFIED (run-20261004-r3-shards)
    four-shard block: end to endnot run44.5 s of GPU stages (setup 12.5 s, four compressed proofs, aggregation); the block at 27 M pgas proves in under a minute on one card (run-20261004-r3-shards)
    setup (one per program id)39.4 to 60.6 s (client plus two key setups)21.3 s first process (client 6.7, shard keys 14.6, aggregator keys 0.03); 12.6 s second process
    GPU idle wait before the run, package download and extract, build (incremental)miners stopped 17:38:56; build 58 s (sources already compiled once); job 1,789 s wall, of which 25 min 46 s was saving proofs (below); mining resumed by itself at 127 MH/s

    Job run-20261004-173115 (the run kind, prove only, as root inside the app's own WSL2 instance), log intake run job-run-20261004-173115-1ccfe586, exit 0 after 1,789 s. Fixtures captured from the devnet: block 338 (one shard at S_p, 11 transactions) and block 341 (two shards, 14 transactions). Every proof verified on the RTX 5090 machine; the three tampered witnesses per fixture (balance, storage or code, dropped account) were rejected before any proving.

    What the numbers say. One RTX 5090 turns a full shard into the 1.27 MB compressed proof the chain carries in about 11 s, and folds a block's shards into one proof in about 2 s more. Against the launch target of 20 to 60 s behind the tip, a single card has 9 s of slack on a one-shard block; a two-shard block needs two cards or two rounds. The 44 cycles per EVM gas and 9 cycles per prover gas are the first measured constants for the prover-gas schedule (spec 7, provisional S_p).

    @@ -412,7 +369,7 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    Hash-rate step under v2 (hop.sh "half:4:600;all:1:600", 14:57 UTC) against the morning's v1 schedule, first 600 s of each step (results/2026-10-04/v2/compare.md): 2-min rate back within 10% of 60/min after 157 s (v1 161 s) on the step up and 172 s (v1 272 s) on the step down; neither rule holds the 3-min criterion inside 600 s on 12 CPU miners. After 300 s the v1 step-up difficulty swung 128k to 134k to 89k (max/min 1.51, std log D 0.169), the v2 one climbed 102k to 117k (1.15, 0.053); on the step down v2 reached the one-thread level (82k) by 600 s, v1 was at 100k after 600 s and 97k after 900 s. One run each, CPU miners, the v2 series has a bridged gap in its first two rows.

    Devnet: docs/plans/difficulty-v2-rollout-devnet.md. The gap found: the app launched igneumd without an override file, so an OTA-delivered v2 node would have forked at N; fixed with node_override_params in the packaged config (igneum-app.json, one NODE_OVERRIDE_PARAMS line in packaging/mac/packaged-config.sh read by both packagers; the engine writes <app data>/app/override-params.json and passes the flag). Rule: N = DAA at the manifest publish + 10,800 at least; since N is baked at the cut, choose DAA + 14,400 when committing the line and check at publish.

    4 October 2026, difficulty rule v2 activated on the live devnet at DAA 33,000 by height switch, no fresh chain

    -

    Rollout: the cloud rehearsal in the morning (12 nodes, one chain through N + 600), then the devnet. Node 1, the observer node and the seed were restarted on the v2 binary with --override-params-file carrying {"difficulty_v2_activation_daa": 33000}; the three app machines received the same height through the signed update manifest (the engine writes it to the node's override file and restarts the node at a safe moment), the two PCs within two minutes of an update-now job, the Apple M5 Max on its next check; the height had first been set to 46,500 and was moved to 33,000 at 16:55 UTC by the same route. The height passed at 17:37 UTC: node 1 and the seed shared the sink (ab6bb0a7147b at block 33,291), the observer followed, both PCs' nodes processed blocks normally, difficulty kept moving (150.8M at the height, then stepping down as PC 2's card paused for a proving job). No node forked; no restart of the chain; a consensus rule changed under a running network with miners on three platforms. The first measurement of v2 on the devnet's own regime (two large miners, bursty parallel blocks) needs PC 2 back from its job; the cloud numbers stand meanwhile (settle 157 to 272 s, no swing).

    +

    Rollout: the cloud rehearsal in the morning (12 nodes, one chain through N + 600), then the devnet. Node 1, the observer node and the seed were restarted on the v2 binary with --override-params-file carrying {"difficulty_v2_activation_daa": 33000}; the three app machines received the same height through the signed update manifest (the engine writes it to the node's override file and restarts the node at a safe moment), the two PCs within two minutes of an update-now job, the Apple M5 Max on its next check; the height had first been set to 46,500 and was moved to 33,000 at 16:55 UTC by the same route. The height passed at 17:37 UTC: node 1 and the seed shared the sink (ab6bb0a7147b at block 33,291), the observer followed, both PCs' nodes processed blocks normally, difficulty kept moving (150.8M at the height, then stepping down as the RTX 5090 Windows rig's card paused for a proving job). No node forked; no restart of the chain; a consensus rule changed under a running network with miners on three platforms. The first measurement of v2 on the devnet's own regime (two large miners, bursty parallel blocks) needs the RTX 5090 Windows rig back from its job; the cloud numbers stand meanwhile (settle 157 to 272 s, no swing).

    Third run (job run-20261004-r3-shards, 18:59 to 19:02 UTC, 3 min 22 s wall for the shard and both blocks): the buffered save closed the gap, the core proof finished at 19:00:38 and the compressed stage started at 19:00:39 UTC; shard timings repeated within 0.3 s of the first run (core 9.1 s, compressed 10.5 s). The second run (run-20261004-1912-shards) failed in its first second with a guest that returned 0 bytes of public values; the same sources executed the shard on the Apple M5 Max, and a forced rebuild of every source on the RTX 5090 machine cleared it (ledger P20 closed; the package build now has a gate).

    4 October 2026, first machine in the United States: a Windows laptop on an Intel integrated GPU, synced and voting

    A colleague's Windows laptop in the United States installed Igneum Miner 0.3.3 from the downloads link at about 18:52 UTC. Its node took the 38,000 headers and blocks from one peer, the seed node, in about eight minutes across the Atlantic. The only card is an Intel UHD integrated GPU: the OpenCL worker runs at 1.46 MH/s and found one block in its first four minutes; the identity's votes on checkpoints 1202 and 1203 were accepted by the network, so a laptop with no discrete card takes part in finality. Machine id 37ba0461 in the console; app log run win-37ba0461-20261004-185342.

    @@ -427,7 +384,7 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    What remains uncertain. (1) The v3 split's hold was observed over the last 24 s of a 150-s split (the control crossed at 126 s); a longer split under the 240-s expiry (say 200 s) would show more held checkpoints, and the "held by the frozen table" line is logged at debug, which the runs did not enable. (2) No cloud rehearsal: the 12-node the cloud provider network was destroyed at 15:30 UTC, so the 95% target is shown on three nodes with emulated 300-ms links and on the cloud logs' arithmetic, not on the cloud topology itself; the rollout plan names the re-creation and the partition experiment to run first. (3) The frozen reference is the node's own highest lock on the chain, not the certificate carried in C_i's past, so two honest nodes can test one checkpoint against tables 30 s apart; in a connected network those tables differ by a minute of blocks, under a partition both are pre-split, and no run showed a disagreement, but it is a property argued, not proved. (4) The price: a sudden departure of a third or more now pauses finality for a full window (30 days on mainnet) instead of 1.4 to 10 days; a gradual one costs nothing. the maintainers asked for the pause over the fork; the number is stated in spec 3.7 item 2. (5) The fold clock is in memory: a restarted node folds from daa(C_i) + depth, a few seconds late at worst. (6) Binaries, all from finality-fixes 6aa69a45, hashes and checks in the rollout plan's section 2: Mac native fe982a1d... (verified running), Linux 7c100fc2... (cargo-zigbuild, 34 min, not run on a Linux host), Windows cc1d1001... (mingw, 12 min 28 s, the v2 exe's DLL set, cannot run here); the Windows payload inputs were staged with push-inputs.sh --no-deploy into a scratch folder and NOT deployed (plan 7a).

    4 October 2026, miner performance: variant racing (Metal worker on the M5 Max; the RTX 5090 job is ready, not run)

    Method (docs/design/miner-tuning.md): at every hourly prepare the worker compiles the bound kernel in several variants (unroll, load path, register budget, threads per group, combinations), checks each bit for bit against the base kernel, times each for 2 s with the job loop paused, and keeps the fastest for the hour. Base is the kernel as it has always shipped. Code: proto-metal/main.swift (raceProgram, --race-test), proto-cuda/nvrtc/worker.cpp (racePair, --race), branch miner-perf, commit 460a99a.

    -

    Machine: Apple M5 Max, Darwin 25.6.0 (macOS 26.6.2), 64 GiB. CONDITIONS: the live Igneum Miner app's own Metal worker (igneum-bench --serve, pid 14687) was mining on the same GPU throughout, and the load average was 130 at the build and 14 to 67 during the races (other agents' cargo builds). The absolute MH/s below are therefore about half of the card's (the app reported 26.7 MH/s on 4 October with the GPU to itself) and each window was contended; the numbers to read are the ratios, taken as the best of three interleaved rounds per variant so the contention hits every variant alike. A re-run with the Apple M5 Max card paused is listed under "next".

    +

    Machine: Apple M5 Max, Darwin 25.6.0 (macOS 26.6.2), 64 GiB. CONDITIONS: the live Igneum Miner app's own Metal worker (igneum-bench --serve, pid <n>) was mining on the same GPU throughout, and the load average was 130 at the build and 14 to 67 during the races (other agents' cargo builds). The absolute MH/s below are therefore about half of the card's (the app reported 26.7 MH/s on 4 October with the GPU to itself) and each window was contended; the numbers to read are the ratios, taken as the best of three interleaved rounds per variant so the contention hits every variant alike. A re-run with the Apple M5 Max card paused is listed under "next".

    Command (under the measure lock, which holds the build lock too):

    tools/lock/with-lock.sh measure bash scratchpad/metal/measure.sh = swiftc -O -target arm64-apple-macos11 -o igneum-bench main.swift -framework Metal (47 s under load 130) igneum-bench --race-test --seed igneum-genesis --day 2026-10-04 --race-rounds 3 --race-bench-ms 2000 igneum-bench --race-test --seed igneum-hourly --day 2026-10-04 --race-rounds 3 --race-bench-ms 2000

    Dataset 2^28 words (1 GiB, memory-hard, built in 285 and 295 ms), batch 2^22 nonces per launch, programs by the version-2 generator (128 loads per hash, no wide loads). 14 variants, every one bit-exact with base over 2^16 nonces (no variant discarded). MH/s = best of 3 rounds, 2 s windows, first launch of each window not counted.

    @@ -435,8 +392,8 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    Race cost: compile 1,798 ms (first seed; the Metal compiler cold) and 267 ms, timing 108 s for 14 variants x 3 rounds (2 s windows plus the 2^16-nonce check); in --serve the race runs one round, about 40 s, inside a 600-DAA lead, with mining paused only inside the windows.

    Reading. On Apple silicon the win is threads per threadgroup: the Metal worker has dispatched one 32-thread group per 32 nonces since 3 October, and 256-thread groups are 17 to 21% faster on both programs under these conditions, with 128 close behind; the unroll, register-budget and size-optimisation knobs are within noise or worse on their own. The winner agrees across the two programs, so a tuning entry Apple_M5_Max: g256 would be the first fleet default; the race itself finds it in one round. These two programs are two points, under contention; the figure for the Apple M5 Max's own card with the GPU to itself is still to take. Nothing here says anything about NVIDIA: w8 (8 warps per block) is the CUDA cousin of g256, and whether the 5090 moves at all is what the RTX 5090 machine job (docs/plans/miner-perf.md) measures. Range to measure there: from no gain to what the block-size and load-path variants give on a 1 GiB random-read kernel; no claim.

    Serve-protocol check (the same binary, --serve --race-rounds 1, scripted stdin: two inline jobs on pair A, the deferred race on A, prepare of pair B with its race, jobs on A meanwhile, the swap to B, a job across the 32-bit nonce boundary): 44 jobs done, 0 errors, no found line missed; the inline compile of pair A 220 ms, the deferred race on A winner g256 14.207 base 11.404 gain +24.58% (compile 563 ms, 36 s of windows); prepared for B after 35,554 ms = program 58 ms, dataset 524 ms, race 34,972 ms (winner mt512-g256 12.807 base 10.346 gain +23.79%), the swap to B in 0.01 ms, the 64-nonce job across the 32-bit boundary 14.8 ms. Found by this check: the job queued during a race waited for the whole race (job 2 done after 35,946 ms; the mutex is not fair), so the race now pauses 150 ms after every window (commit 32d1c01). Re-check with the pause (--serve, a job every 3 s through both races, load average 134 to 183): every job during the deferred race on A and the prepare race on B finished in 0.17 to 2.8 s (33 jobs, none over 2,831 ms, versus 35,946 ms before), the race on B 39.8 s inside a 40.2 s prepare, winner g256 both times, swap 0.01 ms, 0 errors; the race's own windows were 2 to 3 s longer in total than without the pause, as expected.

    -

    NVIDIA side, what the Apple M5 Max could check: proto-cuda/nvrtc/emu/test.sh PASS on the race build (the race off under emulation, "variants 1 base only, no race (emulation)" logged per pair; 9 source checks PASS, the --serve protocol with prepare, swap and self-heal unchanged, 17 sampled hashes equal to igneum-pow hash-bound); mingw cross-compile of igneum-worker-cuda.exe with the race (build-windows.sh, mingw, static): 1,509,376 bytes, the same imports as the shipped worker (KERNEL32 and the Universal CRT), icon and version block verified; zipped as igneum-worker-cuda-race.zip (429,387 bytes, sha256 321a086e...c4c049) for the RTX 5090 machine 1 job. The race has not run on a GPU.

    -

    Next: the RTX 5090 machine 1 job (ready in docs/plans/miner-perf.md); the Apple M5 Max card paused for a clean absolute table; the Mac app's own worker on this build (its hourly prepare then races by itself and logs the TUNING record).

    +

    NVIDIA side, what the Apple M5 Max could check: proto-cuda/nvrtc/emu/test.sh PASS on the race build (the race off under emulation, "variants 1 base only, no race (emulation)" logged per pair; 9 source checks PASS, the --serve protocol with prepare, swap and self-heal unchanged, 17 sampled hashes equal to igneum-pow hash-bound); mingw cross-compile of igneum-worker-cuda.exe with the race (build-windows.sh, mingw, static): 1,509,376 bytes, the same imports as the shipped worker (KERNEL32 and the Universal CRT), icon and version block verified; zipped as igneum-worker-cuda-race.zip (429,387 bytes, sha256 321a086e...c4c049) for the the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job. The race has not run on a GPU.

    +

    Next: the the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job (ready in docs/plans/miner-perf.md); the Apple M5 Max card paused for a clean absolute table; the Mac app's own worker on this build (its hourly prepare then races by itself and logs the TUNING record).

    4 October 2026, miner fault guards and the app watchdog measured against a fake worker (miner-community-lead, app owner)

    Machine: Apple M5 Max, load average 17 to 92 (other agents' builds and runs throughout), everything at nice 19 under tools/lock/with-lock.sh run. These are recoveries and seconds, not hash rates: nothing here is a performance number. Private test networks only: one igneumd (devnet suffix 9950, ports 29950 to 29953) for the miner scenarios and the app's own private node (suffix 9960, ports 29960 and 29961) for the app scenarios; the live devnet was not touched. Worker: tools/reliability/fake-worker.mjs, a stand-in that speaks the serve protocol and misbehaves on command (jobs done in 0.3 ms, 0 hashes, silence, wrong hashes, refused prepares); it never hashes, so no block was found and the fake rate of about 157 MH/s inside jobs is an invented number. Miner: fork branch miner-reliability (aea5ac6d, 501363e0, 945153ab), igneum-miner release with --status-secs 10. App: app/igneum-app at f39e240 plus the card-message fix, IGNEUM_APP_STATUS_SECS=10. Harness: tools/reliability/run.mjs and app-run.mjs; every scenario states what must and must not appear, and the detectors were shown to fire on the faulting scenarios and stay quiet on the healthy stretches before any number below was kept.

    Miner guards (review round 4 M26, M27, X21), one fresh miner process per scenario:

    @@ -486,24 +443,24 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    G12 is covered by the digest run (the environment's schedule is part of the digest, so a devnet node with IGNEUM_POW_EPOCH_BLOCKS set cannot connect to one without it) and by env_pow_schedule_is_devnet_and_simnet_only; no mainnet node was started tonight. M31 is covered by largest_coinbase_fits_on_every_network; no simnet network was started tonight (the red team's tools/exec-attacks/net.sh is the run that would show templates on simnet without an override).

    Uncertain. (1) Every run is fast time (W = 120 DAA, ban 120, depth 20) on three nodes with 100-ms links; the mainnet values are 30 days, 30 days and 60 blocks. (2) The ban run shows one equivocation at one index; the red team's s1 (equivocation at every index, two keys) was re-run on the new build only through the red team's f23 above (0 refusals where the evening had 9 / 3 / 4). (3) The digest-less allowance on devnet and simnet is deliberate for the rollout and is a hole until removed. (4) The reorg run's final pass had the majority lock no index during the first 60 s of the split, so the re-determination at 8 and 9 was exercised, the pending-certificate path only at 10 and 11; the first pass exercised the opposite. (5) The un-determination rule has a unit test and one network pass (reorg-final2) in which the shallow-sink case did not recur, so the rule is exercised by the test, not by a run; the case needs a split whose difficulty drifts enough for blue work to overtake blue score, which happened once in four runs. (6) The red team's f24b is a window-length partition at 6 blocks/s, so it measures F21's stated limit, not F24; a 4/2 cut under 20 s at that rate would be the F24 case.

    5 October 2026, live devnet: the first shards proven, verified and paid

    -

    Proving v0 activated at DAA 84,100 (manifest consensus.override, every node restarted with the same file; a hand node restarted early with another value was refused by the digest handshake and sat isolated for 20 minutes until it was restarted with the same file). The first proof records came from PC 2's RTX 5090 (SP1 CUDA under WSL2, app 0.3.7, node 2b6d23ef) and were verified by the Apple M5 Max node's verifier (igneum-prove-host --mode verify, the only block producer with a verifier until 0.3.7 put one on every machine) and paid at the carrying chain block.

    -
    WhatMeasured
    First shard record in the pool (observer)10:51 UTC, block 94,904 on the live page, prover key e809e396, shard 0, 0 pgas (an empty shard)
    Paid shards by 10:53 UTC (Mac node igneum_getProvingStatus)3 shards, 3.370437410 IGN in total, pool balance 68,601.72 IGN
    Pool at that moment4 entries: 3 pending, 1 failed verification, 0 verified-and-waiting
    Non-empty shardsnot yet: the exporter's post-root assertion fires on blocks with content (58,584 to 58,984 on 5 October); investigation open
    The assertion, explained (12:30 UTC, branch prover-match)Not block content. Every block it fired on is empty (PC 2's export logs: 58,752 to 58,843 hit the assertion; 58,584 to 58,740 hit the backslash path of 6d51e53), one reward plus the pool credit, no transactions, no payouts. PC 2's exporter was a stale build: the panic names shard.rs:175, the line before commit 1251f0a moved the assert to 179, and that core's planner gave an empty segment the pre-root as its post-root while the statement applied the rewards (left = the node's root after the rewards, right = the root before them, as the log shows for 58,752). The core at master reproduces 58,927 and 59,192 with the node's roots, and the same shape (59,507: one reward to the same miner) was proven and paid after the 10:49 and 10:52 UTC rebuilds on PC 2. Branch prover-match: fixture block-58927-empty-reward.json, export/tests/fixtures.rs (every fixture reproduces; an empty segment ends at the root after the rewards), and a source stamp on the first line of the exporter and the host so a stale binary names itself. The guest is untouched: built in one directory, master and the branch give byte-identical loadable segments for the shard program and the aggregator (shard program id 0x1ec8b941 at master in that directory). Noted on the way: the same sources built in three directories on this Mac gave two different guest ELFs (text segment c173b3de in the main checkout and in a fresh worktree, 830f7433 in the branch's worktree, shard program id 0x366e2aca there), so the program id is not yet a pure function of the sources on a native build; SP1's docker build is the reproducible path and is not in use. Open item.
    -

    Commands: curl -X POST http://127.0.0.1:26800 -d '{"jsonrpc":"2.0","id":1,"method":"igneum_getProvingStatus","params":[]}' on the Apple M5 Max; node tools/logs.mjs for PC 2's prover lines (prover: block N shard 0 assigned to win-1ccfe586-1-1: export, cut, prove (CUDA), sign, submit).

    -

    5 October 2026, the program id split: why the Apple M5 Max rejected PC 2's proofs, and the verifier at 114 s

    +

    Proving v0 activated at DAA 84,100 (manifest consensus.override, every node restarted with the same file; a hand node restarted early with another value was refused by the digest handshake and sat isolated for 20 minutes until it was restarted with the same file). The first proof records came from the RTX 5090 Windows rig's RTX 5090 (SP1 CUDA under WSL2, app 0.3.7, node 2b6d23ef) and were verified by the Apple M5 Max node's verifier (igneum-prove-host --mode verify, the only block producer with a verifier until 0.3.7 put one on every machine) and paid at the carrying chain block.

    +
    WhatMeasured
    First shard record in the pool (observer)10:51 UTC, block 94,904 on the live page, prover key e809e396, shard 0, 0 pgas (an empty shard)
    Paid shards by 10:53 UTC (Mac node igneum_getProvingStatus)3 shards, 3.370437410 IGN in total, pool balance 68,601.72 IGN
    Pool at that moment4 entries: 3 pending, 1 failed verification, 0 verified-and-waiting
    Non-empty shardsnot yet: the exporter's post-root assertion fires on blocks with content (58,584 to 58,984 on 5 October); investigation open
    The assertion, explained (12:30 UTC, branch prover-match)Not block content. Every block it fired on is empty (the RTX 5090 Windows rig's export logs: 58,752 to 58,843 hit the assertion; 58,584 to 58,740 hit the backslash path of 6d51e53), one reward plus the pool credit, no transactions, no payouts. the RTX 5090 Windows rig's exporter was a stale build: the panic names shard.rs:175, the line before commit 1251f0a moved the assert to 179, and that core's planner gave an empty segment the pre-root as its post-root while the statement applied the rewards (left = the node's root after the rewards, right = the root before them, as the log shows for 58,752). The core at master reproduces 58,927 and 59,192 with the node's roots, and the same shape (59,507: one reward to the same miner) was proven and paid after the 10:49 and 10:52 UTC rebuilds on the RTX 5090 Windows rig. Branch prover-match: fixture block-58927-empty-reward.json, export/tests/fixtures.rs (every fixture reproduces; an empty segment ends at the root after the rewards), and a source stamp on the first line of the exporter and the host so a stale binary names itself. The guest is untouched: built in one directory, master and the branch give byte-identical loadable segments for the shard program and the aggregator (shard program id 0x1ec8b941 at master in that directory). Noted on the way: the same sources built in three directories on this Mac gave two different guest ELFs (text segment c173b3de in the main checkout and in a fresh worktree, 830f7433 in the branch's worktree, shard program id 0x366e2aca there), so the program id is not yet a pure function of the sources on a native build; SP1's docker build is the reproducible path and is not in use. Open item.
    +

    Commands: curl -X POST http://127.0.0.1:26800 -d '{"jsonrpc":"2.0","id":1,"method":"igneum_getProvingStatus","params":[]}' on the Apple M5 Max; node tools/logs.mjs for the RTX 5090 Windows rig's prover lines (prover: block N shard 0 assigned to win-1ccfe586-1-1: export, cut, prove (CUDA), sign, submit).

    +

    5 October 2026, the program id split: why the Apple M5 Max rejected the RTX 5090 Windows rig's proofs, and the verifier at 114 s

    Machine: Apple M5 Max under the live devnet node, the Metal miner and two other agents' builds (every number here is wall time under that load, taken through the measure lock). Code: proving/igneum-prove on branch program-id, SP1 6.8.1, circuit v6.1.0.

    -
    HostBuiltShard program idSource
    Mac, shipped (Igneum Miner.app/Contents/Resources/bin/igneum-prove-host, app 0.3.7)5 Oct 10:48, release tree on the Apple M5 Max0x0559759b3d8740b26ceceb2c56054b89194878ab691b018d7dd2f8af2f2242ddits own --mode verify setup line
    PC 2, WSL2 CUDA (<server path>)4 Oct 19:00Z, package sources0x05db1aca65f8ae9d585c7bd178a832d92a67275857f21c0d484a58c06dba61a3app log run-20261004-r3-shards (node tools/logs.mjs job-collect-pc2-applog-paid-1ccfe586); confirmed by the sp1_vk_digest inside its proof of block 59507 shard 0 (below)
    Mac, fresh worktree igneum-wt-programid5 Oct 12:07Z, same sources as the shipped host0x0dfade071ffc05a50be5f7e6640fb12638bac0ea63697ec252863f55658be16aigneum-prove-pin
    -

    Three builds of the same guest sources, three ids. Cause: host/build.rs compiled the guest with sp1_build::build_program on whatever machine built the host, and the guest ELF depends on where it is built. Shown by strings on the two Mac ELFs: 946 anonymous symbol names differ, and the crate hash of igneum_prove_core is Csl6o96CsXEfN_ in the main checkout against Cs5Jl7brLd39a_ in the worktree (cargo's -C metadata for a path crate includes the checkout path, and rustc's symbol names carry it); the ELFs also embed ~/.cargo/registry/... panic-location strings, which differ again on Linux. A different ELF is a different verifying key, so every verifier rejects every other machine's proof ("sp1 vk hash mismatch" inside SP1's verify_compressed), and the node log showed it as a bare NOT VERIFIED after 114 s to 138 s. Over the same window the Apple M5 Max's pool read 16 entries, 9 failed, 0 verified, 22 shards paid (included by PC 2's own node).

    +
    HostBuiltShard program idSource
    Mac, shipped (Igneum Miner.app/Contents/Resources/bin/igneum-prove-host, app 0.3.7)5 Oct 10:48, release tree on the Apple M5 Max0x0559759b3d8740b26ceceb2c56054b89194878ab691b018d7dd2f8af2f2242ddits own --mode verify setup line
    the RTX 5090 Windows rig, WSL2 CUDA (<server path>)4 Oct 19:00Z, package sources0x05db1aca65f8ae9d585c7bd178a832d92a67275857f21c0d484a58c06dba61a3app log run-20261004-r3-shards (node tools/logs.mjs job-collect-pc2-applog-paid-1ccfe586); confirmed by the sp1_vk_digest inside its proof of block 59507 shard 0 (below)
    Mac, fresh worktree igneum-wt-programid5 Oct 12:07Z, same sources as the shipped host0x0dfade071ffc05a50be5f7e6640fb12638bac0ea63697ec252863f55658be16aigneum-prove-pin
    +

    Three builds of the same guest sources, three ids. Cause: host/build.rs compiled the guest with sp1_build::build_program on whatever machine built the host, and the guest ELF depends on where it is built. Shown by strings on the two Mac ELFs: 946 anonymous symbol names differ, and the crate hash of igneum_prove_core is Csl6o96CsXEfN_ in the main checkout against Cs5Jl7brLd39a_ in the worktree (cargo's -C metadata for a path crate includes the checkout path, and rustc's symbol names carry it); the ELFs also embed ~/.cargo/registry/... panic-location strings, which differ again on Linux. A different ELF is a different verifying key, so every verifier rejects every other machine's proof ("sp1 vk hash mismatch" inside SP1's verify_compressed), and the node log showed it as a bare NOT VERIFIED after 114 s to 138 s. Over the same window the Apple M5 Max's pool read 16 entries, 9 failed, 0 verified, 22 shards paid (included by the RTX 5090 Windows rig's own node).

    Fix: the guests are pinned build artefacts (proving/igneum-prove/elf/: both ELFs, both verifying keys, manifest.json with SHA-256 hashes and ids), embedded by the host and checked at every start; --mode verify runs on SP1's light verifier with the pinned key, no prover client and no key setup; the verify line prints the id the proof was made with next to ours. Pinned set: shard 0x0dfade07...be16a, aggregator 0x135e67e7...6c62.

    -
    Verify of PC 2's proof of block 59507 shard 0 (1,272,897 bytes) on the Apple M5 MaxSetupVerifyVerdict
    Before: shipped host, ProverClient::from_env + two key setups125.82 s0.383 sNOT VERIFIED, no reason given
    Before, as the node saw it (blocks 59373 and 59402)138.6 s and 114.4 s in all0.409 s and 0.104 sNOT VERIFIED
    After: pinned key, light verifier (program-id host, same proof)2.085 s0.002 s (refused on the program id before any field arithmetic)NOT VERIFIED, program id 0x05db1aca...61a3 IS NOT OURS 0x0dfade07...be16a; 2.35 s wall, exit 3
    After, known-good case: block 56 shard 0 proven with the pinned ELF on this Mac (--mode compressed, 558,137 cycles, prove 1,066 s under load 113), verified against its real statement1.323 s0.108 sVERIFIED, program id ... (ours); 1.80 s wall, exit 0
    +
    Verify of the RTX 5090 Windows rig's proof of block 59507 shard 0 (1,272,897 bytes) on the Apple M5 MaxSetupVerifyVerdict
    Before: shipped host, ProverClient::from_env + two key setups125.82 s0.383 sNOT VERIFIED, no reason given
    Before, as the node saw it (blocks 59373 and 59402)138.6 s and 114.4 s in all0.409 s and 0.104 sNOT VERIFIED
    After: pinned key, light verifier (program-id host, same proof)2.085 s0.002 s (refused on the program id before any field arithmetic)NOT VERIFIED, program id 0x05db1aca...61a3 IS NOT OURS 0x0dfade07...be16a; 2.35 s wall, exit 3
    After, known-good case: block 56 shard 0 proven with the pinned ELF on this Mac (--mode compressed, 558,137 cycles, prove 1,066 s under load 113), verified against its real statement1.323 s0.108 sVERIFIED, program id ... (ours); 1.80 s wall, exit 0

    Before: 127.0 s wall per proof on the Apple M5 Max (the node saw 114 s to 139 s). After: 1.8 s to 2.4 s wall, under the 2 s target for the verify call itself; the remaining 1.3 s to 2.1 s is SP1's light verifier construction plus paging a 58 MB binary under load, and would shrink in a long-lived verifier process. Unit tests (cargo test -p igneum-prove-host --bin igneum-prove-host): the embedded files hash to the manifest, the embedded keys derive the manifest's ids, a changed file is refused; the ignored test re-runs SP1's setup on the embedded ELFs and gets the pinned ids. tools/ci/pinned-guests-check.sh was shown failing on an empty elf/ and passing on the pinned one.

    -

    What every machine must do: the pinned shard id 0x0dfade07...be16a differs from every id now running (Mac 0x0559759b..., PC 2 0x05db1aca...), so this is a guest change for the whole devnet, and proofs in flight at the switch are rejected by a verifier that has moved. Rollout order (proving/README.md, "Pinned guest programs"): provers off on every machine; wait until igneum_getProvingStatus shows an empty pool on every node; install the host built from this elf/ on every node (Mac DMG; PCs through igneum-prove-wsl2.zip, whose package carries elf/, so the WSL build embeds the same files); confirm igneum-prove-host --mode id prints the same shard id everywhere; provers back on. From then on a differing id is impossible without a change to the committed elf/.

    +

    What every machine must do: the pinned shard id 0x0dfade07...be16a differs from every id now running (Mac 0x0559759b..., the RTX 5090 Windows rig 0x05db1aca...), so this is a guest change for the whole devnet, and proofs in flight at the switch are rejected by a verifier that has moved. Rollout order (proving/README.md, "Pinned guest programs"): provers off on every machine; wait until igneum_getProvingStatus shows an empty pool on every node; install the host built from this elf/ on every node (Mac DMG; PCs through igneum-prove-wsl2.zip, whose package carries elf/, so the WSL build embeds the same files); confirm igneum-prove-host --mode id prints the same shard id everywhere; provers back on. From then on a differing id is impossible without a change to the committed elf/.

    5 October 2026 (afternoon), live devnet: real transactions, the first non-empty shard proven and paid, and the exporter's block structure fixed (execution engineer)

    -

    Until this run the devnet had carried no transaction at all, so every one of the 349 shards paid before 15:35 UTC was empty (0 pgas). tools/txgen/run.mjs (new; viem for EIP-1559 signing, otherwise Node 22 built-ins) funds generated wallets from the devnet dev-fee key (~/.config/igneum/dev-fee-devnet.json, keys of the generated wallets in ~/.config/igneum/txgen/wallets.json, mode 0600) and sends transfers between them at a steady rate through one node's EVM RPC; tools/txgen/proving-watch.mjs samples the proving layer during a run and builds the per-block report afterwards. Both runs went through the Apple M5 Max node (127.0.0.1:26800) under tools/lock/with-lock.sh run, with PC 2's RTX 5090 (app 0.3.8, SP1 CUDA under WSL2) as the only prover and the Apple M5 Max node as the verifier. Chain id 4463, gas price quote 3 gwei (1 gwei execution base, 1 gwei proving base at ratio 1.0, 1 gwei tip), eth_estimateGas 25,380 for a transfer.

    +

    Until this run the devnet had carried no transaction at all, so every one of the 349 shards paid before 15:35 UTC was empty (0 pgas). tools/txgen/run.mjs (new; viem for EIP-1559 signing, otherwise Node 22 built-ins) funds generated wallets from the devnet dev-fee key (<config path>, keys of the generated wallets in <config path>, mode 0600) and sends transfers between them at a steady rate through one node's EVM RPC; tools/txgen/proving-watch.mjs samples the proving layer during a run and builds the per-block report afterwards. Both runs went through the Apple M5 Max node (127.0.0.1:26800) under tools/lock/with-lock.sh run, with the RTX 5090 Windows rig's RTX 5090 (app 0.3.8, SP1 CUDA under WSL2) as the only prover and the Apple M5 Max node as the verifier. Chain id 4463, gas price quote 3 gwei (1 gwei execution base, 1 gwei proving base at ratio 1.0, 1 gwei tip), eth_estimateGas 25,380 for a transfer.

    RunWindow (UTC)WalletsSentIncludedIncluded per sLatency p50 / p90 / max (s)Blocks with contentTransfers per content block p50 / p90 / maxFailuresFees paid (IGN)
    1, master code15:37:30 to 15:57:30162,2752,161 (103 pending at the cut, all with a receipt 20 s later)1.8640.7 / 110.8 / 209598 / 92 / 22460: 49 "replacement underpriced", 10 dropped, 1 skipped (9 of the 11 executed later, see below)0.091
    2, fixed code15:59:34 to 16:14:34161,6501,633 (17 pending at the cut)1.7145.7 / 128.7 / 2534810 / 99 / 2240 (0 nonce retries, 0 deferred)0.069

    Funding: 16 wallets at 2 IGN each, 16 IGN from the dev-fee address, which held 891 IGN before and 997 IGN after (it receives 1 block reward in 100 from every fee-paying miner). The wallets end with 31.83 IGN; the whole spend of the afternoon is 16.16 IGN.

    What paced inclusion. There is no p2p relay of EVM transactions (execution-layer ledger item 9), so only blocks produced by the Apple M5 Max's own miner carry what the Apple M5 Max node's RPC received. The Mac miner had 134 blocks accepted in run 1's window and 59 of them carried transfers: the pool hands a sender's contiguous run to one template and then withholds that sender for 4 s (pool.rs HANDOUT_COOLDOWN), templates are rebuilt on every tip change (about one a second, 3,888 switches in the miner's counters), so a sender is mineable about 1 s in 5 and inclusion comes in bursts (quiet 50 s stretches, then a Mac block with 205 or 224 transfers). Measured before run 1 started: 12 of the 14 Mac blocks found while the 8 funding transfers waited 124 s were empty. The pool refuses a nonce more than 16 ahead of the account (MAX_NONCE_GAP), so 8 wallets at 2 per second would hit the gap; 16 wallets keep every queue under 14. Design rule 463 already names this cooldown as a stand-in until the executor listens to block-added.

    The two tool defects run 1 found, fixed before run 2. (1) A transaction judged "not in the pool and in no block" 90 s after the send was counted dropped and the wallet's nonce re-synced to its latest nonce; the verdict is transient around a one-block selected-chain reorg (50 in the window, one every 8 s, the carrying block is re-merged seconds later), and the re-sync made the next send reuse a nonce already queued, which the pool refused as "replacement underpriced" (49 times). Now a drop needs two such verdicts 60 s apart and every re-sync reads the node's pending nonce (eth_getTransactionCount with pending, pool.pending_nonce). The wallets' chain nonces show 2,273 of run 1's 2,275 transfers executed, so 9 of the 11 "lost" verdicts were premature. (2) "nonce gap too large" and "too many queued" are back-pressure, not nonce errors: counted deferred, no retry.

    -
    Proving during run 1 (node log 15:35:25 to 16:08:31 UTC, PC 2 app log by collect job)Measured
    Proof records accepted / verified / rejected / paid lines36 / 36 / 0 / 43 (7 records' "paid" line logged twice at the same carrying block after a reorg re-executed it; paidShards moved by exactly 36, no double payment)
    Shards with pgas > 0 among them1: block 72704 shard 0, 29 transfers, 5,800 pgas, 609,000 gas (the prover takes the newest unpaid assigned shard, prover.rs choose; content blocks were 59 of about 1,400 in the window)
    Block 72704 timelinechain block executed 15:43:29.9; PC 2 assigned 15:43:43; proven and submitted in 34 s; record accepted by the Apple M5 Max 15:44:17 (47 s after execution); verified in 2.3 s wall, 0.297 s in the verifier; paid 1.7623286 IGN at chain block 72744 (15:44:22)
    PC 2 prove+submit time, empty shards in the window (n=34)p50 28 s, 27 to 29 s; 32 to 49 s for 73166 to 73339 while the housekeeping job build-hk-tests-1 (five node suites and the app tests) ran on PC 2 from 15:54:13
    Verify wall time on the Apple M5 Max, p50 / max1.6 s / 6.8 s (the verifier itself 0.05 to 0.30 s)
    Payout per shardthe segment's pool credit, 0.8813 IGN per mergeset block (20% of the 4.407 IGN block reward), divided by its shards: 0.88, 1.76 or 2.64 IGN for 1, 2 or 3 blocks; content changes nothing in v0 (proving.rs shard_payouts)
    Content shard that failedblock 72803 shard 0: 7 copies skipped as NonceTooLow (duplicates from parallel blocks), 0 executed, 1,400 pgas; PC 2: "record refused: statement 0xa1ac35ee... is not the native statement 0xa00dfb3f... (native-execution veto)"; never proven
    Run 25 shards proven, all empty, 28 to 30 s; at 16:02:28 the coordinated 0.3.9 rollout switched PC 2's prover off (prove-off-pc2-039), so run 2 had a prover for its first 3 minutes only
    +
    Proving during run 1 (node log 15:35:25 to 16:08:31 UTC, the RTX 5090 Windows rig app log by collect job)Measured
    Proof records accepted / verified / rejected / paid lines36 / 36 / 0 / 43 (7 records' "paid" line logged twice at the same carrying block after a reorg re-executed it; paidShards moved by exactly 36, no double payment)
    Shards with pgas > 0 among them1: block 72704 shard 0, 29 transfers, 5,800 pgas, 609,000 gas (the prover takes the newest unpaid assigned shard, prover.rs choose; content blocks were 59 of about 1,400 in the window)
    Block 72704 timelinechain block executed 15:43:29.9; the RTX 5090 Windows rig assigned 15:43:43; proven and submitted in 34 s; record accepted by the Apple M5 Max 15:44:17 (47 s after execution); verified in 2.3 s wall, 0.297 s in the verifier; paid 1.7623286 IGN at chain block 72744 (15:44:22)
    the RTX 5090 Windows rig prove+submit time, empty shards in the window (n=34)p50 28 s, 27 to 29 s; 32 to 49 s for 73166 to 73339 while the housekeeping job build-hk-tests-1 (five node suites and the app tests) ran on the RTX 5090 Windows rig from 15:54:13
    Verify wall time on the Apple M5 Max, p50 / max1.6 s / 6.8 s (the verifier itself 0.05 to 0.30 s)
    Payout per shardthe segment's pool credit, 0.8813 IGN per mergeset block (20% of the 4.407 IGN block reward), divided by its shards: 0.88, 1.76 or 2.64 IGN for 1, 2 or 3 blocks; content changes nothing in v0 (proving.rs shard_payouts)
    Content shard that failedblock 72803 shard 0: 7 copies skipped as NonceTooLow (duplicates from parallel blocks), 0 executed, 1,400 pgas; the RTX 5090 Windows rig: "record refused: statement 0xa1ac35ee... is not the native statement 0xa00dfb3f... (native-execution veto)"; never proven
    Run 25 shards proven, all empty, 28 to 30 s; at 16:02:28 the coordinated 0.3.9 rollout switched the RTX 5090 Windows rig's prover off (prove-off-pc2-039), so run 2 had a prover for its first 3 minutes only

    The 72803 cause, in the exporter, not the core. The core's tx accumulator (executor.rs Carry::absorb) hashes every transaction's including miner and blue flag, skipped copies included, and the link hashes the block index; the node enumerates every mergeset block, empty ones included (exec/executor.rs), with the chain block itself last. The export (igneum_exportSegments) listed entries per block as executed-then-skipped with no position, no empty blocks and no miner on a skipped copy, and igneum-prove-export blocks_of sorted them by sequence (every skipped copy behind every executed one), merged consecutive blocks of one miner, dropped the empty blocks and gave a block of skipped copies only the previous block's miner or the zero address. Shown on the Apple M5 Max with the old exporter binary (built from master at 16:03): block 72803 rebuilt under the zero address, link_out 0x362fef10... against the node's 0x111a55ac...; block 72854 (an empty block before the 205 transfers, no skipped copy) link_out 0xd34e57b7... against the node's 0x85f27dc1..., roots equal. 72704 verified only because its transaction block came first.

    The fix, both sides ours. Fork (vendor/igneum-node-txgen, branch txgen-export, exec/src/rpc.rs): the export names the mergeset per segment ("blocks": hash, miner, blue, txCount, empty blocks included) and gives every entry "block" and "position" from the executor's boundaries (body order), skipped copies with their block's miner; records without boundaries keep the old shape. Exporter (proving/igneum-prove/export/src/main.rs blocks_of): rebuilds from those fields block for block; an old export is kept in its order and a block of skipped copies whose miner it does not name is refused instead of guessed. tools/prove-fixtures/complete-export.mjs completes an old export with the mergeset from igneum_getSegment (which names every skipped copy's block) for the fixtures. Fixtures proving/fixtures/block-72803-skipped-copies.json and block-72854-empty-block-first.json, each with <name>.node-plan.json beside it (the node's igneum_getShardPlan); export/tests/fixtures.rs check_against_node_plan asserts the cut's links, roots, gas, pgas and counts against the node's shard by shard, which the exporter-versus-core checks could not see. Known-failed shown: the old 72854 fixture under that check fails on "links (block index, block gas and pgas, tx accumulator)"; known-good: both new fixtures match the node's link_out exactly. Three unit tests on blocks_of (the 0.3.9 shape with an empty block, a skipped copy between two executed transactions and a block of skipped copies only; a count mismatch refused; the old shape kept in order and the skipped-only block refused). cargo test --release -p igneum-prove-export: 3 + 2 tests pass over 9 fixtures. The guest is untouched (no change under core/). The node side needs the 0.3.9 build and rollout; until every prover exports from a 0.3.9 node, a shard whose transaction block follows an empty block, or whose copies were all skipped, fails the veto.

    Also noted: the collect job uploads the first 256 KiB of a log file, so a tail needs --command "powershell -NoProfile -Command Get-Content -Tail 500 logs\app-....log".

    @@ -513,22 +470,22 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
    CheckCommandResult
    The node reads the switchcargo test --release -p igneum-exec on fork 2b6d23ef (this Mac, target vendor/igneum-node/target-036, 15:32:27Z to 15:36:30Z)11 passed, 0 failed, among them the_fee_switch_meters_by_the_block_daa_score
    The digest for H = 210,00020 s scratch node, override {"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}ab8847da538dead1dc10e046dfaadab3c1c35928e3748810c4e050d4a886087a
    One chain across the switchprivate simnet on the 2b6d23ef binaries, override {"fees_v1_activation_daa": 200}, tools/prove-fixtures/gen.mjs before and after DAA 200, one igneum_exportSegments dump with every segment's daaScoreone chain, 358 segments, DAA 0 to 1,121: block 51 (DAA 187, prototype, 11 transactions, 7,494,392 pgas, one shard at S_p 7.5 M) before the switch; blocks 351 (DAA 1,105, 11 transactions, 36,934 pgas, two shards at S_p 30,000) and 355 (DAA 1,117, 14 transactions, 69,292 pgas, three shards) after it; igneum_getBudgets went from provingGasLimit 0x1c9c380 to 0x1d4c0 and the base fees to 100 gwei and 10,000 gwei at the switch. Found on the way: a burst signed with a 21 gwei cap just before the switch never executed after it (the floor is 100 gwei), and under v1 a modexp bomb's proving charge (pgas x 10,000 gwei) crosses the signed budget unless the gas limit covers it (design 4.1); gen.mjs now sizes both from the node's budgets
    The port replays both sidesigneum-prove-export on that dump: every segment's state root equals the node's, prototype below 200 and v1 at and above itreplayed 358 segments from genesis; every state root equals the node's for each of the three cuts; fixtures fees-switch-prototype, fees-v1-shards2, fees-v1-shards3; igneum-prove-host --mode native on each: MATCHES, the three tamper cases REJECTED
    The pinned guest on both sidesigneum-prove-host <fixture> --mode execute on this Mac (setup 37 s, pinned: setup matches the manifest)fees-switch-prototype shard 0: 66,043,259 cycles, 44 cycles per EVM gas, 9 cycles per prototype pgas, 2.88 s; fees-v1-shards2 shard 0: 4,717,439 cycles (213 cycles per v1 pgas, 0.38 s), shard 1: 3,485,430 cycles (236 per pgas, 0.26 s); aggregator 1.4 M cycles over 2 shards; every tamper case REJECTED. Under v1 these transfer-and-modexp shards run at about a quarter of the unit (1,000 cycles per pgas): the table over-charges them, which is the safe side of design R1's calibration
    The new pinproving/igneum-prove/pin-guests.shshard program id 0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a (2,832,504 bytes), aggregator 0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896, pinned 16:20:38Z; the 0.3.8 ids (0x0dfade07..., 0x135e67e7...) are what every machine runs until 0.3.9

    Block rate for H: DAA 111,230 at 15:23Z, 112,227 at 15:40:13Z, 0.965 blocks/s; H = 210,000 is 24 h ahead of a publish before about 19:50Z on 5 October (the runbook moves it otherwise).

    5 October 2026 (night), the C4 fix: certificate-driven reorg

    -

    Owner: the consensus engineer and cryptographer agent, worktrees igneum-wt-c4 (branch c4-fix) and vendor/igneum-node-c4 (fork branch c4-fix on release-0.3.6 a24ab01a). Harness tools/finality-attacks/c4.mjs on the fast-time 3-node network (100-ms proxied links), node built on the Apple M5 Max in vendor/igneum-node/target-c4 from the fork worktree (an APFS clone of target-036), suites on PC 2 through tools/build-job.mjs. The Mac carried two other builds and the M20 live sync throughout; every figure is a count, an index or a second from the harness clock.

    +

    Owner: the consensus engineer and cryptographer agent, worktrees igneum-wt-c4 (branch c4-fix) and vendor/igneum-node-c4 (fork branch c4-fix on release-0.3.6 a24ab01a). Harness tools/finality-attacks/c4.mjs on the fast-time 3-node network (100-ms proxied links), node built on the Apple M5 Max in vendor/igneum-node/target-c4 from the fork worktree (an APFS clone of target-036), suites on the RTX 5090 Windows rig through tools/build-job.mjs. The Mac carried two other builds and the M20 live sync throughout; every figure is a count, an index or a second from the harness clock.

    The cause, in the code. processes/finality.rs: ingest_certificate verified a certificate only when its block was the node's own determination at that index (cp.hash == cert.checkpoint); any other block went to hold_pending, and nothing ever tried the pending certificate against the table at its own block. fork_choice_lock reads state.locks, which only evaluate filled, and evaluate only ever ran over the node's own determination. So a certified checkpoint off the node's chain never became a lock and never constrained the sink search, whatever spec 3.5 says. Second cause, found tonight on the harness: protocol/flows/src/v10/blockrelay/flow.rs skips a relayed block whose blue work is under the virtual's merge-depth root ("hence we are skipping it"), and the certified chain is lighter by construction, so the node on the heavier side never received the certified chain's blocks at all: in the first runs on the fixed consensus n0 held B's certificates by gossip for the whole heal window and B's blocks never arrived (n0's log shows only its own blocks "via submit block" after the reconnect).

    The fix. Fork: ingest_off_chain (verifies against voters_at of the certificate's own block, Q3 and Q5 by quorum_at from that block's past, the lock chain by off_lock_chain, then LOCKED with a FinalityLock notification and a VirtualStateProcessingMessage::Resolve nudge so the sink moves without waiting for a block); retry_pending_off_chain on every virtual change; the lock-chain guard in evaluate (a determination off the chain through the node's nearest locks never locks and never aggregates); fork_choice_lock reports a lock beyond the depth-based finality point once; wants_unknown_certified_block and the relay-flow bypass of the merge-depth skip while a pending certificate names a block the node lacks (finality_wants_blocks through ConsensusApi and the session). Not gated on finality_v3_activation_daa: rule v2 took the same pending path.

    -

    Unit tests (PC 2, job build-20261005-180827, 18:09 UTC): kaspa-consensus 97 passed, 0 failed, 3 ignored; kaspa-consensus-core 101 passed. New: a_lighter_certified_chain_wins_and_a_heavier_uncertified_one_does_not_override_it (main chain 77 blocks locks to 13, a 7-block side chain's index-14 certificate is adopted, the sink moves to the side tip with no new block, ten more main-chain blocks do not move it back, a second certificate at 14 over the main block is CONFLICTING and the lock stands, the side chain then locks 15), the_certificate_driven_reorg_holds_under_rule_v2 (the same at finality_v3_activation_daa never), a_chain_that_misses_an_adopted_lock_never_locks_here (the evaluate guard and the off-lock conflict). reorg_past_an_unlocked_checkpoint_re_determines_it_and_verifies_the_pending_certificate rewritten for the new behaviour (pending while the block is unknown, adopted when it arrives). kaspa-p2p-flows lib tests do not compile on release-0.3.6 before or after this change (nine epoch_seed_headers errors in the pruning-proof message tests; the M20 job build-20261005-172340 hit the same nine an hour earlier). Six PC 2 jobs were lost tonight to two tooling faults, both fixed in the class: igneum-ota-sign embedded | head -1 under pipefail (SIGPIPE panic, four scripts, tools/ci/signer-pipe-check.sh) and the one shared build-inputs.zip in the downloads folder (a job published while another agent's pack landed pinned that agent's sources, three times; build-job.mjs now names every job's zip).

    +

    Unit tests (the RTX 5090 Windows rig, job build-20261005-180827, 18:09 UTC): kaspa-consensus 97 passed, 0 failed, 3 ignored; kaspa-consensus-core 101 passed. New: a_lighter_certified_chain_wins_and_a_heavier_uncertified_one_does_not_override_it (main chain 77 blocks locks to 13, a 7-block side chain's index-14 certificate is adopted, the sink moves to the side tip with no new block, ten more main-chain blocks do not move it back, a second certificate at 14 over the main block is CONFLICTING and the lock stands, the side chain then locks 15), the_certificate_driven_reorg_holds_under_rule_v2 (the same at finality_v3_activation_daa never), a_chain_that_misses_an_adopted_lock_never_locks_here (the evaluate guard and the off-lock conflict). reorg_past_an_unlocked_checkpoint_re_determines_it_and_verifies_the_pending_certificate rewritten for the new behaviour (pending while the block is unknown, adopted when it arrives). kaspa-p2p-flows lib tests do not compile on release-0.3.6 before or after this change (nine epoch_seed_headers errors in the pruning-proof message tests; the M20 job build-20261005-172340 hit the same nine an hour earlier). Six the RTX 5090 Windows rig jobs were lost tonight to two tooling faults, both fixed in the class: igneum-ota-sign embedded | head -1 under pipefail (SIGPIPE panic, four scripts, tools/ci/signer-pipe-check.sh) and the one shared build-inputs.zip in the downloads folder (a job published while another agent's pack landed pinned that agent's sources, three times; build-job.mjs now names every job's zip).

    Harness, weight against work (B four keys and 70% of the weight, A two keys and 30%; at the cut A mines 0.6 and B 0.4 blocks/s; WINDOW = weight window, ban and min_daa at fast time). The 120-DAA window of the earlier runs turns every long split into F21's partition-longer-than-a-window shape once the p2p reconnect is added: n0 dials the proxy again on the connection manager's backoff, 84 to 114 s after the heal in every run tonight (the original sweep's 6 s was a short cut), so A's chain is 130 + 84 s = 128 DAA past the cut before any certificate can reach it, past its 120-DAA frozen table (v3) or its own two-thirds share of a sliding table (v2, 126 DAA at W 240 and s 0.3), and A locks alone first. With WINDOW=240 and WARM=320 the bound is 400 s (v3) or 210 s (v2) after the cut.

    RunNodeRule, W, splitB locks during the splitn0 reconnectedn0 adopted off-chainFinal chainConflictingDisagreeingVerdict
    on 90 s (the sweep's framing)c4 consensus fix, no sync hookv3, 120, 90 s0 (36 blue blocks for B, a new index needs 50)6 s0A, all three (no certificate to follow)00not the C4 shape
    v2 90 ssamev2, 120, 90 s1 (index 8)6 s0apart5 / 5 / 52n0 locked 10 alone at 18:32:42, B's certificate for 8 reached it at 18:32:43: F21's bound (63 DAA of A's own chain) crossed before the heal
    on 130 ssamev3, 120, 130 s1 (index 9)84 s0apart9 / 3 / 32n0 locked 12 alone at DAA 359, one window after lock 8 at 239, 6 s before the reconnect
    off 150 s (control)sameno certificate, 150 s096 s0A (heavier), all three; B's nodes re-determined 2 indices00PASS, as in the sweep
    on 130 s, W 240samev3, 240, 130 s2 (10, 11)114 s0 (certificates 13 and 14 pending, blocks unknown)apart00the sync gap: n0 never received a B block
    v2 130 s, W 240samev2, 240, 130 s2 (10, 11)114 s0apart, n0 locked 16 alone at 293 s0 / 1 / 10the sync gap again (n0 reconnected after v2's 210-s bound)
    v2 130 s, W 240c4 fix with the sync hookv2, 240, 130 s1 (index 12)84 s3 (12, 13, 14 within 2 s of the first B block; 11 re-determined)B, all three, A's split tip abandoned00PASS
    on 130 s, W 240samev3, 240, 130 s0 (Poisson: 52 blue blocks, the index fell just short)84 sn1 1, n2 2 (B's nodes adopted A's post-heal certificates and moved before IBD)A, all three00the mirror case; not the C4 shape
    on 140 s, W 240, addPeer at the healsamev3, 240, 140 s2 (11, 12, first at 12 s)3 s (the harness now dials through addPeer; the address goes as {ip, port})1 (12 by certificate; 11 verified on the new chain)B, all three, A's split tip abandoned00PASS

    Reading. With the consensus fix and the sync hook, a node on the heavier chain that receives a certificate for a chain it has never seen fetches that chain, verifies the certificate at its own block, locks it, moves its sink to the lighter certified chain and re-determines its own records onto it (the v2 W 240 row: 0 conflicts, 0 disagreements, every node on B's chain, which is the spec's F1 and the design's Fork choice items 1 to 4). The same holds under rule v3 with the frozen table on (the last row: B certified 11 and 12 during a 140-s split, n0 reconnected 3 s after the heal once the harness dialled through addPeer, adopted 12 by certificate and ended on B's chain with the other two, 0 conflicts, 0 disagreements). The fix does not and cannot cover a partition that outlasts the bound before the certificate arrives (rows 2, 3 and 6): there the node has already locked alone and 3.11.4 keeps that lock, the late certificate is CONFLICTING for the operator. On the live devnet (W 7,200 DAA, two hours) the bound is two hours after a side's last lock, so every partition under that heals by certificate. Raw: scratchpad c4-results-*.md, node logs c4-*-n0.log.

    5 October 2026 (evening), FUD ledger sweep round 6

    Owner: the consensus engineer and cryptographer agent, worktree igneum-wt-fud-a (branch fud-a), 15:45 to 16:40 UTC. The Mac was loaded throughout (two cargo builds, a txgen run and a fee-switch simnet by other agents; load average over 100), so every figure below is a count, an index, a byte or a number from another machine; the only millisecond figures are the browser verifier's, taken as ratios and labelled. Live reads through the Apple M5 Max node's wRPC (ws://127.0.0.1:28640) and the log intake (Neon HTTP SQL, lines split server-side), never a restart.

    Rolled-out fixes, the live evidence (F23, F24, G12, X18, M30, M31, F25, M20, M26, M27, X21). The 0.3.5 cut at 06:33 UTC (master 2054ae3, fork 20139145) carried fud-consensus, m20-pruning and miner-reliability; every reachable app machine was on the node line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation (docs/plans/release-0.3.6.md 8j, "live devnet: the first shards proven"). Node logs of the five app machines over the 10 hours to 15:45 UTC, one intake query (scratchpad fud-a/nodelines.mjs):

    -
    LinePC 1PC 2MacSam's MacUS laptopReads on
    Finality: state blob of layout 1 read and converted11111F23 (persisted state migrated, no locks lost)
    certificates refused "names N voters"00000F23
    CONFLICTING, EQUIVOCATION0, 00, 00, 00, 00, 0F23, F24
    re-determined (checkpoints 2970 and 2971 at 09:56 UTC on three machines at once; the rest at first start)78401F24
    LOCKED1,1981,2041,197683961all
    Consensus params digest at startf10a4eab...f10a4eab...f10a4eab...f10a4eab...f10a4eab...X18, G12
    consensus params digest mismatch (07:15 to 07:35 UTC, the hand node restarted early with another proving height)115465600X18
    PoW cache built (each at a node start; none at the epoch rolls of 14:29 and 15:29 UTC)55815M30
    +
    Linethe three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT)the RTX 5090 Windows rigMacSam's MacUS laptopReads on
    Finality: state blob of layout 1 read and converted11111F23 (persisted state migrated, no locks lost)
    certificates refused "names N voters"00000F23
    CONFLICTING, EQUIVOCATION0, 00, 00, 00, 00, 0F23, F24
    re-determined (checkpoints 2970 and 2971 at 09:56 UTC on three machines at once; the rest at first start)78401F24
    LOCKED1,1981,2041,197683961all
    Consensus params digest at startf10a4eab...f10a4eab...f10a4eab...f10a4eab...f10a4eab...X18, G12
    consensus params digest mismatch (07:15 to 07:35 UTC, the hand node restarted early with another proving height)115465600X18
    PoW cache built (each at a node start; none at the epoch rolls of 14:29 and 15:29 UTC)55815M30

    M31 and M20 have no live line yet: no simnet or testnet node has been started since the cut, and the Apple M5 Max node's pruning point is still genesis at DAA 113,289 (getBlockDagInfo, 16:00 UTC), so no lottery-hashed pruning proof has been served; the unit tests of the 0.3.5 and 0.3.6 suites cover both (largest_coinbase_fits_on_every_network, pruning_proof 4 passed). Miner side (M26, M27, X21), from the miner-* uploads of the 20 hours to 15:30 UTC (scratchpad fud-a/boundaries.mjs): see the M11 table; the console at 15:46 UTC shows 0 faults and 0 restarts on every card.

    M11, hourly runtime codegen on the fleet (same query, DAA 82,800 to 111,600 from each machine's 0.3.5 start; prepare = the worker's prepared total from the PREPARE sent to the answer):

    -
    MachineCompilerBoundariesSwapped with no pauseCompiled inlinePrepare total min / median / maxNotes
    PC 1, RTX 5090NVRTC 12.810100656 / 684 / 1,074 ms (nvrtc 151 to 180 ms)
    PC 1, Radeon integratedOpenCL108255.3 / 115.8 / 123.8 s (the 1 GiB dataset build on the iGPU beside today's WSL build jobs)the two inline boundaries (82,800 and 93,600) had the prepare sent 156 to 160 DAA before the boundary instead of 449
    PC 2, RTX 5090NVRTC 12.812120580 / 613 / 1,022 ms
    PC 2, Radeon integratedOpenCL121206.9 / 9.4 / 11.7 s
    US laptop, Intel UHDOpenCL7707.3 / 7.9 / 11.7 s (build 3.0 to 6.4 s)
    Mac M5 MaxMetal88034.0 / 34.9 / 37.8 s (program 0 to 444 ms; the rest is the hourly race)
    Sam's Mac M4 MaxMetal11040.3 s (one record before it went silent)
    +
    MachineCompilerBoundariesSwapped with no pauseCompiled inlinePrepare total min / median / maxNotes
    the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), RTX 5090NVRTC 12.810100656 / 684 / 1,074 ms (nvrtc 151 to 180 ms)
    the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), Radeon integratedOpenCL108255.3 / 115.8 / 123.8 s (the 1 GiB dataset build on the iGPU beside today's WSL build jobs)the two inline boundaries (82,800 and 93,600) had the prepare sent 156 to 160 DAA before the boundary instead of 449
    the RTX 5090 Windows rig, RTX 5090NVRTC 12.812120580 / 613 / 1,022 ms
    the RTX 5090 Windows rig, Radeon integratedOpenCL121206.9 / 9.4 / 11.7 s
    US laptop, Intel UHDOpenCL7707.3 / 7.9 / 11.7 s (build 3.0 to 6.4 s)
    Mac M5 MaxMetal88034.0 / 34.9 / 37.8 s (program 0 to 444 ms; the rest is the hourly race)
    Sam's Mac M4 MaxMetal11040.3 s (one record before it went silent)

    The 0.3.4 storm, for the record (M27): between 01:24 and 02:59 UTC both PCs' NVIDIA workers refused the pack for epoch 1130e9ea... (prepare-failed ...: the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT), 4,299 and 4,233 refusals at one every 0.7 s, 3,609 and 3,494 WORKER FAULT seed mismatch lines, boundaries 61,200 and 64,800 crossed by inline compile; from the 0.3.5 start 0 prepare-failed on any machine and 4 and 4 WORKER FAULT lines in all.

    -

    M11, the variant race on the RTX 5090 (docs/plans/miner-perf.md job, PC 1, miners stopped, 15:52:23 to 15:56:10 UTC, run job-run-race-5090-20261004-ae432dc7; pack ac027dca95d9d33f-20731, this hour's version 2 program; nvidia-smi before: 460 W cap of 575, 2,850 MHz, 63 C; after: 323 W, 67 C):

    +

    M11, the variant race on the RTX 5090 (docs/plans/miner-perf.md job, the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), miners stopped, 15:52:23 to 15:56:10 UTC, run job-run-race-5090-20261004-ae432dc7; pack ac027dca95d9d33f-20731, this hour's version 2 program; nvidia-smi before: 460 W cap of 575, 2,850 MHz, 63 C; after: 323 W, 67 C):

    RunVariants timedWinnerBase MH/sGainSpread across the 17Compile for 17Timing
    117 of 17 (none discarded, self-test PASS)base, 31 registers, 24 blocks per SM at 1 warp per block139.746+0.00%137.75 (ldcs, -1.4%) to 139.75300 ms112.2 s
    217 of 17base139.654+0.00%137.70 to 139.69232 ms112.3 s

    Reading: on a 1 GiB random-read kernel the 5090 does not move with block shape, load path, unroll or register budget; the two runs agree and every variant sits within 1.5% of base, so the race finds nothing on NVIDIA for this program class (the plan's "no gain" end of the range). 139.7 MH/s with the card to itself against the 141 Mhash/s projected for version 2 programs (weak-program census) is the first 5090 run of a version 2 pack, a match to 1%; the app mines the same card at 107 to 110 MH/s under its power cap and beside the Radeon worker. The Mac fleet records (node tools/tuning.mjs, 10 records on the M5 Max with the GPU to itself) also put base first (g256 at -4.2%), against the +17 to +21% for g256 measured under contention on 4 October: the race's Apple result was a contention artefact. Both results say the race should default off; it costs the Macs about 35 s of paused mining an hour (the prepare totals above).

    P3, the browser verifier in a phone-sized tab (https://igneum.network/verify/test.html, live checkpoint 3668, 16 of 21 signers, 21 headers; the built-in browser pane, mobile preset 375 x 812 with an Android user agent, then the desktop size, same tab, same Mac at load average over 100):

    @@ -542,8 +499,8 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
    RunRuleNew locks during the split A / BFirst lock A / B (s)Blue score A / B at the healSinks after the healFinal chainConflicting certificatesDisagreeing locked indices
    controlv2 (the live devnet's rule), min_daa 1204 / 3133 / 9335 / 296apart (n0 on its own)none (a finality fork, F21)1 on n01
    offno certificates (min_daa never)0 / 0none / none330 / 301one sink on all threeA's (the heavier)00; B's nodes re-determined 2 indices onto A's chain; n0 reconnected 36 s after the heal
    on, split 150 sv3 from checkpoint DAA 00 / 2none / 39326 / 313apartnone3 on n02 (n0 reconnected 66 s after the heal, A's chain past the 120-DAA table by then)
    on, split 90 sv30 / 2none / 3278 / 265apartnone3 on n02 (n0 reconnected 6 s after the heal, A's chain at about 58 DAA, inside the table)

    Reading (the NEW finding, ledger C4). With the module off GHOSTDAG alone converges on the heavier chain and the losing side's records re-determine (F24 works when the chain moves). With the module on the overlay holds during the split (A, with 30% of the frozen table, locks nothing; B locks 7 and 8) and then fails at the heal in the shipped node: B's certificates for blocks off n0's chain are "kept pending until the chain decides (no lock at this index)", n0's chain never decides because GHOSTDAG keeps its heavier tip and nothing turns the certificate into a fork-choice constraint, and once n0's last lock (index 7, DAA 209) is one window old (DAA 329) the frozen table stops applying on A's chain ("no frozen table (no lock on this chain inside the window)"), A's two keys are 100% of A's own window (B's post-cut blocks are red there) and n0 locks 10, 11, 12 alone; B's certificates for 10 and 11 then log CONFLICTING on n0 (n0 log, 16:27:04 to 16:29:54 UTC). A finality fork from a 96-s honest partition, no attacker, table intact at the heal; the 150-s run and the v2 control end the same way. The spec's fork choice ("GHOSTDAG among tips through all certified checkpoints", 3.5) is therefore implemented only for certificates over blocks already on the node's chain. Fix named in the ledger entry: verify an off-chain certificate against the table at its own block and let it constrain fork choice (a certificate-driven reorg), then re-determine. Raw: scratchpad fud-a/c4-results-*.md, node logs c4-on90-tmp/, c4-v2-control-tmp/.

    5 October 2026 (evening), the 9070 XT on the eGPU: why 17.9 MH/s, and what moved

    -

    PC 1 (ae432dc7, Windows 11, Ryzen 7 9800X3D with its gfx1036, RTX 5090 on CUDA), an AMD Radeon RX 9070 XT (gfx1201, RDNA 4) in a Sonnet Breakaway Box 850T5 over USB4, Adrenalin 26.9.2 (OpenCL driver string 3683.0 (PAL,LC), platform OpenCL 2.1 AMD-APP (3683.0)). Branch opencl-rdna4. the maintainers: "the hashrate is low" (17.9 MH/s with one worker; two workers on the card earlier gave 8.9 and 9.4).

    -

    Before, from PC 1's own app log (node tools/logs.mjs win-ae432dc7-20261005-181046, the miner's STATUS line for the card amd:1:gfx1201, 2^21-nonce jobs): hash=17.82 MH/s wall (17.83 MH/s inside jobs) ... idle=0.3%. Wall equals inside, so the host loop (template fetch, job line, read-back, scan) costs nothing measurable; the dispatch itself is slow. The worker's ready line: exchange 0 (local memory: AMD lists cl_khr_subgroups and no shuffle extension), batch 4194304, dataset-log2 28 (1 GiB), device [1] gfx1201 on the 3683.0 platform, AMD wavefront width 32. The same card was listed again as [3] gfx1201 on the older platform 3652.0 (the 32.0.21042 driver's OpenCL registration is still present after the update): that is the two-worker run.

    +

    the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (ae432dc7, Windows 11, Ryzen 7 9800X3D with its gfx1036, RTX 5090 on CUDA), an AMD Radeon RX 9070 XT (gfx1201, RDNA 4) in a Sonnet Breakaway Box 850T5 over USB4, Adrenalin 26.9.2 (OpenCL driver string 3683.0 (PAL,LC), platform OpenCL 2.1 AMD-APP (3683.0)). Branch opencl-rdna4. the maintainers: "the hashrate is low" (17.9 MH/s with one worker; two workers on the card earlier gave 8.9 and 9.4).

    +

    Before, from the three-card Windows rig's own app log (node tools/logs.mjs win-ae432dc7-20261005-181046, the miner's STATUS line for the card amd:1:gfx1201, 2^21-nonce jobs): hash=17.82 MH/s wall (17.83 MH/s inside jobs) ... idle=0.3%. Wall equals inside, so the host loop (template fetch, job line, read-back, scan) costs nothing measurable; the dispatch itself is slow. The worker's ready line: exchange 0 (local memory: AMD lists cl_khr_subgroups and no shuffle extension), batch 4194304, dataset-log2 28 (1 GiB), device [1] gfx1201 on the 3683.0 platform, AMD wavefront width 32. The same card was listed again as [3] gfx1201 on the older platform 3652.0 (the 32.0.21042 driver's OpenCL registration is still present after the update): that is the two-worker run.

    Hypotheses, each with its number (the measurement job rdna4-bench-1, 18:39:25 to 18:41:17 UTC, the card switched off in the app through POST /api/cards for key amd:1:gfx1201 only, the 5090 untouched; worker exe sha256 53c7e8c9…5403e10 built from this branch by proto-cuda/nvrtc/build-windows.sh; read back with node tools/jobs.mjs rdna4-bench-1):

    #HypothesisMeasuredVerdict
    1The dataset or program is re-sent over the eGPU link per jobNothing is re-sent: the dataset (1 GiB) and cache (256 MiB) are built on the device once per pair (info first pack ... cache 11 dataset 51 ms on the Apple M5 Max check); per 2^21-nonce job the old path sent 32 B up and read 16 MiB down; the serve A/B below puts a number on that read-backNot the cause
    2Work-group, occupancy, wave width, the exchangeclGetKernelSubGroupInfoKHR: sub-group 32 for a 32-item work-group (wave32), private memory 0 (no spills), preferred multiple 32; --group-warps 1, 2, 4, 8 = 18.024, 18.063, 18.070, 18.039 MH/s (--batches 3, 2^24, device event time); --batch-log2 21 (the app's job size) = 18.108Not the cause: the shape does not move the number
    3The wrong AMD platformThe app's worker runs on [1], the 3683.0 platform (ready line). The old platform's [3] gives 18.049 MH/s: the same. The duplicate listing is real and is the two-worker halvingNot the cause of 17.9; fixed anyway (below)
    4The card's own random-read rate--memprobe: dependent random 4-byte loads over 1024 MiB top out at 2.42 to 2.68 G loads/s from 4,096 lanes up (table below); 128 loads per hash gives a ceiling of 18.9 to 20.9 MH/s; the hash runs at 18.0 to 18.1THE CAUSE: the hash is at 87 to 95% of what this card does for this access pattern

    The memprobe on the 9070 XT (igneum-worker-opencl.exe --device 1 --memprobe, device event time, best of 3, 256 dependent steps per lane; chase = one dependent random 4-byte load per step, indep x8 = eight independent chains per lane):

    @@ -557,38 +514,38 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    Reading: the 9070 XT draws 199 W of its 304 W board rating (vendor figure) at 100% busy with the shader clock at its top, so the die is waiting on memory, which is the ceiling finding again; the fans at 657 rpm and 64 C are the card's own curve at that load, not a fault. Per watt the 5090 is 4.5x the 9070 XT on this program class (0.398 against 0.089 MH/W). The earlier per-watt claim from the board rating (304 W) would have read 0.058 MH/W; the measured number is 1.5x that.

    Is it the eGPU link? No. 2.42 G loads/s x 64 B lines = 155 GB/s of DRAM traffic, forty times what a USB4 PCIe tunnel carries (about 4 GB/s, approximate); the 1 GiB buffer sits in the card's own memory (the 4 and 64 MiB cases show the card's caches at work above it, and a buffer in host memory would run below 0.1 G/s). A PCIe slot would move the per-job read-back (16 MiB per 2^21-nonce job on the old path, now gone) and nothing else; the random-read ceiling is the card's. What a PCIe slot would give: the same 18 MH/s.

    What changed on opencl-rdna4 (proto-opencl/host.c, app/igneum-app/src/detect.rs):

    -
    ChangeBeforeAfter
    Duplicate platform--list showed the card twice ([1] 3683.0 and [3] 3652.0); the app made two cards and ran two workers (8.9 + 9.4 MH/s)the older platform's entry prints as dup [3] ... hidden, use [1], the default pick skips it, the app's parser (parse_opencl_list, 3 tests) never makes a card of it; --device 3 still works for comparison. Verified on PC 1: platforms: 2 device(s) hidden ..., cards amd:0:gfx1036 and amd:1:gfx1201 only
    Kernel reportwork-group and local memoryplus preferred multiple, private memory (spills), sub-group size on every exchange path (info kernel: in serve mode)
    Read-back per dispatch8 B per nonce (16 MiB per job) and a host scan of 2^21 wordsa GPU select pass: the hits (index, hash) behind an atomic counter plus 34 sentinel words; 276 B per chunk plus 16 B per hit; found lines in nonce order; --readback full / IGNEUM_READBACK=full keeps the old path; a chunk with over 256 hits falls back to the full read
    Transfer accountingnonebytes up and down per chunk and the mean device time of kernel, select, read-back and scan in the stats line every 200 jobs and at quit
    --memprobenonethe tables above, no pack needed
    +
    ChangeBeforeAfter
    Duplicate platform--list showed the card twice ([1] 3683.0 and [3] 3652.0); the app made two cards and ran two workers (8.9 + 9.4 MH/s)the older platform's entry prints as dup [3] ... hidden, use [1], the default pick skips it, the app's parser (parse_opencl_list, 3 tests) never makes a card of it; --device 3 still works for comparison. Verified on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT): platforms: 2 device(s) hidden ..., cards amd:0:gfx1036 and amd:1:gfx1201 only
    Kernel reportwork-group and local memoryplus preferred multiple, private memory (spills), sub-group size on every exchange path (info kernel: in serve mode)
    Read-back per dispatch8 B per nonce (16 MiB per job) and a host scan of 2^21 wordsa GPU select pass: the hits (index, hash) behind an atomic counter plus 34 sentinel words; 276 B per chunk plus 16 B per hit; found lines in nonce order; --readback full / IGNEUM_READBACK=full keeps the old path; a chunk with over 256 hits falls back to the full read
    Transfer accountingnonebytes up and down per chunk and the mean device time of kernel, select, read-back and scan in the stats line every 200 jobs and at quit
    --memprobenonethe tables above, no pack needed

    Correctness: proto-opencl/test-generic.sh on the Apple M5 Max (Apple OpenCL) PASS on both paths: "15 sampled hashes (both packs, both sides of the 32-bit nonce boundary) equal igneum-pow hash-bound"; select path transfers 5 chunks, up 180 B, down 4452 B, full path up 160 B, down 1536 B (the check's jobs are 32 to 64 nonces with every nonce a hit). The bench on the 9070 XT: cache check PASS, dataset self-test PASS, 6 of 6 vector warps PASS, batch fingerprint 3cc4fbf90fa6366c at 2^24 for the devnet pack (the Apple OpenCL value in the README), at every --group-warps.

    The serve-mode A/B on the card (job rdna4-serve-4, 19:11 UTC, card off in the app, worker exe sha256 324a6d9b…2bfdfff; 200 real job lines of 2,097,152 nonces each, the app's --job-nonces, against the emulator test pack pack-a (epoch edc4fa84…, self-test PASS, 96 of 96 vector lanes), target 0000100000000000 so that 408 hits fall in 200 jobs on both paths; done ms over jobs 11 to 200; node tools/jobs.mjs rdna4-serve-4):

    Read-backBytes down per jobKernel (device, mean)Select passRead-back (wall)Host scanMean jobInside-job rate
    full (before)16,777,216116.12 ms07.28 ms0.55 ms124.22 ms16.88 MH/s
    select (after)309116.00 ms0.039 ms0.78 ms0.00 ms117.38 ms17.87 MH/s
    select (repeat)309115.96 ms0.038 ms0.76 ms0.00 ms117.33 ms17.87 MH/s

    Reading: the kernel is the same 116.0 ms on both paths (18.08 MH/s pure kernel, the bench's number). The old path paid 7.8 ms per job for 16 MiB over the eGPU link (2.3 GB/s, the USB4 tunnel's rate; a PCIe slot would read it in about 1 ms, approximate) and the host scan. The select pass removes it: +5.9% per job on this link, nothing on the kernel. Both paths found the same 408 hits. The --group-warps and exchange levers were already shown flat above, so this is the whole host-side gain available on the 9070 XT.

    Probes with a fresh seed per repetition (the first probe round replayed the same addresses on repeats, so its low-lane rows were cache hits; fixed in probeLaunch, job rdna4-serve-4): 1024 MiB chase at 256 lanes 276 ns per dependent load, at 1,024 lanes 422 ns, at 4,096 lanes 1,560 ns (2.63 G/s, the cap). Random 64-byte lines (four uint4 loads per step) at 1024 MiB: 2.46 to 2.88 G lines/s = 158 to 184 GB/s in lines, the same count per second as the 4-byte chase: every random 4-byte read costs this card a 64-byte line fetch. Coalesced stream over the whole 1024 MiB: 635.2 GB/s against the vendor's 640 GB/s, so the memory clock is in its full state and the card is not parked. Inside the 64 MiB buffer the line probe reaches 8.3 to 14.0 G lines/s (533 to 894 GB/s in lines: the Infinity Cache, approximate).

    -

    A second defect found on the way: the pack export race. PC 1's app log since its 19:02 UTC restart (node tools/logs.mjs win-ae432dc7-20261005-190232): worker error: error 0 pack packs\devnet: the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT at 19:07:03, 19:07:19 and 19:08:07, so the 9070 XT was not mining at all in the app while this entry was written (my job rdna4-serve-1 at 18:43 hit the same folder in the same state). Cause, from app/igneum-app/src/engine.rs prepare_worker: one thread per card, each running igneum-miner export-pack into the one folder packs\devnet; across an epoch change the two exports interleave and the folder keeps one epoch's program.h with the other's seeds.txt until the next export. Fix on this branch: a process-wide mutex around both export sites (EXPORT_LOCK); the second export rewrites the same pack. Not measured in the app yet: it ships with the branch.

    +

    A second defect found on the way: the pack export race. the three-card Windows rig's app log since its 19:02 UTC restart (node tools/logs.mjs win-ae432dc7-20261005-190232): worker error: error 0 pack packs\devnet: the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT at 19:07:03, 19:07:19 and 19:08:07, so the 9070 XT was not mining at all in the app while this entry was written (my job rdna4-serve-1 at 18:43 hit the same folder in the same state). Cause, from app/igneum-app/src/engine.rs prepare_worker: one thread per card, each running igneum-miner export-pack into the one folder packs\devnet; across an epoch change the two exports interleave and the folder keeps one epoch's program.h with the other's seeds.txt until the next export. Fix on this branch: a process-wide mutex around both export sites (EXPORT_LOCK); the second export rewrites the same pack. Not measured in the app yet: it ships with the branch.

    Answer to the maintainers. The 9070 XT does 2.5 G random 4-byte reads per second from its memory for this access pattern, and the hash needs 128 of them, so about 19 MH/s is this card's ceiling for the current program class, on any slot; it was running at 92% of that. The eGPU link cost 6% per job through the read-back, now removed (17.87 against 16.88 MH/s inside jobs standalone). The duplicate platform that halved it to 8.9 + 9.4 is folded away. The pack race that stopped it is serialised. Nothing else in the worker's control moves the number: the next step for this card is the program class itself (fewer, wider loads per hash would favour AMD's 64-byte lines), which is a consensus question, not a worker one.

    -

    5 October 2026 (night), Ember Tune: the two-knob efficiency tune, the fleet prior, and what PC 1 could measure tonight (miner-community-lead)

    +

    5 October 2026 (night), Ember Tune: the two-knob efficiency tune, the fleet prior, and what the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) could measure tonight (miner-community-lead)

    Branch ember-tune (54ff1bc), docs/plans/ember-tune.md. Every card tuned for MH per watt out of the box: the power limit and the core clock cap stepped on the live kernel (memory clock never touched), the point with the best MH per watt within 1% of the top rate kept and pinned, every result uploaded as a TUNE {json} record (a hash of the install id, no address) and folded per (card model, driver major, program class) into a prior the signed manifest carries back, so a new card of a known model starts there and confirms it in two steps.

    -

    What was measured tonight (PC 1, machine ae432dc7, from its own uploads to the intake):

    -
    FactWhere it was readConsequence
    The installed 0.3.9 app runs as <pc-hostname>\Admin with elevated=False (account line, 19:02:33 UTC)app log win-ae432dc7-20261005-190232nvidia-smi -pl and -lgc need administrator rights; the one prompt is the Power control switch (3562f26), which the app never raises by itself
    Two in-app sweep attempts aborted at 20:09 UTC: the_elevated_helper_did_not_run_(the_administrator_prompt_was_cancelled)the same logno stored sweep result from today exists; the 5090's two-knob tune is owed to the morning (one click on Power control, then it runs by itself within 2 minutes of steady mining)
    The RX 9070 XT left PC 1's bus at about 20:40 UTC, was back at 21:09 and gone again at 21:22:59 UTC (the eGPU link, third drop today)the telemetry agent and the RTX 5090 machine 1 schedulerthe AMD path (ADLX, no prompt) is unit-tested on the helper's captured line shapes; its end-to-end run waits for the card
    +

    What was measured tonight (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), machine ae432dc7, from its own uploads to the intake):

    +
    FactWhere it was readConsequence
    The installed 0.3.9 app runs as <pc-hostname>\Admin with elevated=False (account line, 19:02:33 UTC)app log win-ae432dc7-20261005-190232nvidia-smi -pl and -lgc need administrator rights; the one prompt is the Power control switch (3562f26), which the app never raises by itself
    Two in-app sweep attempts aborted at 20:09 UTC: the_elevated_helper_did_not_run_(the_administrator_prompt_was_cancelled)the same logno stored sweep result from today exists; the 5090's two-knob tune is owed to the morning (one click on Power control, then it runs by itself within 2 minutes of steady mining)
    The RX 9070 XT left the three-card Windows rig's bus at about 20:40 UTC, was back at 21:09 and gone again at 21:22:59 UTC (the eGPU link, third drop today)the telemetry agent and the the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) schedulerthe AMD path (ADLX, no prompt) is unit-tested on the helper's captured line shapes; its end-to-end run waits for the card

    The pipeline, verified without a card: 9 ember unit tests (plans, clamps, the choice rule, the five marks, a faulted step reverted inside a fake-clock run, the confirm verdicts, the baseline plan, the record and prior shapes, the vendor reasons), the AMD tune line and the 0.3.10 sample line parsed (engine::amd_telemetry_tests), the helper protocol (sweep::tests), 6 relay aggregation tests (five samples converge on 2,470 MHz at 100%; an outlier at 0.908 MH/W moves the median by nothing; baseline records make no prior; de-duplication; the manifest merge keeps lever 2's cards; the canonical round trip), 3 UI line tests. A test manifest was signed on this Mac with packaging/ota/publish-manifest.sh --tuning from fixture priors: tuning.priors["NVIDIA_GeForce_RTX_5090|581|l128w16"] = 2,470 MHz at 100%, 5 samples, beside the kernel-variant cards entry and tuning.ember {enabled: true, min_samples: 5, rate_tolerance_pct: 1}, signature verified by the signer, 21:25 UTC.

    Tier consequences (docs/plans/ember-tune.md section 7): a 9-step full tune costs about 12 minutes once and 3 minutes a week per card, under 1% of the hour, the worker never stops; a rig tunes one card at a time and every card of a known model after the first takes the 3-minute confirm; a pool user gives up the same 1% of shares at most; Apple silicon and AMD on Linux measure only and the row says so.

    -

    The PC 1 run, 22:30 UTC (job ember-tune-pc1-1, engine aeea3228..., PC 1 on 0.3.10): the job published at 22:29:40Z, the installed app stopped its miners and started the second engine at 22:30:21Z, and at 22:31:06Z the installed app quit (its log: quit: stopping the miners, then the node, then job ember-tune-pc1-1: aborted (the app is quitting)), 46 s in, before any step. Nothing was set. Corrected the same night (C35), then named the next morning from the second engine's own log (collect ember-c35-collect-1, 06:59Z): the second engine, reporting 0.3.9 (the branch's Cargo version) under the manifest's min_supported_version, took the 0.3.10 update as urgent (the "urgent" rule beats the copied auto_update = false), downloaded it at 22:31:02Z and started ota-apply.ps1 with the per-user installer at 22:31:05Z; the installer's PrepareToInstall sent POST /api/quit to the installed app, which logged quit: at 22:31:06Z. So the source was my own second engine's updater, through the installer, one second before: a second install of 0.3.10 over the 0.3.10 PC 1 had taken through the shipper's update-now at 21:40:41Z (release-0.3.10.md section 8), whose only effect was the quit and the hang. The first reading (the 0.3.11 rollout) was wrong in the cause and right in the class: an installer. What else is established: the engine's quit then HUNG for 24 minutes in the jobs runner's abort, waiting for EOF on the script's stdout pipe whose write end the second engine and its miners had inherited, and those miners (2 igneum-miner, 2 CUDA workers, 1 OpenCL worker) mined on, orphaned, until the relay lane killed them at about 23:00Z; the second engine also raised one administrator prompt at about 22:30:25Z (apply_power_limits at start counted --sweep as Power control), 41 s before the quit; PC 2's unexplained quit at 20:01:09Z came 20 s after a cancelled prompt of the same class, so the prompt is the common factor and the morning's test (one prompt raised beside the mining app on PC 2, the stamped quit line read). Fixed on the branch: b671c8b (quit sources, Power control alone decides, no cap at start under --sweep), 8ab9068 (no pipe into a second engine, its tree ended, the CI check), and the third close: a second engine never runs the updater (IGNEUM_APP_NO_OTA=1, implied by --sweep; the playbooks set it; the CI check demands it). What the run did record, the "before" snapshots with the miners stopped:

    +

    The the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) run, 22:30 UTC (job ember-tune-pc1-1, engine aeea3228..., the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) on 0.3.10): the job published at 22:29:40Z, the installed app stopped its miners and started the second engine at 22:30:21Z, and at 22:31:06Z the installed app quit (its log: quit: stopping the miners, then the node, then job ember-tune-pc1-1: aborted (the app is quitting)), 46 s in, before any step. Nothing was set. Corrected the same night (C35), then named the next morning from the second engine's own log (collect ember-c35-collect-1, 06:59Z): the second engine, reporting 0.3.9 (the branch's Cargo version) under the manifest's min_supported_version, took the 0.3.10 update as urgent (the "urgent" rule beats the copied auto_update = false), downloaded it at 22:31:02Z and started ota-apply.ps1 with the per-user installer at 22:31:05Z; the installer's PrepareToInstall sent POST /api/quit to the installed app, which logged quit: at 22:31:06Z. So the source was my own second engine's updater, through the installer, one second before: a second install of 0.3.10 over the 0.3.10 the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) had taken through the shipper's update-now at 21:40:41Z (release-0.3.10.md section 8), whose only effect was the quit and the hang. The first reading (the 0.3.11 rollout) was wrong in the cause and right in the class: an installer. What else is established: the engine's quit then HUNG for 24 minutes in the jobs runner's abort, waiting for EOF on the script's stdout pipe whose write end the second engine and its miners had inherited, and those miners (2 igneum-miner, 2 CUDA workers, 1 OpenCL worker) mined on, orphaned, until the relay lane killed them at about 23:00Z; the second engine also raised one administrator prompt at about 22:30:25Z (apply_power_limits at start counted --sweep as Power control), 41 s before the quit; the RTX 5090 Windows rig's unexplained quit at 20:01:09Z came 20 s after a cancelled prompt of the same class, so the prompt is the common factor and the morning's test (one prompt raised beside the mining app on the RTX 5090 Windows rig, the stamped quit line read). Fixed on the branch: b671c8b (quit sources, Power control alone decides, no cap at start under --sweep), 8ab9068 (no pipe into a second engine, its tree ended, the CI check), and the third close: a second engine never runs the updater (IGNEUM_APP_NO_OTA=1, implied by --sweep; the playbooks set it; the CI check demands it). What the run did record, the "before" snapshots with the miners stopped:

    CardRead back at 22:30:20ZMeaning
    RTX 5090 (driver 617.14)limit 450 W of 575 W default (min 400, max 600), draw 259.9 W idle-after-stop, core 2,850 MHz, clocks.max.gr 3,090 MHz, memory 14,001 MHzthe two-knob plan for this card is 5 power steps (575, 518, 460, 403, 400 W) and 4 clock steps (2,781, 2,472, 2,163, 1,854 MHz); it needs the one administrator prompt (Power control)
    RX 9070 XT (bus 98, present again)tune 1 ... gmax 0 gmax_range -500 1000 plimit 0 plimit_range -30 10 factory 1 okthe helper's clock range is an OFFSET from stock in MHz, not a ceiling: a probe reading it as a 1,000 MHz maximum would have asked for --set-gmax 900, an overclock. Fixed at 054e041: an offset range closes the clock knob (until the stock clock is known) and the power ladder runs on the percent scale bounded by the range, so the 9070 XT's plan is 100, 90, 80, 70% (the -30 floor), 4 steps
    Radeon(TM) Graphics (integrated)tune 0 ... gmax - ... factory 0 okno manual tuning: measure only, and it is off by default anyway
    -

    Run 2, 6 October 2026, 07:21 to 07:56Z (job ember-tune-pc1-2, elevated on the maintainers' word, engine 25113f52..., PC 1 on 0.3.11): the maintainers answered the one prompt; the installed app stopped its miners at 07:21:16Z; the second engine ran for the whole 35-minute budget at "waiting, 0.00 MH/s" and no step ran. Cause: the playbook wrote the engine's copy of settings.json with PowerShell 5.1's Set-Content -Encoding utf8, which adds a UTF-8 BOM; the engine's JSON parser refuses it, Settings::load fell back to defaults (no payout address, no cards), the engine logged [error] no payout address and never started a miner. Run 1's scratch log carried the same line the night before. Readbacks, idle both times: the 5090 at 90.6 W before and 69.9 W after (2,505 then 2,407 MHz core, 14,001 MHz memory, limit 450 W of 575), the 9070 XT at factory (gmax 0, plimit 0). Nothing set on either card. The installed app's runner released the miners-stopped hold by itself on the failed exit (job finished; the miners restart at 07:56:50Z, both miners up by 07:57:04Z, mining at 07:57:29Z): mining paused 36 min 13 s. Fix 8273494: the copy is written without a BOM, the address is read back and the job fails within seconds if it is empty (RESULT TUNE scratch settings: address ..., cards N, first bytes ...), and the CI check fails any playbook writing JSON with Set-Content -Encoding utf8. The re-run needs one more click on the prompt.

    -

    Dry run 3, 6 October 2026, 14:56 to 15:02Z (job ember-dryrun-pc1-3, unelevated, no prompt, measure only; engine from ember-tune 07d5a72, kit sha256 36b522c9...): the first measurement engine on PC 1 that mined. Both cards, one 60 s row each at the installed app's 80% cap, clocks unlocked, rate = the worker's STATUS wall rate, draw = nvidia-smi every 5 s:

    +

    Run 2, 6 October 2026, 07:21 to 07:56Z (job ember-tune-pc1-2, elevated on the maintainers' word, engine 25113f52..., the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) on 0.3.11): the maintainers answered the one prompt; the installed app stopped its miners at 07:21:16Z; the second engine ran for the whole 35-minute budget at "waiting, 0.00 MH/s" and no step ran. Cause: the playbook wrote the engine's copy of settings.json with PowerShell 5.1's Set-Content -Encoding utf8, which adds a UTF-8 BOM; the engine's JSON parser refuses it, Settings::load fell back to defaults (no payout address, no cards), the engine logged [error] no payout address and never started a miner. Run 1's scratch log carried the same line the night before. Readbacks, idle both times: the 5090 at 90.6 W before and 69.9 W after (2,505 then 2,407 MHz core, 14,001 MHz memory, limit 450 W of 575), the 9070 XT at factory (gmax 0, plimit 0). Nothing set on either card. The installed app's runner released the miners-stopped hold by itself on the failed exit (job finished; the miners restart at 07:56:50Z, both miners up by 07:57:04Z, mining at 07:57:29Z): mining paused 36 min 13 s. Fix 8273494: the copy is written without a BOM, the address is read back and the job fails within seconds if it is empty (RESULT TUNE scratch settings: address ..., cards N, first bytes ...), and the CI check fails any playbook writing JSON with Set-Content -Encoding utf8. The re-run needs one more click on the prompt.

    +

    Dry run 3, 6 October 2026, 14:56 to 15:02Z (job ember-dryrun-pc1-3, unelevated, no prompt, measure only; engine from ember-tune 07d5a72, kit sha256 36b522c9...): the first measurement engine on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) that mined. Both cards, one 60 s row each at the installed app's 80% cap, clocks unlocked, rate = the worker's STATUS wall rate, draw = nvidia-smi every 5 s:

    CardMH/sWMH/WcorememoryGPU Climit
    RTX 5090127.31316.50.4022,850 MHz13,801 MHz68460 W of 575
    RTX 407028.68102.70.2792,805 MHz10,251 MHz46160 W of 200
    -

    Nothing set; the installed app's miners back after 350 s. Why every earlier run (5 and 6 October, runs 1 to 4 and dry runs 1 and 2) read its copied settings as defaults, measured on PC 1 (collect ember-acl-2): the engine's own start locks its app folder with icacls /inheritance:r /grant:r <user>:F; cutting the folder's inheritance propagates down, the non-inheritable grant gives the children nothing, so a file COPIED in before the start (settings.json, machine-id, wallet.json) is left with no access entry and its owner cannot read it (ReadAllText: access denied), while the engine's own files written after the lock inherit fine, which hid it for a day. A first fix with (OI)(CI)F /T left the file empty too: /T re-applies /inheritance:r to each file after the propagation and an (OI)(CI) entry on a file is inherit-only. The right form is the inheritable grant without /T (07d5a72). Consequence for every tier on Windows: nothing changes for the installed app (its files were always its own); any tool that drops files into the app folder before the app starts (an installer's seed, a migration, a support script) was unreadable to the app until now and is readable from 0.3.13 on.

    -

    Run 5, 6 October 2026, 15:28 to 15:39Z (job ember-tune-pc1-5, elevated on the maintainers' click, PC 1 on 0.3.13, the tune engine = kit ember-kit-5 from 07d5a72, mode=direct): the first run that set limits. The 5090's power ladder, 75 s a step, the clock unlocked (2,850 MHz core, 13,801 MHz memory), the rate = the worker's STATUS wall rate, the draw = nvidia-smi every 5 s:

    +

    Nothing set; the installed app's miners back after 350 s. Why every earlier run (5 and 6 October, runs 1 to 4 and dry runs 1 and 2) read its copied settings as defaults, measured on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (collect ember-acl-2): the engine's own start locks its app folder with icacls /inheritance:r /grant:r <user>:F; cutting the folder's inheritance propagates down, the non-inheritable grant gives the children nothing, so a file COPIED in before the start (settings.json, machine-id, wallet.json) is left with no access entry and its owner cannot read it (ReadAllText: access denied), while the engine's own files written after the lock inherit fine, which hid it for a day. A first fix with (OI)(CI)F /T left the file empty too: /T re-applies /inheritance:r to each file after the propagation and an (OI)(CI) entry on a file is inherit-only. The right form is the inheritable grant without /T (07d5a72). Consequence for every tier on Windows: nothing changes for the installed app (its files were always its own); any tool that drops files into the app folder before the app starts (an installer's seed, a migration, a support script) was unreadable to the app until now and is readable from 0.3.13 on.

    +

    Run 5, 6 October 2026, 15:28 to 15:39Z (job ember-tune-pc1-5, elevated on the maintainers' click, the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) on 0.3.13, the tune engine = kit ember-kit-5 from 07d5a72, mode=direct): the first run that set limits. The 5090's power ladder, 75 s a step, the clock unlocked (2,850 MHz core, 13,801 MHz memory), the rate = the worker's STATUS wall rate, the draw = nvidia-smi every 5 s:

    CapLimitMH/sWMH/WGPU C
    100%575 W127.38309.90.41164
    90%518 W99.32313.60.31765
    80%460 W123.11312.20.39465
    70%403 W127.38310.90.41065
    60% (floor 400 W)400 W127.38311.30.40965

    Reading: the cap does not bind on this hash (310 to 314 W under every limit, as the 4 October stability line said), so the power knob is flat at 0.41 MH/W on the 5090 and the saving must come from the clocks; the 90% and 80% rows' rate dips at the same draw are stalls inside those holds (a worker restart or a template wait), not the cap. The clock ladder's first step (2,781 MHz at 575 W) was requested at 15:37:47Z and never measured: the playbook's own watchdog killed the live engine at 15:39:03Z (all three cards mining at 177 MH/s) because its idle clause sampled one log line and read "idle" from a missing match; the 4070's and the 9070 XT's plans never ran. Consequences: the 5090 is probably left with its core clock locked at 2,781 MHz (an -lgc lock persists until -rgc or a reboot) under the 575 W cap, which costs little rate; freeing it needs administrator rights; and the Power Helper was NOT registered by this run (the registration lived only in the installed app's cap path, which a --sweep engine skips). Fixed the same hour: the watchdog's idle rule (three consecutive status lines reading 0.00 MH/s and 300 s, never a missing match), the after snapshot and the engine-log dump on every exit, and an elevated tune engine registering the task itself before its first step. The decided way out: the maintainers switches Power control ON in the 0.3.13 app (its one prompt registers the task from the install folder), a job frees the clock through the task (rgc), the tune runs unelevated through the task.

    -

    Consequence for the tiers: an AMD card is tuned on its power limit alone until its stock core clock is read (a 9070 XT at -30% is the floor the driver allows, 4 steps, 5 minutes); every NVIDIA card's two-knob plan waits on the user's one click on Power control; the re-run on PC 1 is held until the quit's source is named (the event-log collect) and follows the 0.3.11 rollout (the update clears the jobs folder, so the engine and the helper are fetched again), with the scheduler's slot.

    +

    Consequence for the tiers: an AMD card is tuned on its power limit alone until its stock core clock is read (a 9070 XT at -30% is the floor the driver allows, 4 steps, 5 minutes); every NVIDIA card's two-knob plan waits on the user's one click on Power control; the re-run on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) is held until the quit's source is named (the event-log collect) and follows the 0.3.11 rollout (the update clears the jobs folder, so the engine and the helper are fetched again), with the scheduler's slot.

    5 October 2026 (night), read width of the lottery hash: 4, 16 and 64-byte loads, a per-load mix, a written scratch; three cards (gate 1 experiment, cryptographer)

    Branch readwidth (commits 019b014, b970dda, 4badcee, a9e002c, d0018cf and the entry commit); plan and recommendation in docs/plans/read-width.md. Nothing here changes consensus: every class sits behind igneum-pow --class and the default class is generator version 2 byte for byte (igneum-pow/tests/packs.rs passes on the four pinned packs after every commit). Question (the maintainers, after "the 9070 XT on the eGPU" above): would wider reads keep the latency-bound random-access property while closing the vendor gap. Additions from the coordinator: a per-load width drawn from an era-fixed mix, and a written per-warp scratch (measurement only, no soundness claim).

    What a class does (igneum-pow/src/generator.rs LoadClass, verify::fold_words, the three emitters): a load of W words reads the W-word-aligned address (src AND MASK) AND NOT (W - 1) and folds every word into dst (x = dst ^ w0; x = (rotl(x, 11) * 0x9e3779b1) ^ w[j]); W = 1 is the lottery hash exactly (w4 = pack bcc1248b10cc90f2). A mix class draws W per load with one extra below(100) roll per instruction. A scratch class scr<k>k<kb> turns k of the 16 memory slots into read-modify-writes of a 16-byte slot of the lane's share of a kb KiB per-warp scratch (kernels run persistent warps, one per block or work-group; a slot reads as a seed-and-base fill until the unit writes it, behind a per-unit tag). Program ids carry the class. Dependent chain and 32-lane unit unchanged.

    Correctness: 23 packs (proto-cuda/packs-readwidth/, Rust CPU reference vectors). Every pack passed its three vector units and the cache and dataset checks on Metal (M5 Max, proto-metal/packbench), Apple OpenCL (--bench-pack), the RTX 5090 (NVRTC, igneum-worker-cuda --bench) and, the 16 width and mix packs, the RX 9070 XT (igneum-worker-opencl --bench-pack); the 2^24 batch fingerprints agree across all four runtimes on every pack (for example w16 e7c890445b47af60, w64 836e56e7d496e980, mixB-2 a18ac73098c76007). The clang CUDA emulation (w16, w64, w64x4, mixA-0, mixB-0: 3 of 3 units standalone and 2 of 2 in batch at 2 warps per block) and the clang OpenCL emulation (the same five plus scr2k32 and scr8k128, sub-group 32 and, width packs, wave64 with sub-group shuffles) pass with equal fingerprints per configuration. Acceptance rule on the classes: 60 candidates per class, rejection 0 to 14 of 60 (w16 and w64 as v2; the mixes the same; the scratch classes' distinct-address bound now covers dataset loads only, since a 64-slot lane scratch repeats slots by design). CPU verifier (M5 Max, one core, avg of 50 units, igneum-pow bench --class): v2 0.604 ms, w16 0.610, w64 0.630, w64x4 0.160, mix50-35-15 0.620, mix25-50-25 0.614, scr0k32 0.600 (1.004 on a loaded re-run), scr2k32 0.657, scr4k32 0.458, scr8k32 0.317, scr2k128 0.535, scr4k128 0.458, scr8k128 0.311; per hash divide by 32. The wide reads cost the verifier nothing (a lane's words lie in one item); scratch ops replace item derivations and make it cheaper.

    Probes (--memprobe, dependent random reads at 1024 MiB, G reads/s, best over lanes in flight; 4 B = the hash's pattern; the 5090 and 9070 XT with the card off in the app, the Apple M5 Max through Apple OpenCL under a load average of 5 to 10):

    -
    Card4 B chase16 B64 B64 B as GB/scoalesced stream GB/s (rated)integer chain
    RTX 5090 (PC 2, CUDA)17.5 to 18.218.0 to 19.99.1 to 15.7 (9.1 at 4 M lanes)5841,579 (1,792)39.0 T op/s
    RX 9070 XT (PC 1, eGPU, OpenCL)2.42 to 2.662.43 to 2.732.47 to 2.87158636 (640)6.2 T op/s
    Apple M5 Max (Apple OpenCL, approximate)3.503.513.51225522
    +
    Card4 B chase16 B64 B64 B as GB/scoalesced stream GB/s (rated)integer chain
    RTX 5090 (the RTX 5090 Windows rig, CUDA)17.5 to 18.218.0 to 19.99.1 to 15.7 (9.1 at 4 M lanes)5841,579 (1,792)39.0 T op/s
    RX 9070 XT (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), eGPU, OpenCL)2.42 to 2.662.43 to 2.732.47 to 2.87158636 (640)6.2 T op/s
    Apple M5 Max (Apple OpenCL, approximate)3.503.513.51225522

    Reading: on the 9070 XT and the M5 Max a 64-byte dependent read costs exactly what a 4-byte one costs (the line is fetched either way); on the 5090 a 64-byte read costs about two 4-byte reads (two 32-byte sectors) and the 64 B chase at full occupancy sits at 584 GB/s, a third of the stream.

    -

    Hash rates (5 timed dispatches of 2^24 nonces after a warm-up; Metal and the 9070 XT by device time, the 5090 by wall time around the stream sync; the RTX 5090 machine cards switched off in the app for the run and restored, PC 1's 5090 and the integrated chip kept mining; the Apple M5 Max under other agents' builds, load 4 to 9, so its absolute numbers carry that; the share = measured / (the card's probe ceiling at the class's widths / loads per hash)):

    +

    Hash rates (5 timed dispatches of 2^24 nonces after a warm-up; Metal and the 9070 XT by device time, the 5090 by wall time around the stream sync; the RTX 5090 machine cards switched off in the app for the run and restored, the three-card Windows rig's 5090 and the integrated chip kept mining; the Apple M5 Max under other agents' builds, load 4 to 9, so its absolute numbers carry that; the share = measured / (the card's probe ceiling at the class's widths / loads per hash)):

    Classdataset B/hashRTX 5090 MH/s (share)RX 9070 XT MH/s (share)M5 Max Metal MH/s (share)5090 / 9070
    v2 (w4, the lottery hash)512136.1 (0.96)18.15 (0.87)27.74 (1.01)7.5x
    w162,048139.8 (0.90)17.90 (0.84)28.26 (1.03)7.8x
    w648,19271.9 (0.58)17.59 (0.78)28.27 (1.03)4.1x
    w64x4 (32 loads)2,048275.3 (0.56)75.19 (0.84)109.7 (1.00)3.7x
    mix50-35-15, 6 programs: min / median / max (spread of median)1,664 to 3,68099.5 / 114.2 / 121.0 (18.8%)17.45 / 18.76 / 18.83 (7.4%)25.36 / 27.26 / 28.43 (11.3%)6.1x
    mix25-50-25, 6 programs2,240 to 5,02495.9 / 107.3 / 119.8 (22.3%)17.84 / 18.45 / 18.85 (5.5%)23.21 / 24.68 / 25.21 (8.1%)5.8x

    Scratch (variant 5; N persistent warps; 5090: 2,048 warps launched against a resident capacity of 4,080 = 24 blocks/SM x 1 warp/block x 170 SMs at --block-warps 1, the occupancy query unchanged by the allocation (24 before and after); Metal: 2,048 to 16,384 warps swept, best shown; arena = N x per-warp size; the whole working set = 1 GiB dataset + 256 MiB cache + 128 MiB output + arena, under 2 GB on every row):

    Class (k of 16 slots, KiB per warp)scratch ops/hashdataset B/hashRTX 5090 MH/s (vs scr0, share)M5 Max Metal MH/s (vs scr0)RX 9070 XT MH/s5090 arena / working set
    scr0k32 (control, persistent loop, no RMW)0512139.1 (0, 0.98)28.25 (0)17.88 (control, 0.86)64 MiB / 1.4 GiB
    scr2k32 (12.5%)16448114.4 (-18%, 0.80)26.14 (-7%)14.65 (-18%)64 MiB / 1.4 GiB
    scr4k32 (25%)32384109.8 (-21%, 0.76)31.74 (+12%)14.00 (-22%)64 MiB / 1.4 GiB
    scr8k32 (50%)64256122.1 (-12%, 0.82)49.08 (+74%)14.17 (-21%)64 MiB / 1.4 GiB
    scr2k128 (12.5%)16448110.1 (-21%, 0.77)26.24 (-7%)14.07 (-21%)256 MiB / 1.6 GiB
    scr4k128 (25%)3238498.0 (-30%, 0.68)28.08 (-1%)13.14 (-27%)256 MiB / 1.6 GiB
    scr8k128 (50%)6425672.8 (-48%, 0.49)35.44 (+25%)12.03 (-33%)256 MiB / 1.6 GiB
    @@ -609,7 +566,7 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    Addendum, the added form (coordinator's form of 5 October 2026: 16 + k load slots, the k hot ones drawn among them, the 16 dataset loads and the 4,096-item verifier bound unchanged; packs hot32k4a, hot64k4a, hot96k4a; second Mac session 21:03 to 21:19 UTC, load average 7 to 14; same harnesses and commands, branch ca2-cache on ca2-v3 464d6e1, the hosts rebuilt on the merged packfile.h):

    PackMetal Mhash/sApple OpenCL Mhash/sfingerprint (equal on both)vectorshot tableg against v2 (Metal, v2 27.63 in this session)probe-predicted gCPU verify ms/warp (v2 0.602)hot fill, one core
    hot32k4a25.7625.728a3414735db4523c96/96 bothPASS both0.930.960.63121.7 ms
    hot64k4a23.9223.8745668f34105f630796/96 bothPASS both0.870.940.60943.3 ms
    hot96k4a22.9222.88af763997dfee4c8296/96 bothPASS both0.830.930.61464.9 ms

    Reading: the added form costs this card 7, 13 and 17% of its rate at 32, 64 and 96 MiB for four extra loads per iteration, more than the probe predicts as the table grows; the verifier is unchanged (4,096 items, plus 32 table reads) and pays the fill per epoch. Chip arithmetic in the plan, section 6.4. All eight packs load and self-test through the rebuilt OpenCL host (the Windows exe's host.c) on the Apple M5 Max.

    -

    Addendum, the PCs (5 October 2026, 21:29 to 21:35 UTC, PC 1 ae432dc7, app 0.3.9 before and after; fetch fetch-ca2-hot-20261005 (zip sha256 bd49faa1c9d48024f49c615481faff5c68a4c09f0889dbaf009c208674d67b3f), jobs run-ca2-hot-5090-20261005 (126 s) and run-ca2-hot-9070-20261005 (247 s), both exit 0, the card under test switched off in the app through api/cards and restored; workers igneum-worker-cuda.exe sha256 956c4ab34f42cbcd1d2c1c6fb1a58fd9b3a8c70166df771cafcd0296ca6a27d4 and igneum-worker-opencl.exe sha256 32d3d34390aad70485c3524424c354223387137d383b5c5daf01f40073c12703, built from ca2-cache 196db96 on ca2-v3's merged packfile.h d2cd6e1; read back with node tools/jobs.mjs <id> --all):

    +

    Addendum, the PCs (5 October 2026, 21:29 to 21:35 UTC, the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) ae432dc7, app 0.3.9 before and after; fetch fetch-ca2-hot-20261005 (zip sha256 bd49faa1c9d48024f49c615481faff5c68a4c09f0889dbaf009c208674d67b3f), jobs run-ca2-hot-5090-20261005 (126 s) and run-ca2-hot-9070-20261005 (247 s), both exit 0, the card under test switched off in the app through api/cards and restored; workers igneum-worker-cuda.exe sha256 956c4ab34f42cbcd1d2c1c6fb1a58fd9b3a8c70166df771cafcd0296ca6a27d4 and igneum-worker-opencl.exe sha256 32d3d34390aad70485c3524424c354223387137d383b5c5daf01f40073c12703, built from ca2-cache 196db96 on ca2-v3's merged packfile.h d2cd6e1; read back with node tools/jobs.mjs <id> --all):

    Probe (--memprobe --probe-mib S, dependent 4 B chase ceiling at 4,194,304 lanes, G loads/s; ns per dependent load at 4,096 lanes in brackets):

    Card32 MiB64961024stream at 1024 MiB
    RTX 5090 (CUDA, wall)112.6 (320)112.6 (340)112.6 (336)17.6 (610)1,563 GB/s
    RX 9070 XT (OpenCL, event)9.88 (396)9.47 (457)8.18 (454)2.43 (1,579)633 GB/s

    Rates (5 dispatches of 2^24 after a warm-up; 5090 --bench --block-warps 1, 9070 XT --bench-pack --device 1 work-group 256; every row check=PASS with the Apple M5 Max's fingerprint; v2 references from the readwidth entry, same night, same workers: 136.1 and 18.15 MH/s):

    @@ -623,25 +580,25 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
    ConstructionVerifier ms per 32-lane unit, avg of 50 (two rounds)Worst cold unitAgainst v2256 MiB fill, one coreMetal 1 GiB build, GPU ms
    v21.361 / 1.3101.5791172 to 173 ms29.7 (first touch) / 21.0
    x4 (class v3)1.956 / 1.9232.0431.45x172 to 175 ms20.9 / 21.0
    x8 (candidate)2.785 / 2.7902.9422.09x172 ms21.9 / 21.9

    Reading: the mixer multiplies the verifier's ALU part only (the 8 dependent misses per item are unchanged), hence 1.45x and 2.1x and not 4x and 8x; the Apple M5 Max's GPU build is latency-bound and does not move with the mixer, so the "under 1 s on every discrete card" half of the x8 rule is the RTX 5090 machine job (five packs, relay/playbooks/mixer-x4-pc1-bench.ps1, waiting for the go). Verification throughput (C19): a quiet 2026 core serves about 1,100 shares per second at x4 and 800 at x8 (1,660 at v2, re-cutting spec 09's 2,270), a 22,000-member pool at one share per 10 s needs 2 cores at x4 and 3 at x8, IBD over 108,000 headers is 1.6 min at x4 and 2.3 at x8 on that core; the 10 ms gate keeps 8.0 ms (x4) and 7.1 ms (x8) of margin on the loaded core, 6 to 7 ms on a 2019-class laptop core (approximate, unmeasured, O-1.14).

    Chip model (docs/analysis/chip-model-v3.md): the on-die-cache recompute chip at 50 T op/s against the 5090's measured 136.1 MH/s: v2 334 MH/s, 2.45x bare, 7.4x with the 3x fixed-function factor; x4 83.5 MH/s, 0.61x bare, 1.84x with the factor, 1.53x with the 128 mm^2 N5 mirror deducted at equal silicon; x8 41.7 MH/s, 0.31x, 0.92x, 0.76x. The claim at x4 is "under 2x" with the margin thin on the equal-budget convention (a 3.3x factor or a 10 percent larger budget reads 2.0x); the hot table in the added form would have raised it to 2.1x to 2.2x at the 5090's g (kept as measured, not adopted). Nothing here is a measurement of a chip.

    -

    Addendum, 22:15 UTC: the verifier regression, the RTX 5090 machine 1 build rows, and x8 into v3. The era agent measured the same v2 input with readwidth's binary (0.604 ms) and ca2-v3 HEAD's (1.33) in one minute; bisected under the measure lock to this branch's 0fc0ad1 (seam 6c75dad 0.610, 0fc0ad1 1.332; the "loaded box" reading above was wrong by that factor, the load was real but the 2x was the code). Cause: the item loop (derive_items) inlined into MemhardCpu::fetch; the mask hoisted, the mask constant, and the constant-mask loop inlined all stayed at 1.33, the same loop #[inline(never)] read 0.60 to 0.62. Fix: derive_items_mask, out of line, one instance per cache size with the line mask a constant. Measured the era agent's way (readwidth's binary beside the fixed one, same input, same minute, 22:07 UTC): v2 0.607 / 0.610 against 0.609 / 0.611; on the fixed binary x4 1.238 / 1.237 (2.0x), x8 2.077 / 2.058 (3.4x), worst cold 2.15 ms; the increments (+0.63, +1.46 ms per unit) equal the slow binary's. Lesson, the class: an inlined item loop costs 2.2x and nothing in the suite sees it; a verifier benchmark with a pinned bound in the crate's CI is filed for the next cut, and until then every change to the item loop is measured against the previous binary on the same input in the same minute. PC 1 (job run-mixer-x4-pc1-20261005, 22:00 to 22:04 UTC, the worker's cache ... dataset ... ms wall line): RTX 5090 dataset 23 to 25 ms at v2, x4 and x8; RX 9070 XT (gfx1201) 72 to 77 ms at all three; every fingerprint equal to the Apple M5 Max's; rates the v2 rate (136.5 to 137.4 and 18.0 to 18.2 MH/s). Decision under the delegated rule (coordinator, 22:05 UTC): x8 enters class v3 (V3_CLASS = MX8); pinned packs mx8-genesis (7c28cfb06c5c65a9) and mx8-devnet-epoch0 through the chain path with the era inside (90f794dd556f7a3b, Metal and Apple OpenCL, 22:12 UTC); the x4 packs kept as the candidate's record. Chip headline at x8: 41.7 MH/s, 0.31x bare, 0.92x with the 3x factor, 0.76x at equal silicon (docs/analysis/chip-model-v3.md).

    +

    Addendum, 22:15 UTC: the verifier regression, the the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) build rows, and x8 into v3. The era agent measured the same v2 input with readwidth's binary (0.604 ms) and ca2-v3 HEAD's (1.33) in one minute; bisected under the measure lock to this branch's 0fc0ad1 (seam 6c75dad 0.610, 0fc0ad1 1.332; the "loaded box" reading above was wrong by that factor, the load was real but the 2x was the code). Cause: the item loop (derive_items) inlined into MemhardCpu::fetch; the mask hoisted, the mask constant, and the constant-mask loop inlined all stayed at 1.33, the same loop #[inline(never)] read 0.60 to 0.62. Fix: derive_items_mask, out of line, one instance per cache size with the line mask a constant. Measured the era agent's way (readwidth's binary beside the fixed one, same input, same minute, 22:07 UTC): v2 0.607 / 0.610 against 0.609 / 0.611; on the fixed binary x4 1.238 / 1.237 (2.0x), x8 2.077 / 2.058 (3.4x), worst cold 2.15 ms; the increments (+0.63, +1.46 ms per unit) equal the slow binary's. Lesson, the class: an inlined item loop costs 2.2x and nothing in the suite sees it; a verifier benchmark with a pinned bound in the crate's CI is filed for the next cut, and until then every change to the item loop is measured against the previous binary on the same input in the same minute. the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (job run-mixer-x4-pc1-20261005, 22:00 to 22:04 UTC, the worker's cache ... dataset ... ms wall line): RTX 5090 dataset 23 to 25 ms at v2, x4 and x8; RX 9070 XT (gfx1201) 72 to 77 ms at all three; every fingerprint equal to the Apple M5 Max's; rates the v2 rate (136.5 to 137.4 and 18.0 to 18.2 MH/s). Decision under the delegated rule (coordinator, 22:05 UTC): x8 enters class v3 (V3_CLASS = MX8); pinned packs mx8-genesis (7c28cfb06c5c65a9) and mx8-devnet-epoch0 through the chain path with the era inside (90f794dd556f7a3b, Metal and Apple OpenCL, 22:12 UTC); the x4 packs kept as the candidate's record. Chip headline at x8: 41.7 MH/s, 0.31x bare, 0.92x with the 3x factor, 0.76x at equal silicon (docs/analysis/chip-model-v3.md).

    5 October 2026 (evening), EVM transaction relay: three nodes in a chain, every transaction sent to one end included by the other two miners (execution and networking engineer)

    Until this change the node did not relay EVM transactions to its peers, so a transaction sent to one node was only ever included by that node's own templates (this file, "5 October 2026 (afternoon), live devnet: real transactions": 3,794 transfers, all in the Apple M5 Max's blocks; execution-layer ledger item 9). Fork branch tx-gossip (worktree vendor/igneum-node-txgossip, from release-0.3.6 a24ab01a, commit e242acd0), main repo branch tx-gossip. Design in docs/design/execution-layer.md 1.4 "Relay"; the hand-out cooldown of its 10.2 table is gone with it (row "Mempool hold").

    What was built. Three p2p messages after Kaspa's own transaction relay (protocol/flows/src/v10/txrelay/flow.rs): an inventory of admitted hashes, a request for the unknown ones, one answer with the raw bytes (protocol/p2p/proto/p2p.proto, payload numbers 72 to 74). Two flows per peer (protocol/flows/src/v10/evmrelay.rs), a pump that announces the mempool's admitted hashes every 250 ms, a sink trait the execution layer implements (kaspa_consensus_core::evm::EvmTxSink, igneum/exec/src/service.rs EvmTxRelaySink), and the mempool's side: every admitted hash queued for gossip, executed, evicted and invalid hashes remembered (65,536) so a second announcement is not requested, a 50,000-transaction cap, and the hold on block-added in place of the 4-second cooldown (the executor subscribes to consensus BlockAdded; a transaction leaves the templates when any DAG block carries it and comes back if a chain block skipped it). Limits per peer in the table.

    LimitValueOver it
    Hashes announced to us, or requested from us2,000 per second, burst 8,192the surplus of the message is dropped (the sender paid as much as we did)
    Hashes per inventory or request message4,096disconnect
    Bytes per answer / per transaction4 MiB / 128 KiBdisconnect
    Transaction failing a state-free rule (malformed, signature, chain id, type 3 or 4)disconnect, hash remembered
    State-dependent refusal (nonce more than 16 ahead, fee cap under the base fee, funds, 64 queued per sender, pool full)dropped quietly, hash not remembered

    Protocol version. 13 to 14. An Igneum node drops a connection on a payload it cannot decode (protocol/p2p/src/core/router.rs route_to_flow: prost leaves the oneof empty, the router returns "empty payload", the connection closes), so the three messages go only to peers that advertised 14 or later, exactly as the finality (12) and proof-record (13) messages did. A 14 node registers the 13 flows for a 13 peer and never announces to it. The consensus params digest does not cover the protocol version: a scratch node on the devnet profile from the shipped 0.3.6 binary (target-036) and from this build printed the same digest, 9409dedac4bf9f0f20a54fb169b52a75a2903364909fe9ffd6fc5cdcd9d95d38, so a 14 node and a 13 node still peer. Rollout: during the mixed fleet a transaction reaches the 14 nodes connected to the node it was sent to, and whatever a 13 node mines carries only what its own RPC received, as today; the relay is complete when the last miner is on 14. No fresh chain, no activation height.

    -

    Unit tests (PC 2, job build-20261005-173606, igneum-exec 15 of 15 in 0.01 s, kaspa-p2p-flows 33 of 33 in 0.19 s, 24 s for both): the pool queues an admitted hash for gossip once and answers "known" for the duplicate; wrong chain id, a signature above the curve order and truncated bytes are refused and remembered by hash, a nonce beyond the gap and a fee cap under the base fee are refused and not remembered; a transaction stays in every template until a block carries it, is held then, comes back when a chain block skips it and leaves (hash remembered) when one executes it; the wire messages round-trip through prost and the router's payload type, hash lists of the wrong length or over 4,096 are refused, the per-peer bucket grants the burst then the rate. The first PC 2 run of the suites (build-20261005-173013) failed on the signature case: a flipped low bit of s recovers a different signer (a funds refusal), not a fault; the test now sets s above the curve order. Found on the way: the kaspa-p2p-flows test target had not compiled since M20 added the epoch-seed headers to the pruning proof messages (ibd/proof.rs tests), fixed in the same commit.

    +

    Unit tests (the RTX 5090 Windows rig, job build-20261005-173606, igneum-exec 15 of 15 in 0.01 s, kaspa-p2p-flows 33 of 33 in 0.19 s, 24 s for both): the pool queues an admitted hash for gossip once and answers "known" for the duplicate; wrong chain id, a signature above the curve order and truncated bytes are refused and remembered by hash, a nonce beyond the gap and a fee cap under the base fee are refused and not remembered; a transaction stays in every template until a block carries it, is held then, comes back when a chain block skips it and leaves (hash remembered) when one executes it; the wire messages round-trip through prost and the router's payload type, hash lists of the wrong length or over 4,096 are refused, the per-peer bucket grants the burst then the rate. The first the RTX 5090 Windows rig run of the suites (build-20261005-173013) failed on the signature case: a flipped low bit of s recovers a different signer (a funds refusal), not a fault; the test now sets s above the curve order. Found on the way: the kaspa-p2p-flows test target had not compiled since M20 added the epoch-seed headers to the pruning proof messages (ibd/proof.rs tests), fixed in the same commit.

    The 3-node run (tools/txgen/relay-net.mjs, new; this Mac, load 7 to 8 at the end of the run after the other agents' harnesses finished, every number a count or an inclusion latency, not a timing of the node). Fast-time profile (infra/fast-time/override-60x.json, proof of work skipped), ports 29700+, data /tmp/igneum-txrelay. Chain A - B - C: B dials A and C (a harness node that dials accepts no inbound, and --connect takes one address per flag; both found by the first two runs, which are not numbers). A mines nothing. One vmine on B and one on C at 0.5 blocks/s each, paid to throwaway keys made for the run; B's rewards funded 16 generator wallets (2 IGN each) 33 s after start. The generator (tools/txgen/run.mjs) sent to A's EVM RPC only, 2 transfers a second for 120 s, so every inclusion is by a block B or C built from a pool the relay fed; C is two hops from A. Result files docs/benchmarks/evm-relay-2026-10-05/{relay-report,txgen-summary}.json.

    Measured, 3-node fast-time run (17:49 to 17:52 UTC)Value
    Sent to A / included / pending at the end / failures240 / 240 / 0 / 0 (0 nonce retries, 0 deferred, 0 throttled)
    Included per second over the send span1.98 (target 2)
    Inclusion latency p50 / p90 / p99 / max1,545 / 3,058 / 5,033 / 6,017 ms (mean 1,859)
    Chain blocks in the window / executed transfers / skipped copies149 / 256 (240 transfers and 16 funding) / 0
    Included by miner B (one hop): blocks / with transactions / executed79 / 59 / 151
    Included by miner C (two hops): blocks / with transactions / executed70 / 42 / 105
    Pool depth, sampled every 5 s on A, B and Cequal on all three at 27 of 27 samples (0 to 6 pending), peak 6
    Sinks agree at the endyes
    First funding transfer, sent to A, included2.0 s after the send (block 37, mined by B or C)

    Reading. Every transaction given to A was mined by B or C within 6 s, two thirds of them within 3 s, with no skipped copy: the hold on block-added kept B's and C's parallel blocks from carrying the same transfer. The afternoon run on the live devnet, through one node with the cooldown, had p50 40.7 s and p90 110.8 s with 50-s quiet stretches; here the 1.5 s p50 is one fast-time block plus the relay and the executor's lag. The pool depth matching on all three nodes at every sample is the convergence. Not measured here: a transaction flood above the per-peer rate (the bucket is unit-tested only), a 13 peer in the fleet (the digest check and the version gate are the evidence), and the hold's 30-s expiry on a block that never reaches the chain (not seen in 149 chain blocks).

    Commands: IGNEUMD=vendor/igneum-node/target-txgossip/release/igneumd IGNEUM_MINER=vendor/igneum-node/target-txgossip/release/igneum-miner tools/lock/with-lock.sh run node tools/txgen/relay-net.mjs --rate 2 --duration 120 --wallets 16 --fund 2; the Apple M5 Max binaries from the fork worktree with CARGO_TARGET_DIR=vendor/igneum-node/target-txgossip cargo build --release -j 4 -p kaspad -p igneum-miner --features kaspad/igneum-pow under the build lock (an APFS clone of target-036, 2 min 15 s to clone, 5 min 06 s to build); the suites with node tools/build-job.mjs run --target 1ccfe586 --node vendor/igneum-node-txgossip --targets linux --node-tests "igneum-exec kaspa-p2p-flows" --no-app.

    -

    5 October 2026 (night), the SP1 CPU prover on PC 1 beside the miners, and the backend survey: no zkVM proves on AMD (amd-prove agent)

    +

    5 October 2026 (night), the SP1 CPU prover on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) beside the miners, and the backend survey: no zkVM proves on AMD (amd-prove agent)

    the maintainers, 21:50 UTC: "test proving on the amd card?" and "can we test proving on mac?". The analysis with the backend table and the tier consequences: docs/analysis/amd-proving.md. The survey (SP1 v6.8.1 and dev 318dd530 of 28 Sep 2026, RISC Zero, Jolt, OpenVM, ICICLE, sppark; every claim cites a file or page there): on 5 October 2026 no zkVM proves on an AMD GPU; Apple silicon has RISC Zero's shipped Metal prover and ICICLE's Metal backend; SP1, the prover here, is CPU-only off NVIDIA.

    -

    Machine: PC 1 (machine ae432dc7), Windows 11, WSL2 Ubuntu 24.04 as root, 16 cores and 46,994 MB visible to the VM, the Igneum Miner app 0.3.9 mining on the RTX 5090 and the RX 9070 XT throughout (the 5090 at 89% mean utilisation, 59 to 70% minimum, from a 1-s nvidia-smi sampler under the run: the job never touched a card). Signed run job cpu-prove-pc1-small2 (tools/amd-prove/pc1-cpu-prove.ps1), 20:49:00Z to 20:59:49Z: the hosted package igneum-prove-wsl2-pv1b.zip (sha256 df50dee5...) built WITHOUT the cuda feature (6 s warm; the first job cpu-prove-pc1-small built it cold in 126 s), --mode id the pinned pair (shard 0x2b1a81cb..., aggregator 0x474678f3..., pinned 2026-10-05T16:20:38Z), SP1_PROVER=cpu, --mode shard --shard 0 under /usr/bin/time -v. Log: node tools/jobs.mjs cpu-prove-pc1-small2 --all.

    -
    FixtureSP1 cyclesSetup sCore prove s (bytes, verify s)Compressed prove s (bytes, verify s)Wall sPeak RSSCPU
    block-56-transfers-3shards shard 0 (200 pgas, one transfer)315,47922.75 (client 19.46, shard keys 1.85, aggregator keys 1.44)82.5 (7,310,257, 0.210) VERIFIED199.2 (1,272,897, 0.035) VERIFIED312.129,503,652 kB (29.5 GB)978% (9.8 of 16 cores), user 2,516 s, system 537 s, load max 11.3
    block-78-increment (2 transactions, 1 executed 1 skipped)631,12721.7587.0 (7,317,857, 0.209) VERIFIED202.3 (1,272,897, 0.034) VERIFIED322.330,517,916 kB (30.5 GB)979%, user 2,616 s, system 541 s, load max 13.1
    block-338-shard1 (one shard at S_p, 60.8 M cycles)not run: the RTX 5090 machine 1 scheduler kept the machine for the Counter ASIC 2.0 gates (21:05Z). Approximate extrapolation: about 29 SP1 shards of 2^21 cycles at about 80 s each, 40 min of core proof, then hours of recursion; floor from the 5090's ratios (6x core, 4x compressed, block-78 to S_p): 9 min core, 13 min compressed
    +

    Machine: the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (machine ae432dc7), Windows 11, WSL2 Ubuntu 24.04 as root, 16 cores and 46,994 MB visible to the VM, the Igneum Miner app 0.3.9 mining on the RTX 5090 and the RX 9070 XT throughout (the 5090 at 89% mean utilisation, 59 to 70% minimum, from a 1-s nvidia-smi sampler under the run: the job never touched a card). Signed run job cpu-prove-pc1-small2 (tools/amd-prove/pc1-cpu-prove.ps1), 20:49:00Z to 20:59:49Z: the hosted package igneum-prove-wsl2-pv1b.zip (sha256 df50dee5...) built WITHOUT the cuda feature (6 s warm; the first job cpu-prove-pc1-small built it cold in 126 s), --mode id the pinned pair (shard 0x2b1a81cb..., aggregator 0x474678f3..., pinned 2026-10-05T16:20:38Z), SP1_PROVER=cpu, --mode shard --shard 0 under /usr/bin/time -v. Log: node tools/jobs.mjs cpu-prove-pc1-small2 --all.

    +
    FixtureSP1 cyclesSetup sCore prove s (bytes, verify s)Compressed prove s (bytes, verify s)Wall sPeak RSSCPU
    block-56-transfers-3shards shard 0 (200 pgas, one transfer)315,47922.75 (client 19.46, shard keys 1.85, aggregator keys 1.44)82.5 (7,310,257, 0.210) VERIFIED199.2 (1,272,897, 0.035) VERIFIED312.129,503,652 kB (29.5 GB)978% (9.8 of 16 cores), user 2,516 s, system 537 s, load max 11.3
    block-78-increment (2 transactions, 1 executed 1 skipped)631,12721.7587.0 (7,317,857, 0.209) VERIFIED202.3 (1,272,897, 0.034) VERIFIED322.330,517,916 kB (30.5 GB)979%, user 2,616 s, system 541 s, load max 13.1
    block-338-shard1 (one shard at S_p, 60.8 M cycles)not run: the the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) scheduler kept the machine for the Counter ASIC 2.0 gates (21:05Z). Approximate extrapolation: about 29 SP1 shards of 2^21 cycles at about 80 s each, 40 min of core proof, then hours of recursion; floor from the 5090's ratios (6x core, 4x compressed, block-78 to S_p): 9 min core, 13 min compressed

    For comparison (this log): the Apple M5 Max CPU on 4 October, loaded, block-56 shard 0: core 83.1 s, compressed 272.3 s; on 3 October the v0 guest on block-78: core 22.0 s, compressed 55.7 s. The RTX 5090: block-78 core 1.4 s, compressed 2.7 s (4 October, mining paused); a full shard at S_p compressed 10.9 s alone and 33.0 s beside the miner; an empty live shard 7.0 to 7.7 s beside the miner (5 October). No fresh Mac run tonight: the measure lock was held from 20:31Z (a read-width packbench, three builds, a 1,500-s proving-v1 network under run) and did not free inside the 10-minute window set for it.

    Reading, and the consequences (the design document, every number). Doubling the cycles added 4.5 s to the core proof and 3.1 s to the compressed proof: about 280 s of a CPU proof is fixed cost in the compressed-proof recursion, so no shard size brings a CPU proof under the launch deadline (20 to 60 s behind the tip) or near the 10-s assignment window; it fits only the v1 unproven deadline (600 s), which pays a CPU prover only when no card has proven the shard in 10 minutes. The 29.5 to 30.5 GB peak RSS means the CPU prover needs 32 GB free: a 64 GB an RTX 5090 on Windows (WSL2 takes half the host's RAM by default), a 32 GB Linux machine, a 64 GB Mac; a 16 GB machine cannot run it at all. Per tier: an AMD-only home miner (8, 12 or 16 GB, Windows or Linux) mines and does not prove, and loses the 20% proving-pool share; Apple silicon the same (the M5 Max mines at 26.7 MH/s, this log, 4 October); a mixed rig proves on its NVIDIA cards and the rig installer's prover_decision already skips every non-NVIDIA card (packaging/linux/bin/igneum-rig-lib.sh, branch rig-install), now a stated requirement; the app's provedefault.rs already keeps proving off on Apple silicon and off without an NVIDIA card. Decision asked of nobody: no CPU tier (the analysis, section 4a); the public line for the site, litepaper and Proving tile is in section 4c ("Proving needs an NVIDIA card with 16 GB or more today ... AMD and Apple cards mine. A prover for them lands when a zkVM ships one"). The first job proved nothing because an apostrophe inside a single-quoted awk program ended the quote and bash refused the loop while the job reported exit 0; the class fix is tools/amd-prove/check-job-bash.sh (bash -n on the embedded bash body before publishing) and the same bash -n inside the job before the run, both shown to refuse the bad body and pass the fixed one.

    Counter ASIC 2.0, the numbers

    -

    5 October 2026 (night). The chip-resistance layers measured on the three cards we own (Apple M5 Max, RTX 5090 on PC 1 and PC 2, RX 9070 XT on PC 1's eGPU), the decisions taken under the maintainers' delegated rules for the devnet, and the chip model before and after. Every number is from an entry above or from the plan documents named; approximate is marked. Levels: docs/plans/counter-asic-2-public.md.

    +

    5 October 2026 (night). The chip-resistance layers measured on the three cards we own (Apple M5 Max, RTX 5090 on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) and the RTX 5090 Windows rig, RX 9070 XT on the three-card Windows rig's eGPU), the decisions taken under the maintainers' delegated rules for the devnet, and the chip model before and after. Every number is from an entry above or from the plan documents named; approximate is marked. Levels: docs/plans/counter-asic-2-public.md.

    Program class v3 (the devnet, activation by height switch program_class_v3_activation_daa) = class v2's 128 x 4-byte loads, the era draw of the table layout and the working-set windows (layers 4 and 8), the cache growth rule (layer 6, option C: the cache doubles when the dataset doubles), the mixer at x8 (M16's multiplier), reserve family R1 (integer matrix, switched off) and the epoch length as a signalled reserve parameter (layer 9, 3,600 DAA s until a 90% signal). Not adopted on the measurements: wider reads (layer 1), the per-load width mix (layer 2), the per-warp write scratch (layer 3), the hot table (layer 5).

    Cardv2 MH/sv3 MH/s, six eras (spread)Bytes per hashLatency-bound shareDaily 1 GiB build, v2 / v3
    Apple M5 Max, Metal27.6827.85 to 27.98 (0.5%)5121.0621 / 21 ms
    RTX 5090, CUDA137.2135.90 to 137.70 (1.3%)5121.0125 / 23 ms
    RX 9070 XT, OpenCL18.0918.59 to 19.18 (3.1%)5120.9574 / 75 ms

    CPU verifier, one M5 Max core at load average 5.5 (the fixed crate, ca2-mixer 1ab8b21): v2 0.61 ms per warp, v3 (x8) 2.08 ms (3.4x), worst cold 2.15; the 10 ms gate holds 4.8x (4.6x on the worst cold unit). Bit-exact: every v3 pack's fingerprint equal on Metal, Apple OpenCL, CUDA and AMD OpenCL.

    @@ -650,38 +607,38 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    The user tiers. AMD RDNA 4 sits at about a seventh of a 5090 on this hash (its dependent-read rate: 2.4 G against 17.5 G per second), 2.2x worse per pound at list prices and 4.9x worse per watt (approximate); the card's memory system, not a tuning gap. The integrated tier on the CUDA and OpenCL one-click workers mines v3 with a restart per epoch until per-day dataset reuse lands (0.3.12). Card lifetime under the step schedule: a 4 GB card to year 4, 8 GB to year 12, 12 GB to year 28 with the cache freed after the daily build.

    The bounty. A bounty for any chip design beating a GPU by more than 2x on the published model, with a leaderboard by card model, follows the external review (spec O-1.17, January 2027); it is named publicly only once escrowed (docs/plans/funding.md, rule 3), which it is not yet.

    5 October 2026 (evening), proving v1: segment records, the chain rule, the unproven rule; what was measured tonight (proving engineer)

    -

    Branches proving-v1 (main repository, worktree igneum-wt-proving-v1; fork vendor/igneum-node-pv1 from a24ab01a). Rules: spec 7.8; plan docs/plans/proving-v1.md. Every row names its command. The live devnet was in a degraded state the whole evening: from 18:35Z the RTX 5090 workers on PC 1 and PC 2 exited at start on a pack seed mismatch (the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT, restart 60+ on PC 2 by 19:05Z, another agent's branch pack-loop), the Apple M5 Max app node was down from 17:45Z, so PC 2 mined 3.4 MH/s from its iGPU and PC 2's prover was the only prover; the coordinator held every PC 2 measurement at 19:00Z until the fleet mines again.

    +

    Branches proving-v1 (main repository, worktree igneum-wt-proving-v1; fork vendor/igneum-node-pv1 from a24ab01a). Rules: spec 7.8; plan docs/plans/proving-v1.md. Every row names its command. The live devnet was in a degraded state the whole evening: from 18:35Z the RTX 5090 workers on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) and the RTX 5090 Windows rig exited at start on a pack seed mismatch (the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT, restart 60+ on the RTX 5090 Windows rig by 19:05Z, another agent's branch pack-loop), the Apple M5 Max app node was down from 17:45Z, so the RTX 5090 Windows rig mined 3.4 MH/s from its iGPU and the RTX 5090 Windows rig's prover was the only prover; the coordinator held every the RTX 5090 Windows rig measurement at 19:00Z until the fleet mines again.

    Step 1, the prover default and its cost

    -
    WhatMeasured
    The default rule (app/igneum-app/src/provedefault.rs)cargo test --release -p igneum-app provedefault on this Mac (the app crate, build lock, 19:05Z): 5 passed (a 5090 with WSL2 on Windows is on; Windows without WSL2 off with the Set up hint; Linux needs no WSL2 and the 12 GB gate holds, a 10 GB 3080 and a 16 GB AMD card stay off; Apple silicon off; the biggest qualifying card is named)
    Mining alone against mining with the prover, first try (PC 2 job prover-cost-pc2-pv1, tools/proving-v1/pc2-prover-cost.ps1, published 18:40:48Z, ran 18:41:13Z)VOID: the job waited 20 min for the 5090 worker to hash and it never did (the pack fault above); "mining alone" was 0 MH/s
    Mining alone against mining with the prover, the re-run after the coordinator's go (job prover-cost-pc2-pv1b, ran 19:20:36Z to 19:51:17Z; the 5090 worker restored at 19:16Z and hashing throughout; prover OFF by POST /api/prove {"on":false} 19:40:39Z, back ON 19:46:09Z, left on). The job's own /api/state samples stayed empty on PC 2 (Invoke-RestMethod returns an object PowerShell 5.1 cannot walk, cards=0, the fix is for the next run), so the hash rate is read from the miner's own STATUS lines (miner-nvidia-1ccfe586-1 uploads, now=... MH/s wall, one every 30 s, the intake table miner_logs)prover OFF, 19:41:09 to 19:46:09Z: n 10, mean 124.72 MH/s, p50 124.81, min 124.10, max 125.38. Prover ON, 19:46:39 to 19:51:13Z: n 9, mean 119.74, p50 118.87, min 118.08, max 123.42. The 15 min before the job with the prover on (19:25 to 19:40Z): n 30, mean 119.88, p50 118.79. So the prover costs the 5090 5.0 MH/s, 4.0% of its hash rate, while it proves the devnet's empty shards one after another (1.4 a minute here: the node's paidShards 559 -> 566 over the 5-min phase). A full shard at S_p keeps the card busier (the 4 October run proved one in 10.9 s); the cost at that load is the chain job's row
    GPU memory during proving, first try (phase B of the first job: the prover on for 5 min, 298 one-second nvidia-smi --query-gpu=memory.used samples, the 5090 worker dead so the card held nothing else)memory.used min 1,654 MiB, max 13,816 MiB, utilisation mean 2.7%, power max 190.6 W: the prover alone on empty shards
    GPU memory with the miner AND the prover on the card (the re-run's phase B, 298 one-second samples, 19:46 to 19:51Z)memory.used min 3,396 MiB (the miner's dataset and program resident), max 15,590 MiB, utilisation mean 92.9%, power max 328.6 W. So the prover's own peak is about 12.2 GB on an empty shard (15,590 minus the miner's 3,396), and the two together need 15.6 GB: a 16 GB card (5080, 9070 XT class, if it had a CUDA path) sits 0.4 GB under tonight's peak with no room for a full shard, a 24 GB 4090 has 8.4 GB of headroom, a 12 GB card cannot mine and prove at once on this build. The full-shard peak is the chain job's row
    Shards per minute with the mining worker deadthe node's paidShards 510 -> 518 over the 5-min phase: 1.6 shards a minute from one 5090 through the app's loop (export, cut, prove, sign, submit)
    Host RAM (Windows Win32_OperatingSystem and the vmmem working set, sampled every 15 s)host used 25,550 MB of 63,132 MB at the end; the WSL2 VM's working set 7,915 MB (2,334 MB used of 30,914 MB inside the distribution)
    The SP1 GPU server's compiled targets (cuobjdump --list-elf <server path> inside PC 2's Ubuntu-24.04, CUDA 12.8, driver 610.47)sp1-gpu-server 6.8.1 (251,306,680 bytes, sha256 c2642ad1c42e85d8525159cf0c7cd5200d8766c9be1283f452a1f9bf9fea725c, the asset sp1_gpu_server_v6.8.1_x86_64.tar.gz the SDK downloads, sp1-cuda-6.8.1/src/server.rs): one ELF each for sm_80, sm_86, sm_89, sm_90, sm_100 and sm_120; strings finds compute_120 PTX as well. So sm_89 (Ada: RTX 4090, 4080) is compiled in natively, no JIT; so are Ampere (3090, 3060), Hopper, Blackwell datacentre (sm_100) and consumer (sm_120, the 5090). Nothing for AMD (no HIP path in SP1)
    +
    WhatMeasured
    The default rule (app/igneum-app/src/provedefault.rs)cargo test --release -p igneum-app provedefault on this Mac (the app crate, build lock, 19:05Z): 5 passed (a 5090 with WSL2 on Windows is on; Windows without WSL2 off with the Set up hint; Linux needs no WSL2 and the 12 GB gate holds, a 10 GB 3080 and a 16 GB AMD card stay off; Apple silicon off; the biggest qualifying card is named)
    Mining alone against mining with the prover, first try (the RTX 5090 Windows rig job prover-cost-pc2-pv1, tools/proving-v1/pc2-prover-cost.ps1, published 18:40:48Z, ran 18:41:13Z)VOID: the job waited 20 min for the 5090 worker to hash and it never did (the pack fault above); "mining alone" was 0 MH/s
    Mining alone against mining with the prover, the re-run after the coordinator's go (job prover-cost-pc2-pv1b, ran 19:20:36Z to 19:51:17Z; the 5090 worker restored at 19:16Z and hashing throughout; prover OFF by POST /api/prove {"on":false} 19:40:39Z, back ON 19:46:09Z, left on). The job's own /api/state samples stayed empty on the RTX 5090 Windows rig (Invoke-RestMethod returns an object PowerShell 5.1 cannot walk, cards=0, the fix is for the next run), so the hash rate is read from the miner's own STATUS lines (miner-nvidia-1ccfe586-1 uploads, now=... MH/s wall, one every 30 s, the intake table miner_logs)prover OFF, 19:41:09 to 19:46:09Z: n 10, mean 124.72 MH/s, p50 124.81, min 124.10, max 125.38. Prover ON, 19:46:39 to 19:51:13Z: n 9, mean 119.74, p50 118.87, min 118.08, max 123.42. The 15 min before the job with the prover on (19:25 to 19:40Z): n 30, mean 119.88, p50 118.79. So the prover costs the 5090 5.0 MH/s, 4.0% of its hash rate, while it proves the devnet's empty shards one after another (1.4 a minute here: the node's paidShards 559 -> 566 over the 5-min phase). A full shard at S_p keeps the card busier (the 4 October run proved one in 10.9 s); the cost at that load is the chain job's row
    GPU memory during proving, first try (phase B of the first job: the prover on for 5 min, 298 one-second nvidia-smi --query-gpu=memory.used samples, the 5090 worker dead so the card held nothing else)memory.used min 1,654 MiB, max 13,816 MiB, utilisation mean 2.7%, power max 190.6 W: the prover alone on empty shards
    GPU memory with the miner AND the prover on the card (the re-run's phase B, 298 one-second samples, 19:46 to 19:51Z)memory.used min 3,396 MiB (the miner's dataset and program resident), max 15,590 MiB, utilisation mean 92.9%, power max 328.6 W. So the prover's own peak is about 12.2 GB on an empty shard (15,590 minus the miner's 3,396), and the two together need 15.6 GB: a 16 GB card (5080, 9070 XT class, if it had a CUDA path) sits 0.4 GB under tonight's peak with no room for a full shard, a 24 GB 4090 has 8.4 GB of headroom, a 12 GB card cannot mine and prove at once on this build. The full-shard peak is the chain job's row
    Shards per minute with the mining worker deadthe node's paidShards 510 -> 518 over the 5-min phase: 1.6 shards a minute from one 5090 through the app's loop (export, cut, prove, sign, submit)
    Host RAM (Windows Win32_OperatingSystem and the vmmem working set, sampled every 15 s)host used 25,550 MB of 63,132 MB at the end; the WSL2 VM's working set 7,915 MB (2,334 MB used of 30,914 MB inside the distribution)
    The SP1 GPU server's compiled targets (cuobjdump --list-elf <server path> inside the RTX 5090 Windows rig's Ubuntu-24.04, CUDA 12.8, driver 610.47)sp1-gpu-server 6.8.1 (251,306,680 bytes, sha256 c2642ad1c42e85d8525159cf0c7cd5200d8766c9be1283f452a1f9bf9fea725c, the asset sp1_gpu_server_v6.8.1_x86_64.tar.gz the SDK downloads, sp1-cuda-6.8.1/src/server.rs): one ELF each for sm_80, sm_86, sm_89, sm_90, sm_100 and sm_120; strings finds compute_120 PTX as well. So sm_89 (Ada: RTX 4090, 4080) is compiled in natively, no JIT; so are Ampere (3090, 3060), Hopper, Blackwell datacentre (sm_100) and consumer (sm_120, the 5090). Nothing for AMD (no HIP path in SP1)

    Step 2, aggregated chains

    -
    WhatMeasured
    The new host (--mode chain, aggregate, verify-segment) against every fixture nativelyigneum-prove-host <f> --mode native on the Apple M5 Max for the 12 fixtures of proving/fixtures/ (9 block, 3 fee-switch), host built from this branch 19:06Z: every one MATCHES (the package gate's native half); --mode id: shard 0x2b1a81cb..., aggregator 0x474678f3..., the 0.3.9 pin, unchanged
    Eight consecutive live fixturesigneum_exportSegments 0x0..0x13cb4 on node 1's exec RPC (127.0.0.1:26790, read-only, 19:06 UTC, tip 81,076): 71,042,616 bytes, 81,077 segments, 28 accounts, 0.5 s; igneum-prove-export export.json <n> block-<n>.json for 81046..81053: replayed 81,077 segments from genesis in 1.8 s each, every state root equal to the node's; one shard a block, 0 pgas (no transactions on the devnet tonight), proving/fixtures/chain/
    Chain of 2 on the Apple M5 Max CPU (the known-finished case of --mode chain before the GPU; M5 Max under the live nodes, the harness and two builds)SP1_PROVER=cpu igneum-prove-host --mode chain --chain block-81046.json,block-81047.json --out results.json under the run lock, 19:07:48Z to 19:11:28Z: setup 12.2 s; block 81046: shard 0 compressed 55.4 s (1,272,897 bytes, verify 0.036 s), aggregate 52.0 s (1,272,909 bytes, verify 0.031 s), chain_len 1, agg_vk zero; block 81047: shard 41.3 s, aggregate WITH the previous block proof 59.1 s, chain_len 2, agg_vk = the pinned aggregator id; end to end 207.9 s; final proof 1,272,909 bytes, statement 0x232276f4... The recursion over the previous proof cost 7 s more than the first aggregation on this CPU
    --mode verify-segment on that proof (the node's path: SP1 light verifier, pinned aggregator key)VERIFIED in 0.032 s (0.27 s wall, three runs: 0.033, 0.032, 0.032); known-failed: a wrong statement NOT VERIFIED (0.032 s); the shard verifier (--mode verify) on the segment proof NOT VERIFIED, "program id 0x474678f3... IS NOT OURS 0x2b1a81cb..."
    Chain of 8 on the RTX 5090 (N = 2, 4, 8), job chain-pc2-pv1b (tools/proving-v1/pc2-chain.ps1; the package igneum-prove-wsl2-pv1.zip eb6dccf8..., 1.5 MB, fetched by fetch-prove-pv1 19:51Z; the first try chain-pc2-pv1 died in its own export step, fixed)Ran 19:58:37Z: the export from PC 2's node (72,901,414 bytes, 1.4 s), the host built in WSL2 against the live build's warm target dir in 6 s and installed to <server path> (the live <server path> host untouched, sha 29cc4768...), --mode id the pinned pair; eight consecutive fixtures 83346..83353 cut, every one MATCHES natively. The chain on the GPU (SP1_PROVER=cuda, the miner mining on the same card at 119 MH/s): setup 12.7 s; block 83346: shard 7.4 s, aggregate 7.6 s (chain_len 1), 15.1 s; block 83347: shard 7.2 s, aggregate WITH the previous proof 9.5 s (chain_len 2, agg_vk the pinned aggregator id), 16.8 s, cumulative 31.8 s over 2 blocks; block 83348: shard 7.0 s, then at 20:01:09Z the app quit and aborted the job ("quit: stopping the miners, then the node", then "job chain-pc2-pv1b: aborted (the app is quitting)"; NOT an update: nothing of 0.3.10 was published; the log gives the quit no source; 20 s earlier the efficiency sweep's administrator prompt had been cancelled at the keyboard, and 13 s earlier the live prover had failed with "CudaClientError: Connect(PermissionDenied)", the root-owned socket my job had left, below). So N = 2 measured: 31.8 s of GPU time for two empty blocks, the chained aggregation 1.9 s dearer than the first; N = 4 and 8 are the re-run chain-pc2-pv1c after the restart. An empty shard's compressed proof on the 5090 is 7.0 to 7.4 s (the 200-pgas shard of 4 October took 2.7 s with the card to itself; tonight the miner held it at 92% utilisation)
    The chain of 8, the third run chain-pc2-pv1c (20:05:21Z to 20:08:33Z, after the app restart; blocks 83616..83623 from PC 2's node at tip 83646, the same script; results tools/proving-v1/chain-pc2-2026-10-05.json)Build 5 s (warm), eight fixtures cut and MATCHING natively, setup 15.7 s, then on the GPU with the miner mining on the same card: shard proofs 7.3 to 7.7 s each (8 x, 59.5 s), aggregations 7.9 s for the first block and 9.6 to 9.7 s for every chained one (75.5 s), every proof VERIFIED, end to end 135.6 s for 8 blocks (17.0 s a block from the second on). Cumulative: N = 2 at 32.6 s, N = 4 at 66.8 s, N = 8 at 135.6 s. The final proof is 1,272,909 bytes whatever N (chain_len 8, agg_vk the pinned aggregator id), the record 586 bytes; --mode verify-segment on it: VERIFIED in 0.039, 0.037, 0.040 s after a 0.26-s light-verifier setup, the same three runs each time. GPU memory over the chain (152 one-second samples): max 16,751 MiB with the miner's 3.4 GB resident, so the chained aggregation holds about 13.4 GB, 1.2 GB over the shard-only peak; WSL used 2,456 MB
    +
    WhatMeasured
    The new host (--mode chain, aggregate, verify-segment) against every fixture nativelyigneum-prove-host <f> --mode native on the Apple M5 Max for the 12 fixtures of proving/fixtures/ (9 block, 3 fee-switch), host built from this branch 19:06Z: every one MATCHES (the package gate's native half); --mode id: shard 0x2b1a81cb..., aggregator 0x474678f3..., the 0.3.9 pin, unchanged
    Eight consecutive live fixturesigneum_exportSegments 0x0..0x13cb4 on node 1's exec RPC (127.0.0.1:26790, read-only, 19:06 UTC, tip 81,076): 71,042,616 bytes, 81,077 segments, 28 accounts, 0.5 s; igneum-prove-export export.json <n> block-<n>.json for 81046..81053: replayed 81,077 segments from genesis in 1.8 s each, every state root equal to the node's; one shard a block, 0 pgas (no transactions on the devnet tonight), proving/fixtures/chain/
    Chain of 2 on the Apple M5 Max CPU (the known-finished case of --mode chain before the GPU; M5 Max under the live nodes, the harness and two builds)SP1_PROVER=cpu igneum-prove-host --mode chain --chain block-81046.json,block-81047.json --out results.json under the run lock, 19:07:48Z to 19:11:28Z: setup 12.2 s; block 81046: shard 0 compressed 55.4 s (1,272,897 bytes, verify 0.036 s), aggregate 52.0 s (1,272,909 bytes, verify 0.031 s), chain_len 1, agg_vk zero; block 81047: shard 41.3 s, aggregate WITH the previous block proof 59.1 s, chain_len 2, agg_vk = the pinned aggregator id; end to end 207.9 s; final proof 1,272,909 bytes, statement 0x232276f4... The recursion over the previous proof cost 7 s more than the first aggregation on this CPU
    --mode verify-segment on that proof (the node's path: SP1 light verifier, pinned aggregator key)VERIFIED in 0.032 s (0.27 s wall, three runs: 0.033, 0.032, 0.032); known-failed: a wrong statement NOT VERIFIED (0.032 s); the shard verifier (--mode verify) on the segment proof NOT VERIFIED, "program id 0x474678f3... IS NOT OURS 0x2b1a81cb..."
    Chain of 8 on the RTX 5090 (N = 2, 4, 8), job chain-pc2-pv1b (tools/proving-v1/pc2-chain.ps1; the package igneum-prove-wsl2-pv1.zip eb6dccf8..., 1.5 MB, fetched by fetch-prove-pv1 19:51Z; the first try chain-pc2-pv1 died in its own export step, fixed)Ran 19:58:37Z: the export from the RTX 5090 Windows rig's node (72,901,414 bytes, 1.4 s), the host built in WSL2 against the live build's warm target dir in 6 s and installed to <server path> (the live <server path> host untouched, sha 29cc4768...), --mode id the pinned pair; eight consecutive fixtures 83346..83353 cut, every one MATCHES natively. The chain on the GPU (SP1_PROVER=cuda, the miner mining on the same card at 119 MH/s): setup 12.7 s; block 83346: shard 7.4 s, aggregate 7.6 s (chain_len 1), 15.1 s; block 83347: shard 7.2 s, aggregate WITH the previous proof 9.5 s (chain_len 2, agg_vk the pinned aggregator id), 16.8 s, cumulative 31.8 s over 2 blocks; block 83348: shard 7.0 s, then at 20:01:09Z the app quit and aborted the job ("quit: stopping the miners, then the node", then "job chain-pc2-pv1b: aborted (the app is quitting)"; NOT an update: nothing of 0.3.10 was published; the log gives the quit no source; 20 s earlier the efficiency sweep's administrator prompt had been cancelled at the keyboard, and 13 s earlier the live prover had failed with "CudaClientError: Connect(PermissionDenied)", the root-owned socket my job had left, below). So N = 2 measured: 31.8 s of GPU time for two empty blocks, the chained aggregation 1.9 s dearer than the first; N = 4 and 8 are the re-run chain-pc2-pv1c after the restart. An empty shard's compressed proof on the 5090 is 7.0 to 7.4 s (the 200-pgas shard of 4 October took 2.7 s with the card to itself; tonight the miner held it at 92% utilisation)
    The chain of 8, the third run chain-pc2-pv1c (20:05:21Z to 20:08:33Z, after the app restart; blocks 83616..83623 from the RTX 5090 Windows rig's node at tip 83646, the same script; results tools/proving-v1/chain-pc2-2026-10-05.json)Build 5 s (warm), eight fixtures cut and MATCHING natively, setup 15.7 s, then on the GPU with the miner mining on the same card: shard proofs 7.3 to 7.7 s each (8 x, 59.5 s), aggregations 7.9 s for the first block and 9.6 to 9.7 s for every chained one (75.5 s), every proof VERIFIED, end to end 135.6 s for 8 blocks (17.0 s a block from the second on). Cumulative: N = 2 at 32.6 s, N = 4 at 66.8 s, N = 8 at 135.6 s. The final proof is 1,272,909 bytes whatever N (chain_len 8, agg_vk the pinned aggregator id), the record 586 bytes; --mode verify-segment on it: VERIFIED in 0.039, 0.037, 0.040 s after a 0.26-s light-verifier setup, the same three runs each time. GPU memory over the chain (152 one-second samples): max 16,751 MiB with the miner's 3.4 GB resident, so the chained aggregation holds about 13.4 GB, 1.2 GB over the shard-only peak; WSL used 2,456 MB

    Reading the chain numbers. Aggregation is a fixed cost per block (9.7 s here), not per segment: the recursion verifies one more proof whatever chain_len, so the record for N blocks costs N aggregations and the verifier one. Against 4 October with the miner stopped (aggregate 2.2 to 2.5 s, a 200-pgas shard 2.7 s), tonight's 9.7 s and 7.3 s say the miner's 92% utilisation slows the prover about 3 to 4x while the prover slows the miner 4%: the card is shared, and the lottery wins the arbitration. A machine that mines and proves at once delivers one empty block's proof and aggregation in 17 s; one that only proves, about 5 s (approximate, from the 4 October stages).

    Step 3, coverage

    -
    WhatMeasured
    A 3-minute window at 18:57Z on node 1 (node tools/proving-v1/coverage.mjs --minutes 3, chain blocks 80754..80839, 86 blocks)4 blocks with a paid shard (4.7%), 4 fully proven, 4 of 86 shards; on-chain latency (carrier timestamp minus block timestamp) n 4: min 36 s, p50 39 s, max 44 s; 0 content blocks. One prover (PC 2), the Apple M5 Max verifier node down, PC 2 producing few blocks (3.4 MH/s): the degraded state above, not the fleet's number
    A 30-minute window, 19:13 to 19:43Z, the degraded fleet (PC 2 the only prover, its 5090 worker restored at 19:16Z, the Apple M5 Max app node down by decision: the Apple M5 Max app is attached to node 1)node tools/proving-v1/coverage.mjs --minutes 30 --watch on node 1: chain blocks 81236..82668, 1,433 blocks; 38 with a paid shard (2.7%), all 38 fully proven (one shard a block, 0 content blocks); on-chain latency n 38: min 36, p50 44, p90 52, p99 62, max 65 s. The live page's 10-minute proving object read 0 shards and 0 provers at 19:42Z (it counts what its own node verified; that node is the Apple M5 Max app node, down), so the chain's own count is the number
    A 30-minute window with the fleet mining (PC 2 at 119 MH/s from 19:16Z, PC 1 at 128.8 from 19:18Z; PC 2 still the only prover, its prover OFF for the 5 min of the cost job's phase A inside this window; the Apple M5 Max app node down by decision)coverage.mjs --minutes 30 --watch, 19:21 to 19:51Z on node 1: chain blocks 81644..83069, 1,426 blocks; 34 with a paid shard (2.4%), all fully proven (one shard a block, no content); on-chain latency n 34: min 38, p50 44, p90 51, p99 52, max 53 s. One 5090 through the app's loop as it is covers 2.4 to 2.7% of the blocks; the latency from block to carried record is 44 s at the median, under the litepaper's minute, and would be the same for every block if the fleet were 40 cards (the table below)
    +
    WhatMeasured
    A 3-minute window at 18:57Z on node 1 (node tools/proving-v1/coverage.mjs --minutes 3, chain blocks 80754..80839, 86 blocks)4 blocks with a paid shard (4.7%), 4 fully proven, 4 of 86 shards; on-chain latency (carrier timestamp minus block timestamp) n 4: min 36 s, p50 39 s, max 44 s; 0 content blocks. One prover (the RTX 5090 Windows rig), the Apple M5 Max verifier node down, the RTX 5090 Windows rig producing few blocks (3.4 MH/s): the degraded state above, not the fleet's number
    A 30-minute window, 19:13 to 19:43Z, the degraded fleet (the RTX 5090 Windows rig the only prover, its 5090 worker restored at 19:16Z, the Apple M5 Max app node down by decision: the Apple M5 Max app is attached to node 1)node tools/proving-v1/coverage.mjs --minutes 30 --watch on node 1: chain blocks 81236..82668, 1,433 blocks; 38 with a paid shard (2.7%), all 38 fully proven (one shard a block, 0 content blocks); on-chain latency n 38: min 36, p50 44, p90 52, p99 62, max 65 s. The live page's 10-minute proving object read 0 shards and 0 provers at 19:42Z (it counts what its own node verified; that node is the Apple M5 Max app node, down), so the chain's own count is the number
    A 30-minute window with the fleet mining (the RTX 5090 Windows rig at 119 MH/s from 19:16Z, the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) at 128.8 from 19:18Z; the RTX 5090 Windows rig still the only prover, its prover OFF for the 5 min of the cost job's phase A inside this window; the Apple M5 Max app node down by decision)coverage.mjs --minutes 30 --watch, 19:21 to 19:51Z on node 1: chain blocks 81644..83069, 1,426 blocks; 34 with a paid shard (2.4%), all fully proven (one shard a block, no content); on-chain latency n 34: min 38, p50 44, p90 51, p99 52, max 53 s. One 5090 through the app's loop as it is covers 2.4 to 2.7% of the blocks; the latency from block to carried record is 44 s at the median, under the litepaper's minute, and would be the same for every block if the fleet were 40 cards (the table below)

    Step 3, the fleet size (arithmetic from measured inputs; every input names its entry)

    -

    Inputs, all RTX 5090 (PC 2), SP1 6.8.1 cuda: a full shard at the provisional S_p (6.75 M pgas) compressed in 10.9 s and the four shards of a near-B_p block in 10.2 to 10.7 s each (bench-log 4 October 2026, "shard proving on the RTX 5090", runs run-20261004-173115 and run-20261004-r3-shards); one aggregation 2.2 s (two shards) to 2.5 s (four shards), the same entry; tonight's chain of 2 on the Apple M5 Max CPU shows the recursion over the previous block proof costs the same order as a first aggregation (52.0 s against 59.1 s), so the GPU figure for a chained aggregation is taken as 2.5 s, approximate, until the held PC 2 chain job measures it; the app's live loop tonight: 1.6 shards a minute per card on empty shards (export, cut, key setup, prove, sign, submit: about 37 s a shard, of which the proof is a few seconds), bench-log step 1 above. A 5090 proves one thing at a time.

    +

    Inputs, all RTX 5090 (the RTX 5090 Windows rig), SP1 6.8.1 cuda: a full shard at the provisional S_p (6.75 M pgas) compressed in 10.9 s and the four shards of a near-B_p block in 10.2 to 10.7 s each (bench-log 4 October 2026, "shard proving on the RTX 5090", runs run-20261004-173115 and run-20261004-r3-shards); one aggregation 2.2 s (two shards) to 2.5 s (four shards), the same entry; tonight's chain of 2 on the Apple M5 Max CPU shows the recursion over the previous block proof costs the same order as a first aggregation (52.0 s against 59.1 s), so the GPU figure for a chained aggregation is taken as 2.5 s, approximate, until the held the RTX 5090 Windows rig chain job measures it; the app's live loop tonight: 1.6 shards a minute per card on empty shards (export, cut, key setup, prove, sign, submit: about 37 s a shard, of which the proof is a few seconds), bench-log step 1 above. A 5090 proves one thing at a time.

    Block content at 1 block/sShard proofs a second (fleet)Card-seconds a second for shardsAggregations a secondCard-seconds a second for aggregation5090-class cards for 100%Rule
    empty blocks (tonight's devnet), the app's loop as it is, the card also mining13719.7 (measured, chain-pc2-pv1c)47one shard per block, the loop's 37 s each plus a chained aggregation
    empty blocks, the chain mode's shape (one key setup per process, proofs back to back), the card also mining17.4 (measured)19.7 (measured)1817.1 card-seconds a block, chain-pc2-pv1c
    empty blocks, cards that only prove12.7 (4 October, a 200-pgas shard)12.5 (4 October)6 (approximate)the miner's 92% utilisation costs the prover 3 to 4x
    one full shard a block (S_p, 6.75 M pgas), cards that only prove110.912.5144 October's stages
    one full shard a block, the card also mining1about 35 (approximate: 10.9 x 3.2, tonight's ratio)19.7about 45 (approximate)the full-shard proof with the miner on the card is not measured
    blocks at B_p (four full shards), cards that only prove442.512.5454 x 10.6 + 2.5
    at the adopted v1 budgets (B_p 120,000 pgas, S_p 30,000, from DAA 210,000 on the devnet): a v1 shard of transfers ran at 213 to 236 cycles per pgas (bench-log 5 October, "the prover carries both fee tables"), 7 M cycles a shard against 60 M for the prototype shard4under 42.5 (the 5090 time for a 7 M-cycle shard is not measured; scaling 10.9 s by cycles gives about 1.3 s, approximate)12.5 to 9.78 to 15 (approximate)measure before the switch lands

    Reading. The card count is the sum of card-seconds of work per block-second, rounded up, with no slack for the exclusive window, the relay or a card's idle gaps; the devnet's own numbers tonight (one card, 1.4 to 1.6 shards a minute, 2.4 to 4.7% of blocks) are the first row. Two levers, both measured tonight: the loop (a shard's carriage through export, cut and a 12-s key setup is 25 s on top of a 7-s proof; the host's --mode aggregate and --mode chain hold one key setup per process and the prover loop should do the same, the 0.3.11 item in the plan) and the card's other job (a mining card proves 3 to 4x slower than an idle one, chain-pc2-pv1c against 4 October; the prover's cost to mining is 4%). A fleet of 18 mining 5090s, or 6 proving-only ones, covers an empty-block chain at 1 block/s through the chain mode; the mandatory rule waits for the measured share to reach one, not for these rows.

    The 12 GB requirement (the maintainers, 20:1xZ: "make sure we can prove on 12gb cards"): the GPU memory peak against SP1's knobs

    -

    Job memsweep-pc2-pv1 (tools/proving-v1/pc2-memory-sweep.ps1), PC 2's RTX 5090 (32,607 MiB), the miners STOPPED by the job and the live prover switched off (its sp1-gpu-server would otherwise be the one the client connects to), every row: the server killed first, a 1-s nvidia-smi memory.used sampler, one --mode compressed --shard 0 run of the pv1 host (<server path>, SP1 6.8.1 cuda, sp1-gpu-server 6.8.1), 20:19 to 20:25Z. The knobs are the environment the GPU server inherits from the host process (sp1-core-executor-6.8.1/src/opts.rs: SHARD_SIZE, ELEMENT_THRESHOLD, HEIGHT_THRESHOLD, MINIMAL_TRACE_CHUNK_THRESHOLD, TRACE_CHUNK_SLOTS; sp1-prover-6.8.1/src/worker/config.rs: the SP1_WORKER_NUM_* and *_BUFFER_SIZE counts, defaults 4 core workers, 8 recursion prover workers). Idle card before the sweep: 1,732 MiB.

    +

    Job memsweep-pc2-pv1 (tools/proving-v1/pc2-memory-sweep.ps1), the RTX 5090 Windows rig's RTX 5090 (32,607 MiB), the miners STOPPED by the job and the live prover switched off (its sp1-gpu-server would otherwise be the one the client connects to), every row: the server killed first, a 1-s nvidia-smi memory.used sampler, one --mode compressed --shard 0 run of the pv1 host (<server path>, SP1 6.8.1 cuda, sp1-gpu-server 6.8.1), 20:19 to 20:25Z. The knobs are the environment the GPU server inherits from the host process (sp1-core-executor-6.8.1/src/opts.rs: SHARD_SIZE, ELEMENT_THRESHOLD, HEIGHT_THRESHOLD, MINIMAL_TRACE_CHUNK_THRESHOLD, TRACE_CHUNK_SLOTS; sp1-prover-6.8.1/src/worker/config.rs: the SP1_WORKER_NUM_* and *_BUFFER_SIZE counts, defaults 4 core workers, 8 recursion prover workers). Idle card before the sweep: 1,732 MiB.

    Config (environment)FixtureCyclesPeak MiBCompressed prove sVerified
    baseline (no knob)block-338-shard1, a full shard at S_p (6.75 M pgas)60,415,37628,29511.4yes
    baselineblock-83616, an empty live shard280,70613,8632.3yes
    ELEMENT_THRESHOLD 2^27full shard60.4 M28,32610.9yes
    ELEMENT_THRESHOLD 2^26, HEIGHT_THRESHOLD 2^21full shard60.4 M28,32610.7yes
    every worker count and buffer 1full shard60.4 M28,32620.8yes
    every worker count and buffer 2full shard60.4 M28,32712.9yes
    workers 1 + ELEMENT 2^27full shard60.4 M28,26320.3yes
    workers 1 + ELEMENT 2^26 + HEIGHT 2^21full shard60.4 M28,32620.6yes
    workers 1 + ELEMENT 2^26 + HEIGHT 2^21 + trace chunks 4 M x 2 slotsfull shard60.4 M28,35822.6yes
    workers 1 + ELEMENT 2^25 + HEIGHT 2^20full shard60.4 M22,91922.2yes
    workers 1 + ELEMENT 2^26 + HEIGHT 2^21empty shard280,70613,8612.6yes

    Reading. The GPU memory of a compressed shard proof is 13.9 GB for a shard of 280,000 cycles and 28.3 GB for one of 60 M cycles, and no knob the environment carries moves the floor: the worker counts only slow the proof (11.4 s to 20.8 s), the trace thresholds at 2^26 and 2^27 change nothing, and the smallest trace threshold tried (2^25 elements, 2^20 rows) takes 5.4 GB off the full shard (22.9 GB) at twice the time. The floor sits in the GPU server's own allocation, not in the shard: an empty shard with every knob at its minimum still takes 13.9 GB. So on SP1 6.8.1's sp1-gpu-server as shipped, a 12 GB card cannot prove even an empty shard (13.9 GB), and the 11.0 GB target of tonight's requirement is out of reach from the environment. The S_p/2 and S_p/4 cuts of block 344 did not run: the package carries no tools/prove-fixtures/seq.json (the cut rows need the export; they would sit between the two measured points, and the floor is the binding number anyway). What is left to try, in order: the server's own options (its --help and the option names in its strings: the miner-on job prints them), SP1's core-only proof (the node needs the compressed proof, so this changes the protocol), and an SP1 release built for smaller cards (the 6.8.1 release notes are not read here; approximate: the project's documentation names 24 GB as the GPU requirement, proving/windows-wsl2/setup-wsl.sh quotes it).

    The same shard with the miner running (the 16 GB requirement), and the GPU server's own options

    Job memminer-pc2-pv1 (tools/proving-v1/pc2-memory-miner-on.ps1), 20:28 to 20:30Z, the miner at full rate on the card, the live prover off for the run, the same 1-s sampler: the full shard at S_p (60.4 M cycles) peaked at 30,039 MiB and took 33.0 s (28,295 MiB and 11.4 s with the card to itself: the miner costs the prover 2.9x in time and 1.7 GB of memory); the empty shard 15,670 MiB and 7.7 s (13,863 and 2.3 s alone). So a 32 GB card mines and proves the prototype shard with 2.5 GB to spare; a 24 GB card cannot prove it even alone (28.3 GB); a 16 GB card cannot hold even the empty shard beside the miner (15.7 GB, the display and driver on top). sp1-gpu-server --help prints only --version: it has no options of its own, and its strings carry no memory setting (CUDA_OUT_OF_MEMORY is an error name). The shard SIZE is therefore the only lever left on this build, measured next as the S_p curve.

    -

    The root-socket fault (the class, fixed the same evening). The chain and memory jobs ran the host as root inside WSL2; the first sp1-gpu-server they started left /tmp/sp1-cuda-0.sock owned by root, and the live prover (the app's own WSL user) then failed every shard with CudaClientError: Connect(Os { code: 13, kind: PermissionDenied }) (PC 2 app log 1791230456, 20:00:56Z) until the socket was gone. Every pv1 playbook now kills the server and unlinks /tmp/sp1-cuda-*.sock at its start and end, tools/ci/prover-socket-check.sh fails CI on any playbook that runs a prove mode as root without both lines (shown failing on pc2-prover-cost.ps1 before its --mode id-only exemption, passing after), and the plan carries the rule: a prover job on a shared card runs as the app's user or cleans its socket. It recurred at 21:25Z from another agent's job (agg-cost-pc2-1, the same root-run shape) and survived the 0.3.10 restart at 21:49:41Z; the fix job socketfix-pc2-pv1 (tools/proving-v1/pc2-socket-fix.ps1, 22:01:14 to 22:02:12Z) found /tmp/sp1-cuda-0.sock owned by root, removed it, switched the prover off and on, and the app's next shard (block 89011 shard 0) was proven and submitted in 34 s and paid 0.93 IGN at 22:02:24Z. Playbooks that run the host: tools/proving-v1/pc2-chain.ps1, pc2-memory-sweep.ps1, pc2-memory-miner-on.ps1, pc2-sp-curve.ps1 (all root, all with the cleanup now; the first two chain and sweep runs had none), pc2-prover-cost.ps1 (--mode id only), relay/playbooks/shard-test.ps1 and proving/windows-wsl2/prove-shard.sh, prove-block.sh (the app's user, not root), tools/proving-v0/run.mjs (the Apple M5 Max, no server).

    +

    The root-socket fault (the class, fixed the same evening). The chain and memory jobs ran the host as root inside WSL2; the first sp1-gpu-server they started left /tmp/sp1-cuda-0.sock owned by root, and the live prover (the app's own WSL user) then failed every shard with CudaClientError: Connect(Os { code: 13, kind: PermissionDenied }) (the RTX 5090 Windows rig app log 1791230456, 20:00:56Z) until the socket was gone. Every pv1 playbook now kills the server and unlinks /tmp/sp1-cuda-*.sock at its start and end, tools/ci/prover-socket-check.sh fails CI on any playbook that runs a prove mode as root without both lines (shown failing on pc2-prover-cost.ps1 before its --mode id-only exemption, passing after), and the plan carries the rule: a prover job on a shared card runs as the app's user or cleans its socket. It recurred at 21:25Z from another agent's job (agg-cost-pc2-1, the same root-run shape) and survived the 0.3.10 restart at 21:49:41Z; the fix job socketfix-pc2-pv1 (tools/proving-v1/pc2-socket-fix.ps1, 22:01:14 to 22:02:12Z) found /tmp/sp1-cuda-0.sock owned by root, removed it, switched the prover off and on, and the app's next shard (block 89011 shard 0) was proven and submitted in 34 s and paid 0.93 IGN at 22:02:24Z. Playbooks that run the host: tools/proving-v1/pc2-chain.ps1, pc2-memory-sweep.ps1, pc2-memory-miner-on.ps1, pc2-sp-curve.ps1 (all root, all with the cleanup now; the first two chain and sweep runs had none), pc2-prover-cost.ps1 (--mode id only), relay/playbooks/shard-test.ps1 and proving/windows-wsl2/prove-shard.sh, prove-block.sh (the app's user, not root), tools/proving-v0/run.mjs (the Apple M5 Max, no server).

    The S_p curve: peak GPU memory against shard size against time, the card to itself (the first of the two curve jobs)

    -

    Job spcurve-stopped-pc2-pv1 (tools/proving-v1/pc2-sp-curve.ps1, the miners stopped by the job, the live prover off, the server killed and its socket unlinked around every point, a 1-s nvidia-smi sampler), 20:33 to 20:37Z, PC 2's RTX 5090, the pv1 host (this run's --budget points were ignored by the pv1 host, so its block-344 rows are the fixture's own 6.75 M-pgas shard 0 twice; the pv1b host's re-plans at 2.25 M and 4.5 M pgas are the next job's rows). Idle card 1,743 MiB.

    +

    Job spcurve-stopped-pc2-pv1 (tools/proving-v1/pc2-sp-curve.ps1, the miners stopped by the job, the live prover off, the server killed and its socket unlinked around every point, a 1-s nvidia-smi sampler), 20:33 to 20:37Z, the RTX 5090 Windows rig's RTX 5090, the pv1 host (this run's --budget points were ignored by the pv1 host, so its block-344 rows are the fixture's own 6.75 M-pgas shard 0 twice; the pv1b host's re-plans at 2.25 M and 4.5 M pgas are the next job's rows). Idle card 1,743 MiB.

    ShardpgasWitness bytesSP1 cyclesPeak MiB, card aloneCompressed prove sKnob
    block 83616, an empty live shard013,964280,70613,8742.2none
    block 56, one transfer6004,902556,36913,9073.2none
    fees-v1-shards2 shard 0, a shard at the ADOPTED v1 budget (S_p 30,000; 4 transactions, 2 shards a block)22,17218,3904,717,43920,4344.3none
    the same22,17218,3904.7 M20,4353.7ELEMENT_THRESHOLD 2^25, HEIGHT 2^20
    block 338 shard 0, the full PROTOTYPE shard (S_p 7.5 M)6,751,56821,61160,415,37628,30710.8none
    the same6.75 M21,61160.4 M22,96311.5ELEMENT_THRESHOLD 2^25, HEIGHT 2^20
    block 344 shard 0 (the fixture's own cut, 6.75 M pgas, modexp)6,748,39218,53559,678,42028,275 and 28,30711.5 and 11.0none

    The second job (spcurve-stopped-pc2-pv1b, the pv1b host whose --budget re-plans a fixture, 20:43 to 20:47Z, the same conditions) repeats the points (empty 13,875 MiB 2.1 s; one transfer 13,907 MiB 3.3 s; the v1 shard 20,435 MiB 4.2 s; the prototype shard 28,275 MiB 11.2 s) and adds the re-plans of block 344 (27 M pgas of modexp): at 2.25 M pgas (one transaction, 16 shards a block, 19,987,938 cycles) 28,371 MiB and 6.6 s; at 4.5 M pgas (7 shards a block, 40,011,108 cycles) 28,307 MiB and 8.5 s; with the 2^25 trace threshold the 2.25 M shard 22,835 MiB and 6.2 s. So the peak is flat at 28.3 GB from 20 M cycles to 60 M (the server's buffers step up between 4.7 M and 20 M cycles and not after), and cutting the prototype shard smaller buys nothing until the v1 size.

    The third job (spcurve-miner-pc2-pv1, the same points WITH THE MINER RUNNING on the card, 20:49Z on, the live prover off): empty shard 15,585 MiB and 7.5 s; one transfer 15,745 MiB and 12.7 s; the v1 shard 22,210 MiB and 13.2 s (20,435 and 4.2 s alone: the miner adds 1.8 GB and 3.1x); the 2.25 M shard 30,049 MiB and 17.9 s; the 4.5 M shard 29,954 MiB and 26.3 s; the prototype shard 30,083 MiB and 33.3 s. With the 2^25 trace threshold beside the miner: the 2.25 M shard 24,642 MiB and 21.5 s, the prototype shard 24,739 MiB and 38.8 s (24.7 GB: over a 24 GB card by the display's share, and 3.6x slower than the card alone). So beside the miner the adopted shard needs 22.2 GB: a 24 GB card (24,564 MiB) has 2.3 GB spare for it (the number for a 24 GB card is the 5090's allocation pattern on a 32 GB card, so approximate for the card itself), and the prototype shard needs 30.1 GB, the 32 GB card alone.

    Reading, with the miner-on pairs above (empty shard 15,670 MiB, full prototype shard 30,039 MiB). The witness is never the binding term (4.9 to 21.6 KB a shard); the GPU server's working set is: a floor of 13.9 GB for any shard, 20.4 GB at 4.7 M cycles, 28.3 GB at 60 M cycles (23.0 GB with the smallest trace threshold, at the same time). By card: a 12 GB card proves nothing on this build (the floor is 13.9 GB alone); a 16 GB card proves only empty and near-empty shards, alone (13.9 GB; 15.7 GB beside the miner leaves nothing for the display); a 24 GB card proves the adopted v1 shard alone (20.4 GB) and, at the miner's measured 1.7 GB extra, about 22.1 GB beside it (approximate: not measured on a 24 GB card), and never the prototype shard (28.3 GB); a 32 GB card proves the prototype shard beside the miner with 2.5 GB spare (30.0 of 32.6 GB). The devnet is on the prototype table until H = 210,000 (6 October, about 19:50Z) and on the adopted v1 table (S_p 30,000 pgas) after it, so from H the 24 GB tier joins the provers and the shard that binds the memory is the 4.7 M-cycle one. Shards per block at each size: 1 at the prototype S_p, 4 at B_p; at the v1 budget 1 to 4 (one a block on tonight's chain, 2 to 3 on the txgen blocks).

    Step 4, the rule

    -
    WhatMeasured
    Unit testscargo test --release -p kaspa-consensus-core -p igneum-exec --lib -- proving config::params::tests::override_params_carry_the_proving_v1 config::params::tests::consensus_digest on this Mac (target vendor/igneum-node/target-pv1, 19:09Z): consensus core 13 passed (the segment record round trip, signature and the three nested sections; the credit split; the params switch and the digest that moves only once the switch is set), exec 8 passed (the segment grid and the split; the record checks: alignment, block, chain length, the veto naming the field, the deadline, the window; the chain rule both ways; the unproven restart; the shard side at 90%; the pool offering the segment section). The six full node suites go to PC 2 as a build job when the fleet is back
    The fast-time 3-node harness (tools/proving-v1/net.mjs, 29950+, suffix 956, every node in trust mode, three vmine voters, v0 at DAA 60, v1 at DAA 120, 4 blocks a segment, unproven after 60 DAA, a tenth to the aggregator; fork b177718e built on this Mac)run 2, 19:13:01Z to 19:16:19Z, under the run lock: PASSED, 21 checks in 197.3 s (tools/proving-v1/report-2026-10-05.json). v1 start = chain block 119 on all three nodes; the native statement identical on all three. Known-finished: segment 119..122's fresh-chain record submitted to n1 at t=131.1 s, relayed, verified (trust) and PAID on n0 1.0 s later at chain block 129, 253,611,648,000,000,000 wei = a tenth of the four credits, the same on every node, the payout address holding it. Chain rule: segment 123..126's fresh-chain record refused ("does not chain to segment 119..122 ... proven (record paid at chain block 129)"), the continuing one (chain_len 8) accepted and paid. Known-failed: segment 127..130 left without a record: a fresh-chain record for 131..134 refused while 127..130 was pending ("pending until DAA 191"); at DAA 192 the status read unproven, a late record for 127..130 refused ("unproven: carried after the deadline"), the fresh-chain record for 131..134 accepted and paid with chain_len 4; segmentsInWindow proven 3, unproven 1. The shard side: a v1 shard's shardWei = 90% of its block's credit. Run 1 (19:10Z) failed in its own tooling (the signer's argument order), fixed. Run 3 on the FINAL fork tree (ece42979 on the 0.3.10 commit 21d4c73c, protocol 15, N = 8 both in the params default and --segment 8, the fast-time file's four fields), 20:52:41Z to 20:56:45Z: PASSED, 21 checks in 244.4 s (segments of 8: 119..126 paid in 1.0 s after submission, 127..134 refused fresh and paid continuing with chain_len 16, 135..142 left unproven and skipped, 143..150 restarted the chain)
    +
    WhatMeasured
    Unit testscargo test --release -p kaspa-consensus-core -p igneum-exec --lib -- proving config::params::tests::override_params_carry_the_proving_v1 config::params::tests::consensus_digest on this Mac (target vendor/igneum-node/target-pv1, 19:09Z): consensus core 13 passed (the segment record round trip, signature and the three nested sections; the credit split; the params switch and the digest that moves only once the switch is set), exec 8 passed (the segment grid and the split; the record checks: alignment, block, chain length, the veto naming the field, the deadline, the window; the chain rule both ways; the unproven restart; the shard side at 90%; the pool offering the segment section). The six full node suites go to the RTX 5090 Windows rig as a build job when the fleet is back
    The fast-time 3-node harness (tools/proving-v1/net.mjs, 29950+, suffix 956, every node in trust mode, three vmine voters, v0 at DAA 60, v1 at DAA 120, 4 blocks a segment, unproven after 60 DAA, a tenth to the aggregator; fork b177718e built on this Mac)run 2, 19:13:01Z to 19:16:19Z, under the run lock: PASSED, 21 checks in 197.3 s (tools/proving-v1/report-2026-10-05.json). v1 start = chain block 119 on all three nodes; the native statement identical on all three. Known-finished: segment 119..122's fresh-chain record submitted to n1 at t=131.1 s, relayed, verified (trust) and PAID on n0 1.0 s later at chain block 129, 253,611,648,000,000,000 wei = a tenth of the four credits, the same on every node, the payout address holding it. Chain rule: segment 123..126's fresh-chain record refused ("does not chain to segment 119..122 ... proven (record paid at chain block 129)"), the continuing one (chain_len 8) accepted and paid. Known-failed: segment 127..130 left without a record: a fresh-chain record for 131..134 refused while 127..130 was pending ("pending until DAA 191"); at DAA 192 the status read unproven, a late record for 127..130 refused ("unproven: carried after the deadline"), the fresh-chain record for 131..134 accepted and paid with chain_len 4; segmentsInWindow proven 3, unproven 1. The shard side: a v1 shard's shardWei = 90% of its block's credit. Run 1 (19:10Z) failed in its own tooling (the signer's argument order), fixed. Run 3 on the FINAL fork tree (ece42979 on the 0.3.10 commit 21d4c73c, protocol 15, N = 8 both in the params default and --segment 8, the fast-time file's four fields), 20:52:41Z to 20:56:45Z: PASSED, 21 checks in 244.4 s (segments of 8: 119..126 paid in 1.0 s after submission, 127..134 refused fresh and paid continuing with chain_len 16, 135..142 left unproven and skipped, 143..150 restarted the chain)

    5 October 2026 (night), dp4a-class throughput on the M5 Max: the dot4 emulation against the ALU chain (Counter ASIC 2.0 layer 7)

    Apple M5 Max, macOS 26, branch ca2-analysis (base readwidth 4badcee). The probes are standalone (no pack, no lottery kernel): proto-metal/dot4-probe.swift (built swiftc -O -o dot4-probe dot4-probe.swift -framework Metal under with-lock.sh build), proto-opencl/dot4-probe.c (built cc -std=c99 -O2 -o dot4-probe-cl dot4-probe.c -framework OpenCL), both run under with-lock.sh measure (exclusive; nothing else built or measured on the Apple M5 Max during the runs). Shape: a dependent chain of one dot4 per step per lane, acc = dot4(x, y, acc); x = x * 0x9E3779B1 + acc; y = rotl(y, 7) ^ (acc + s), 1,048,576 lanes x 4,096 steps, work-group 256, best of 3 with a fresh seed per repetition, device time (Metal: command buffer GPU start to end; OpenCL: event profiling). Beside it the ALU chain of the 9070 XT entry (x = x * K + rotl(y, 7); y = (y ^ x) + s, 5 ops per step counted). Every kernel is checked bit for bit against a CPU reference on lanes 0 and 1,048,575 in every repetition ("ok"). Design context: docs/analysis/int8-matrix-family.md.

    API, kernelWhat one step isbest msG steps/sns per dependent stepok
    Metal, probe_alumul, add, rotate, xor, add4.882879.8 (about 4.4 T int ops/s at 5 per step, approximate)1,192yes
    Metal, probe_dot4ssigned dot4 emulated: int4(as_type<char4>(a)) x same for b, 4 products summed into a wrapping int, plus the 3-op chain22.820188.2 G dot4/s5,571yes
    Metal, probe_dot4uunsigned dot4 emulated: uint4(as_type<uchar4>(a)), same chain7.834548.2 G dot4/s1,913yes
    Apple OpenCL 1.2, aluas Metal4.928871.51,203yes
    Apple OpenCL 1.2, dot4esigned dot4 emulated with convert_int4(as_char4(a))22.797188.4 G dot4/s5,566yes
    Apple OpenCL 1.2, dot4_khracc + dot(as_char4(x), as_char4(y)) under #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable5.076846.21,239NO: mismatched the CPU reference on every lane checked in all 3 repetitions

    Reading: on this GPU a signed-byte dot4 costs 4.7 ALU-chain steps and an unsigned-byte one 1.6; Metal has no dp4a and no integer simdgroup matrix (MSL 4.1 sections 2.4 and 6.9), so these are the honest Apple costs of a per-lane dot4 family, and an unsigned definition is 3x cheaper for Apple at no cost to NVIDIA or AMD (both carry the unsigned form, PTX dp4a.u32.u32, AMD v_dot4_u32_u8). Apple's OpenCL does not list cl_khr_integer_dot_product; its dot on char4 compiled anyway and returned something other than the integer dot (the mismatch), which is why a family's conformance vectors must gate every vendor path on the feature macro, not on "it compiled". Not run here: NVIDIA and AMD. The PC job is prepared and not published (coordinator's rule): relay/playbooks/dot4-probe.ps1 with dot4-probe-cl.exe (proto-opencl/dot4-probe.c cross-compiled with mingw as x86_64-w64-mingw32-gcc -std=c99 -O2 -static -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I proto-cuda/nvrtc/redist/include, sha256 5adaeb1aceb03dc41135baabe0b53f1ed5fac891a5b3c3849645b03efe4416f4, 161,863 bytes); it runs the scalar, KHR, AMD __builtin_amdgcn_sudot4 and NVIDIA inline-PTX dp4a variants on every OpenCL GPU of the machine with the mining cards switched off through /api/cards and restored after. The CUDA form (proto-cuda/dot4-probe.cu, __dp4a) needs nvcc on the RTX 5090 machine and is the cross-check.

    -

    PC 1, 5 October 2026 20:29 UTC, the same probe on the RTX 5090 and the RX 9070 XT (machine ae432dc7, Windows 11; fetch job fetch-dot4-20261005 placed dot4-probe-cl.exe sha256 5adaeb1a…6416f4, run job run-dot4-20261005 ran relay/playbooks/dot4-probe.ps1: the app's nvidia:0 and amd:1:gfx1201 cards switched off through POST api/cards, the probe run on every OpenCL device, the cards restored with their settings (identities 8 and 2, power cap 80% and none); node tools/jobs.mjs run-dot4-20261005; 101 s wall, every kernel under 10 ms; device event time, best of 3, same lanes and steps as the Apple M5 Max rows):

    +

    the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), 5 October 2026 20:29 UTC, the same probe on the RTX 5090 and the RX 9070 XT (machine ae432dc7, Windows 11; fetch job fetch-dot4-20261005 placed dot4-probe-cl.exe sha256 5adaeb1a…6416f4, run job run-dot4-20261005 ran relay/playbooks/dot4-probe.ps1: the app's nvidia:0 and amd:1:gfx1201 cards switched off through POST api/cards, the probe run on every OpenCL device, the cards restored with their settings (identities 8 and 2, power cap 80% and none); node tools/jobs.mjs run-dot4-20261005; 101 s wall, every kernel under 10 ms; device event time, best of 3, same lanes and steps as the Apple M5 Max rows):

    Device, platformalu, G steps/s (ms)dot4e signed emulation, G dot4/s (ms)dot4 instruction, G dot4/s (ms)cl_khr_integer_dot_productok
    RTX 5090, NVIDIA OpenCL 3.0 CUDA, driver 617.148,753.5 (0.491)1,239.1 (3.466), 7.1x the ALU step7,453.6 (0.576) via inline PTX dp4a.s32.s32, 1.17x the ALU stepnot listed; the dot(char4,char4) kernel does not buildyes
    RX 9070 XT (gfx1201), AMD-APP 3683.0 (PAL,LC), OpenCL 2.0701.4 (6.124)480.8 (8.932), 1.46x664.3 (6.465) via __builtin_amdgcn_sudot4, 1.06xnot listed; sameyes
    RX 9070 XT, the older 3652.0 platform entry (dup)696.2 (6.169)501.7 (8.561)683.6 (6.283)not listedyes
    gfx1036 (integrated RDNA 2, 2 CUs), 3683.040.6 (105.9)15.8 (272.3), 2.6xsudot4 does not build: "needs target feature dot8-insts"not listedalu and dot4e yes

    Reading: one dp4a on the 5090 costs about one ALU-chain step (7.45 T dot4/s, 0.85 of the chain's 8.75 T steps/s); one v_dot4_i32_iu8 on the 9070 XT the same (0.66 T, 0.95 of its chain). Emulating the signed dot4 costs 6.0x the instruction on NVIDIA (the OpenCL compiler does not fold the four sign-extended products into dp4a) and 1.38x on AMD. Vendor ratios: the 5090 is 12.5x the 9070 XT on the ALU chain and 11.2x on hardware dot4; against the M5 Max's best (unsigned emulation, 0.55 T) it is 10x on the chain and 13.6x on dot4. The hash itself is bound by DRAM reads, so these per-op numbers bound a family's cost and are not hash rates (docs/analysis/int8-matrix-family.md section 4). Adrenalin's OpenCL C accepts the clang builtin and emits the instruction on RDNA 4 (the third-party RDNA 3 report of the same route is now confirmed on this card); no PC platform lists the Khronos integer-dot extension. The 5090 SM clock read 2,505 MHz before and after (nvidia-smi; 2,850 MHz while mining in the telemetry entry), so the card was idle for the probe.

    5 October 2026, layer 3 scratch soundness (Counter ASIC 2.0 step 4; branch ca2-soundness on readwidth b970dda; cryptographer)

    @@ -707,50 +664,50 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    Daily 1 GiB build and hash rate, Metal (with-lock.sh measure, the same session, packbench --batches 2 --batch-log2 22 --group 256, three rounds):

    PackCompile (1 / 2 / 3)Build, GPU ms (1 / 2 / 3)MH/s GPU (1 / 2 / 3)
    mx8-genesis (x8, the control)80 / 1 / 1 ms31.3 / 22.1 / 22.127.155 / 27.076 / 27.123
    dr736-genesis751 / 1 / 1 ms28.9 / 29.0 / 29.127.125 / 27.129 / 27.063

    Chip model (chip-model-v3.md section 6): 1,278,976 chip ops per hash on the genesis day, 39.1 MH/s at 50 T op/s, 0.29x bare (0.31x at the floor, x8's figure); the fixed-function allowance of the wired mixer (3x) no longer applies to a chip that must run the day's program: at ProgPoW's claimed 1.2x the row reads 0.34x, at a cautious 1.5x 0.43x, at the old 3x 0.86x; equal silicon 0.29x / 0.36x. dr368: 0.57x bare, 0.69x / 0.86x.

    -

    Consequences per tier. The verifier: no miner tier runs it; a node on any 2026 core verifies a block in 5 ms (x8: 2.1), a pool core serves 205 shares per second (x8: 485; a 22,000-member pool at one share per 10 s needs 11 cores against 4.5), IBD over 108,000 headers is 8.8 min on one core (x8: 3.7); on a 2019-class laptop core (2.5x, approximate, O-1.14 unmeasured) 736 reads about 12 ms, over the gate, and 368 about 6.7 ms, under it. The build: the Apple M5 Max pays 7 ms more per day (29 against 22 ms), nothing to any tier; the 5090 is the RTX 5090 machine 2 job below; the 9070 XT is OWED (PC 1 is the maintainers' desk today; its x8 build was 72 to 77 ms); the integrated gfx1036 tier already misses the per-prepare rule at x8 (epoch-length.md 6.1: 6.9 / 9.4 / 11.7 s prepares at x1, about 55 to 94 s at x8, approximate) and the day program leaves that need (per-day dataset reuse in the workers, 0.3.12) the same in kind. The compile: the Metal item library is 0.75 to 0.8 s cold once a day and 1 ms from the shader cache; the CUDA worker compiles memhard.h into every per-epoch kernel and every race variant, so the 5090's nvrtc line is the number to read. The hash rate: unchanged within 0.3% on the Apple M5 Max, as the hash kernel only loads. Packs grow by about 550 KB (memhard.h 196 KB, program.json 156 KB): nothing to any tier.

    +

    Consequences per tier. The verifier: no miner tier runs it; a node on any 2026 core verifies a block in 5 ms (x8: 2.1), a pool core serves 205 shares per second (x8: 485; a 22,000-member pool at one share per 10 s needs 11 cores against 4.5), IBD over 108,000 headers is 8.8 min on one core (x8: 3.7); on a 2019-class laptop core (2.5x, approximate, O-1.14 unmeasured) 736 reads about 12 ms, over the gate, and 368 about 6.7 ms, under it. The build: the Apple M5 Max pays 7 ms more per day (29 against 22 ms), nothing to any tier; the 5090 is the the RTX 5090 Windows rig job below; the 9070 XT is OWED (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) is the maintainers' desk today; its x8 build was 72 to 77 ms); the integrated gfx1036 tier already misses the per-prepare rule at x8 (epoch-length.md 6.1: 6.9 / 9.4 / 11.7 s prepares at x1, about 55 to 94 s at x8, approximate) and the day program leaves that need (per-day dataset reuse in the workers, 0.3.12) the same in kind. The compile: the Metal item library is 0.75 to 0.8 s cold once a day and 1 ms from the shader cache; the CUDA worker compiles memhard.h into every per-epoch kernel and every race variant, so the 5090's nvrtc line is the number to read. The hash rate: unchanged within 0.3% on the Apple M5 Max, as the hash kernel only loads. Packs grow by about 550 KB (memhard.h 196 KB, program.json 156 KB): nothing to any tier.

    Go / no-go: GO as reserve entry R0 (the PROPOSED text in the derivation document's section 6, not in docs/spec); NO-GO for genesis-live at 736 instructions until the 2019-class core measurement lands under 10 ms; the number that decides it is 4.88 ms per unit on one M5 Max core (pass) against about 12 ms on the approximate laptop row (fail); dr368 passes both rows at 2.69 ms with the chip at 0.57x bare.

    -

    RTX 5090 (PC 2, one job run-ca3-derive-pc2-20261006, relay/playbooks/ca3-derive-pc2.ps1, published 08:26:08Z after the proving agent's clear at 08:24:27Z, lock 08:25:55 to 08:29:08Z; ran 08:26:43 to 08:28:49Z, done exit 0): the installed 0.3.11 worker through NVRTC 12.8 on the self-fetched zip. The card did NOT come off: the job read the key from settings.json (nvidia:0:NVIDIA GeForce RTX 5090, with the device index) where the 5 October jobs posted the state's key without it, and one worker process stayed up through the 90 s wait, so every row is a loaded-card figure (the v2 control 62.3 MH/s against its unloaded 136 to 137) with the ratios valid.

    +

    RTX 5090 (the RTX 5090 Windows rig, one job run-ca3-derive-pc2-20261006, relay/playbooks/ca3-derive-pc2.ps1, published 08:26:08Z after the proving agent's clear at 08:24:27Z, lock 08:25:55 to 08:29:08Z; ran 08:26:43 to 08:28:49Z, done exit 0): the installed 0.3.11 worker through NVRTC 12.8 on the self-fetched zip. The card did NOT come off: the job read the key from settings.json (nvidia:0:NVIDIA GeForce RTX 5090, with the device index) where the 5 October jobs posted the state's key without it, and one worker process stayed up through the 90 s wait, so every row is a loaded-card figure (the v2 control 62.3 MH/s against its unloaded 136 to 137) with the ratios valid.

    PackNVRTCCache1 GiB buildSelf-test (64 samples, 96 lanes)Fingerprint 2^24MH/s bw1 / bw8 (loaded)
    v2-genesis-mh167 ms646 msPASS25f96e7dce90bd4e = Mac62.26 / 61.34
    mx8-genesis164 ms440 msPASS7c28cfb06c5c65a9 = Mac61.98 / 60.53
    dr736-genesis1,266 ms542 msPASS50e3eaa779da4f1e = Metal = Apple OpenCL61.08 / 58.51
    dr736-devnet-epoch01,266 ms632 msPASS9553f6d5c667205a = Metal62.15 / 61.44
    -

    Reading: bit-exact on CUDA (four compilers now agree on both packs); the build and the rate do not move beyond the loaded noise; the number that moved is the NVRTC compile, +1.1 s per pack, because memhard.h's 6,624-statement item function is inside every hash-kernel and race-variant compile (17 variants: about +19 s per epoch, approximate, against a 38 s compile-ahead budget at the 600-s epoch floor), so compiling the item function once a day into its own module is a requirement of the class. Consequences: a 5090 owner pays 1.1 s once a day after that fix and 1.1 s per variant per epoch before it; the Apple M5 Max 0.75 s once a day. Filed: the card-off key form (post both forms, confirm by the process list) before the next PC 2 round; the unloaded 5090 rows re-run then. RX 9070 XT: OWED (PC 1).

    +

    Reading: bit-exact on CUDA (four compilers now agree on both packs); the build and the rate do not move beyond the loaded noise; the number that moved is the NVRTC compile, +1.1 s per pack, because memhard.h's 6,624-statement item function is inside every hash-kernel and race-variant compile (17 variants: about +19 s per epoch, approximate, against a 38 s compile-ahead budget at the 600-s epoch floor), so compiling the item function once a day into its own module is a requirement of the class. Consequences: a 5090 owner pays 1.1 s once a day after that fix and 1.1 s per variant per epoch before it; the Apple M5 Max 0.75 s once a day. Filed: the card-off key form (post both forms, confirm by the process list) before the next the RTX 5090 Windows rig round; the unloaded 5090 rows re-run then. RX 9070 XT: OWED (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT)).

    6 October 2026, Counter ASIC 3.0 item 8: program work in the latency shadow

    Branch ca3-shadow, worker "shadow" (docs/analysis/latency-shadow-2026-10-06.md carries the design, the chip side and the consequences; this entry carries the measurements). The knob: LoadClass::shadow, class name <class>+sh<S>x<R>, a block of S ALU instructions drawn from the program stream after the 64 base instructions and run R times at the end of every iteration (no load; the base program, its attempt and the acceptance verdict are the class's without the shadow; v2 and v3 byte-identical, cargo test in igneum-pow 54 + 4 + 19 + 7 green). Packs proto-cuda/packs-ca3-shadow/* over mx8 for seed igneum-genesis; the control is the pinned class v3 pack packs-ca2-mixer/mx8-genesis. Ops per hash = shadow instructions x 1.83 (counted from the emitted statements: add 5, rotr 2, shfl 2, the rest 1, weighted over the non-load weights) + 930 (the base program's 384 ALU instructions and 128 loads).

    Apple M5 Max, Metal (proto-metal/packbench --pack <dir> --batches 60 --batch-log2 24 --group 256 under with-lock.sh measure, two sessions 07:51 to 08:03 UTC, GPU time; power = the IOReport "Energy Model" GPU and DRAM channels at 2 Hz through a dlopen of libIOReport, no root, the mean over each run after its first 6 s; idle GPU 0.44 W, DRAM 0.64 W; the package is about 17 W more, Ember Tune's 38 W row, approximate; load averages 3.3 to 6.8, the GPU idle: the Apple M5 Max mines nothing):

    PackShadow instrs per hashOps per hashMH/sAgainst the controlGPU WDRAM WMicrojoules per hash (GPU + DRAM)Verifier ms per warp, one core, avg of 20 (worst cold)Bit-exact, fingerprint 2^24Load at start
    mx8-genesis (control; runs 1, 2, 3)093027.07, 27.07, 27.1011.2, 9.2, 12.310.2, 10.0, 10.20.782.062 (2.188)yes, 7c28cfb06c5c65a94.6, 6.8, 4.2
    sh256x24,0968,40026.85-0.8%15.110.40.952.080 (2.249)yes, 33e8bbe4c35b2e544.6
    sh256x714,33627,20026.74-1.3%18.010.61.072.112 (2.224)yes, 6cfb70911007520a4.2
    sh256x1326,62449,70026.75-1.2%20.610.51.162.212 (2.237)yes, 59ac286fe2a5a9ef3.7
    sh64x52 (64-instruction block; runs 1, 2)26,62449,70027.72, 27.79+2.5%19.8, 20.310.2, 10.31.092.137 (2.237)yes, 9dd010f79d8ca9f44.4, 4.1
    sh1024x3 (1,024-instruction block)24,57645,90022.53-16.8%20.29.71.332.150 (2.274)yes, a05399c819b79aad6.0
    sh256x27 (runs 1, 2)55,296102,10026.48, 26.86-1.5%26.9, 26.910.4, 10.21.402.229 (2.276)yes, 3d2e8245cc084d073.3, 5.6
    sh256x4081,920150,80025.10-7.3%26.710.11.462.329 (2.396)yes, 0844b706302f1c9c5.0
    sh256x53 (runs 1, 2)108,544199,60024.40, 24.09-10.4%28.8, 28.59.5, 9.71.582.427 (2.461)yes, 4f824b15cf2b124a3.9, 4.6
    sh256x88180,224330,70021.39-21.0%31.78.41.882.619 (2.771)yes, 0572522e39a94d8a3.8

    Reading: the M5 Max stays latency-bound to about 100,000 ops per hash and its 5 percent point is about 130,000 (between the 102,100 and 150,800 rungs), 2.2x under the chip model's 290,000 (from memory); the block size matters on Apple (64 instructions +2.5 percent, 256 holds, 1,024 costs 17 percent at the same N: the instruction footprint); the GPU rises from 11 to 27 W at 100,000 ops (marginal 6.9 pJ per counted op; 2.9 pJ at the compute-bound end) and the energy per hash from 0.78 to 1.40 microjoules, GPU plus DRAM. The verifier's law on this core: 2.06 ms + 3.2 microseconds per 1,000 shadow instructions per warp (0.1 ns per lane-instruction), so 330,700 ops cost 0.56 ms here and about 1.4 ms on a 2019-class core by the 2.5x rule: inside every pairing's headroom (x8 7.8 / 4.6 ms, dr368 7.1 / 2.8, dr736 5.1 / none, M5 Max / 2019-class, item 2's figures), so the node never binds the shadow before the cards do. The control is 2.5 percent under the 5 October figure for this pack (27.7, mixer-x4.md 6.2) on three runs; every row is read against today's 27.08.

    -

    RTX 5090 (PC 2, 1ccfe586), CUDA through NVRTC (job run-ca3-shadow-pc2-20261006, 08:30:26Z to 08:38:57Z, 511 s, exit 0, --stop-miners, the prover off for the run and back on, the card EMPTY before the ladder by nvidia-smi's compute-apps list; the installed worker 0.3.11 --bench --batches 250 --batch-log2 24 --block-warps 1, wall time; power = nvidia-smi -l 1 means over each bench's window; the card under the app's 431 W limit, 73.8 W idle, 56 to 71 C):

    +

    RTX 5090 (the RTX 5090 Windows rig, 1ccfe586), CUDA through NVRTC (job run-ca3-shadow-pc2-20261006, 08:30:26Z to 08:38:57Z, 511 s, exit 0, --stop-miners, the prover off for the run and back on, the card EMPTY before the ladder by nvidia-smi's compute-apps list; the installed worker 0.3.11 --bench --batches 250 --batch-log2 24 --block-warps 1, wall time; power = nvidia-smi -l 1 means over each bench's window; the card under the app's 431 W limit, 73.8 W idle, 56 to 71 C):

    PackShadow instrs per hashOps per hashMH/sAgainst the controlWatts, meanSM MHzMicrojoules per hashBit-exact, fingerprint 2^24 = the Apple M5 Max'sNVRTC ms
    mx8-genesis (control, first and last)0930131.94, 132.47342.4, 357.43,052, 3,0372.65yes, 7c28cfb06c5c65a9158, 160
    sh256x24,0968,400132.34+0.1%354.43,0372.68yes248
    sh256x714,33627,200132.32+0.1%385.33,0372.91yes250
    sh256x1326,62449,700132.28+0.1%424.63,0343.21yes240
    sh64x52 (64-instruction block)26,62449,700136.77+3.5%431.5 (the cap)3,0243.15yes181
    sh1024x3 (1,024-instruction block)24,57645,900132.02-0.1%428.33,0303.24yes510
    sh256x2755,296102,100131.95-0.2%431.0 (the cap)2,8243.27yes242
    sh256x4081,920150,800131.75-0.3%431.02,4273.27yes242
    sh256x53108,544199,600128.67-2.7%431.01,7533.35yes241
    sh256x88180,224330,70086.39-34.7%431.01,8344.99yes241

    Reading: the 5090 holds to 150,800 ops (-0.3 percent) and loses 2.7 percent at 199,600, under a 431 W cap that the control never reaches (342 to 357 W) and that binds from 102,100 ops up: the SM clock falls from 3,037 to 1,834 MHz and at 330,700 ops the card is compute-bound at the capped clock (28.6 T counted op/s, the 45.2 T budget scaled by the clock). The 5 percent point at 431 W is about 210,000 ops. The marginal ALU energy at the shipping clock, read on the three rungs under the cap: 10.2 to 13.2 pJ per counted op, twice the 5.5 pJ the chip model assumed. The 64-instruction block runs 3.5 percent above the control here too. Clock rows (-lgc): OWED, nvidia-smi refused the lock without administrator rights and the job did not ask for them. Power-cap rows: the 5 October sweep's (floor 400 W, so -pl 200 and 250 cannot be set; the cap never binds at the control).

    -

    RX 9070 XT (PC 1, ae432dc7): OWED (PC 1 is the maintainers' desk and not released today); the OpenCL kernels are in every pack.

    +

    RX 9070 XT (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), ae432dc7): OWED (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) is the maintainers' desk and not released today); the OpenCL kernels are in every pack.

    Consequences per tier (the file's section 8 in short): at the recommended N = 100,000 ops per hash (sh256x27) the Apple card loses 1.5 percent of its rate and pays 16 W more (income per watt 0.56x, per pound unchanged), the 5090 holds its rate at its 431 W cap (350 W at the control: per watt 0.81x, measured), the 9070 XT holds by its budget (owed), a rig pays about 30 percent more electricity for the same hash, a pool user sees nothing, and the f = 1 chip's edge per joule falls from 1.6x to 0.9x against the M5 Max and from 5.6x to 2.1x against the 5090 at k = 1, where k is the chip core's energy per op over the 5090's measured 11 pJ: the number that decides the item. Verdict: GO as a class v4 candidate at N = 100,000 (mx8+sh256x27), subject to the 9070 XT row and the gates; NO-GO above 130,000 or with a block over 256 instructions. No card we own may lose more than 5 percent (the 2.0 rule): the M5 Max caps N at 130,000.

    6 October 2026, Counter ASIC 3.0 item 6: the reserve families' step costs

    -

    Branch ca3-reserve, worker "reserve" (docs/plans/counter-asic-3-reserve.md carries the proposed order and spec text; this entry carries the measurements). Method: the dot4 probe's dependent chain (docs/analysis/int8-matrix-family.md section 4), one op of the family per step per lane, 1,048,576 lanes x 4,096 steps, best of 3 dispatches per run, three runs, bit-exact against a CPU reference on two whole 32-lane warps (the shuffle rows need the whole warp). Every chain has the same glue (acc = OP(acc, x, y); x = x * K + acc; y = rotl(y, 7) ^ (acc + s)), so the "step cost" is the family's one op plus four glue ops against the add-xor-rotate chain of the 9070 XT bench-log entry (alu: x = x * K + rotl(y, 7); y = (y ^ x) + s, 5 ops per step counted, no acc). Reference rows are live families (alu; rotr = the live rotr_var text; shflx = the live shfl, lane XOR 8). Candidate rows are the seven families of spec 1.13.2 (shl, shr, bfe with the vendor's extract function and bfec the C form (y >> 7) & 0x1fff, andn, perm = bytes (b1, b3, b0, b2), popc and clz folded by add, sel on bit 5, shfla = lane + 3 mod 32). Comparison rows: dot4u and dot4s (Apple, emulated), dot4i (__dp4a) and mm8 (one mma.sync.m8n8k16 u8 per step per warp, inline PTX) on CUDA. Sources: proto-metal/family-probe.swift, proto-cuda/family-probe.cu, the RTX 5090 machine 2 job tools/ca3-reserve/pc2-family-probe.ps1 (made by make-pc2-playbook.sh). G steps/s is the whole card's dependent-step throughput; ops per step counted = the family's op plus 4 glue (alu 5, shfla and shflx 6: shuffle plus xor, mm8 1 mma plus 4).

    +

    Branch ca3-reserve, worker "reserve" (docs/plans/counter-asic-3-reserve.md carries the proposed order and spec text; this entry carries the measurements). Method: the dot4 probe's dependent chain (docs/analysis/int8-matrix-family.md section 4), one op of the family per step per lane, 1,048,576 lanes x 4,096 steps, best of 3 dispatches per run, three runs, bit-exact against a CPU reference on two whole 32-lane warps (the shuffle rows need the whole warp). Every chain has the same glue (acc = OP(acc, x, y); x = x * K + acc; y = rotl(y, 7) ^ (acc + s)), so the "step cost" is the family's one op plus four glue ops against the add-xor-rotate chain of the 9070 XT bench-log entry (alu: x = x * K + rotl(y, 7); y = (y ^ x) + s, 5 ops per step counted, no acc). Reference rows are live families (alu; rotr = the live rotr_var text; shflx = the live shfl, lane XOR 8). Candidate rows are the seven families of spec 1.13.2 (shl, shr, bfe with the vendor's extract function and bfec the C form (y >> 7) & 0x1fff, andn, perm = bytes (b1, b3, b0, b2), popc and clz folded by add, sel on bit 5, shfla = lane + 3 mod 32). Comparison rows: dot4u and dot4s (Apple, emulated), dot4i (__dp4a) and mm8 (one mma.sync.m8n8k16 u8 per step per warp, inline PTX) on CUDA. Sources: proto-metal/family-probe.swift, proto-cuda/family-probe.cu, the the RTX 5090 Windows rig job tools/ca3-reserve/pc2-family-probe.ps1 (made by make-pc2-playbook.sh). G steps/s is the whole card's dependent-step throughput; ops per step counted = the family's op plus 4 glue (alu 5, shfla and shflx 6: shuffle plus xor, mm8 1 mma plus 4).

    Apple M5 Max, Metal (swiftc -O -o family-probe family-probe.swift -framework Metal under with-lock.sh build; three runs of with-lock.sh measure ./family-probe --reps 3, 07:29:05 to 07:29:08 UTC, load average 7.64 / 7.59 / 7.14 before and after every run (the Apple M5 Max was loaded by other agents' builds the whole morning; the measure lock held, the GPU idle: the Apple M5 Max mines nothing), GPU start-to-end time):

    kernelbest ms, runs 1 / 2 / 3best of the three, msG steps/s (best)ns per step (best)ops per step countedstep cost (ratio to alu, best)bit-exact, 3 runs
    alu5.039 / 4.918 / 4.8734.8738811,19051.00yes
    rotr (live)5.610 / 5.533 / 5.4925.4927821,34151.13yes
    shflx (live)4.196 / 4.259 / 4.2234.1961,0241,02460.86yes
    shl4.120 / 4.202 / 4.1194.1191,0431,00650.85yes
    shr4.296 / 4.194 / 4.3194.1941,0241,02450.86yes
    bfe (extract_bits)3.731 / 3.805 / 3.8163.7311,15191150.77yes
    bfec (C form)3.762 / 3.818 / 3.6463.6461,17889050.75yes
    andn3.680 / 3.732 / 3.6763.6761,16889850.75yes
    perm5.500 / 5.548 / 5.5245.5007811,34351.13yes
    popc4.261 / 4.223 / 4.2624.2231,0171,03150.87yes
    clz4.918 / 4.916 / 4.9144.9148741,20051.01yes
    sel3.718 / 3.831 / 3.7183.7181,15590850.76yes
    shfla (lane + 3)9.337 / 9.323 / 9.2879.2874622,26761.91yes
    dot4u (emulated)7.818 / 8.044 / 7.9257.8185491,90951.60yes
    dot4s (emulated)23.264 / 23.254 / 23.04523.0451865,62654.73yes

    Reading of the Apple M5 Max rows. The run-to-run spread is under 4% on every row. The dot4 rows reproduce the 5 October figures (1.6x unsigned, 4.7x signed), which is the check on the method. A step cost under 1.00 means the family's op plus the glue is cheaper than the five-op reference chain: the reference's two registers are a tighter dependency than the three-register candidate chains, and Apple's shifts, extract, andn and select each cost about what an xor costs. Three rows cost more than the reference: perm (1.13: no byte-permute function in MSL; the uchar4 swizzle compiles to shifts and masks, so a byte permute is emulated on Apple at about the price of the live rotr), clz (1.01) and shfla (1.91: a shuffle by a computed lane index costs 2.2x the live xor shuffle on Apple, simd_shuffle against simd_shuffle_xor; the second shuffle form is the one candidate Apple pays for). mm8 as a chain on Apple is owed (Metal 4 matmul2d; this toolchain is Swift 5.8 without the tensor API).

    -

    RTX 5090 (PC 2, 1ccfe586), CUDA (job run-ca3-family-pc2-20261006, a signed run job with --stop-miners, published 08:41:45Z after /tmp/igneum-devnet/pc2-ca3.clear (08:24:27Z) under the mkdir lock (taken 08:41:26Z, released 08:43:24Z the moment the closing report was read); ran 08:42:27Z to 08:43:03Z, done, exit 0, 36 s; node tools/jobs.mjs run-ca3-family-pc2-20261006 --all). The card to itself: the app had stopped the miner before the script started (workers_before: no CUDA compute app, the card at 847 MHz SM and 72 W), the script posted the card off through api/cards in both key forms (settings.json carries two NVIDIA keys, nvidia:0:NVIDIA GeForce RTX 5090 with 8 identities and the older nvidia:NVIDIA GeForce RTX 5090 with 2) and read the card quiet by nvidia-smi's compute-apps list and the process list after 30 s; prover off at 08:42:27Z and back on at 08:43:02Z ({"ok":true}, in the finally block); the cards restored to their settings. nvcc 12.8 in WSL2, -arch=sm_120, the source sha256 1a3d07b8...0cf90d equal on the Apple M5 Max, the Windows side and inside WSL. Three runs of ./family-probe --reps 3, CUDA event time; the SM clock ramped from 862 MHz at run 1 to 2,572 MHz at run 3 (gpu_before per run; 129 W at the end), so the best of the three runs is the card's warm figure and the table carries it; the run-to-run spread of the best values is under 3% on every row except shl (12%: run 2 caught the ramp). Driver 610.47:

    +

    RTX 5090 (the RTX 5090 Windows rig, 1ccfe586), CUDA (job run-ca3-family-pc2-20261006, a signed run job with --stop-miners, published 08:41:45Z after /tmp/igneum-devnet/pc2-ca3.clear (08:24:27Z) under the mkdir lock (taken 08:41:26Z, released 08:43:24Z the moment the closing report was read); ran 08:42:27Z to 08:43:03Z, done, exit 0, 36 s; node tools/jobs.mjs run-ca3-family-pc2-20261006 --all). The card to itself: the app had stopped the miner before the script started (workers_before: no CUDA compute app, the card at 847 MHz SM and 72 W), the script posted the card off through api/cards in both key forms (settings.json carries two NVIDIA keys, nvidia:0:NVIDIA GeForce RTX 5090 with 8 identities and the older nvidia:NVIDIA GeForce RTX 5090 with 2) and read the card quiet by nvidia-smi's compute-apps list and the process list after 30 s; prover off at 08:42:27Z and back on at 08:43:02Z ({"ok":true}, in the finally block); the cards restored to their settings. nvcc 12.8 in WSL2, -arch=sm_120, the source sha256 1a3d07b8...0cf90d equal on the Apple M5 Max, the Windows side and inside WSL. Three runs of ./family-probe --reps 3, CUDA event time; the SM clock ramped from 862 MHz at run 1 to 2,572 MHz at run 3 (gpu_before per run; 129 W at the end), so the best of the three runs is the card's warm figure and the table carries it; the run-to-run spread of the best values is under 3% on every row except shl (12%: run 2 caught the ramp). Driver 610.47:

    kernelbest ms, runs 1 / 2 / 3best of the three, msG steps/s (best)ns per step (best)ops per step countedstep cost (ratio to alu, best)bit-exact, 3 runs
    alu0.553 / 0.541 / 0.5530.5417,94113251.00yes
    rotr (live)0.729 / 0.719 / 0.7150.7156,00517551.32yes
    shflx (live)0.808 / 0.817 / 0.8170.8085,31519761.49yes
    shl0.687 / 0.770 / 0.6960.6876,25316851.27yes
    shr0.698 / 0.697 / 0.6910.6916,21216951.28yes
    bfe (bfe.u32, inline PTX)0.837 / 0.851 / 0.8350.8355,14220451.54yes
    bfec (C form)0.836 / 0.837 / 0.8350.8355,14420451.54yes
    andn0.680 / 0.700 / 0.6930.6806,31316651.26yes
    perm (__byte_perm)0.706 / 0.715 / 0.7180.7066,08417251.30yes
    popc0.819 / 0.813 / 0.8350.8135,28319851.50yes
    clz0.897 / 0.898 / 0.8840.8844,85621651.63yes
    sel0.723 / 0.713 / 0.7290.7136,02417451.32yes
    shfla (lane + 3)0.845 / 0.848 / 0.8290.8295,17920261.53yes
    dot4i (__dp4a)0.677 / 0.656 / 0.6250.6256,87015351.16yes
    mm8 (mma.sync.m8n8k16.u8, one per warp per step)1.313 / 1.314 / 1.3501.3133,2723211 mma + 42.43yes

    Reading of the 5090 rows. Every row is bit-exact, mm8 included, so the m8n8k16 fragment layout of the CPU reference (PTX ISA 9.4 section 9.7.16.5.3) is the layout the hardware uses. The alu chain reads 7,941 G steps/s here against 8,754 through OpenCL event time on 5 October: a CUDA event pair around a 0.54 ms kernel carries about 0.05 ms of launch, which also compresses every ratio toward 1 (approximate: the ratios are the card's at the 2% level, not better). On this card every candidate costs more than the reference chain, unlike Apple: the 5090 runs the two-register add-xor-rotate chain at one IMAD and one funnel shift per step, and the three-register candidate chains pay their glue. Against the live rotr (1.32), the candidates read: andn 0.95x, shl 0.96x, shr 0.97x, perm 0.98x, sel 1.00x, popc 1.14x, shfla 1.16x (the same as the live xor shuffle, 1.49: the indexed shuffle costs NVIDIA nothing extra), bfe 1.17x, clz 1.23x. bfe.u32 and the C form cost the same to the nanosecond (0.835 ms), so the compiler emits the same code for both and no single-instruction bit-field extract is in play on this architecture (not checked by cuobjdump; the equal times are the evidence). dp4a reads 1.16x (1.17x on 5 October). mm8 is the most expensive row on NVIDIA too (2.43x the reference: one tensor-core mma per warp per dependent step, latency-bound), which supports its place at the end of the reserve on the honest-card side as well as on the chip side.

    -

    RX 9070 XT (PC 1, ae432dc7), OpenCL: OWED. PC 1 is the maintainers' desk and not released today (the brief's rule); the OpenCL twin of the probe (__builtin_amdgcn_* paths for v_bfe_u32, v_perm_b32, v_bcnt_u32_b32, v_cndmask_b32, ds_bpermute_b32) is the next job on that card.

    +

    RX 9070 XT (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT), ae432dc7), OpenCL: OWED. the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) is the maintainers' desk and not released today (the brief's rule); the OpenCL twin of the probe (__builtin_amdgcn_* paths for v_bfe_u32, v_perm_b32, v_bcnt_u32_b32, v_cndmask_b32, ds_bpermute_b32) is the next job on that card.

    Consequences per tier, Mac rows (the hash is latency-bound by 128 dependent DRAM reads; a family at W_new = 4 points is about 4% of the 64 instructions, so these per-op costs bound a family's hash-rate cost and are not hash rates; the 5% rule of 1.13.2 is argued from them, not measured, until a family is live):

    -
    TierWhat the rows meanWhat is being done
    Apple user (M-series laptop or desktop, the app's Metal worker)six of the seven candidates (shl, shr, bfe, andn, popc, sel) cost at most the live rotr step; clz the same as the reference; perm 1.13x (emulated); shfla 1.91x, the only candidate over the live shfl's cost by more than 2x on this card. At 4 points of 64 a 1.91x op costs under 1% of the program's ALU time, itself a small share of a latency-bound hash (approximate: argued, measured when live)the proposed order puts shfla after the plain datapath families (R6), so Apple pays it last; mm8 stays last
    NVIDIA user (8 to 32 GB card)every candidate is native and costs 0.95x to 1.23x the live rotr step (andn, the shifts, perm, sel under 1.0x; popc 1.14x; shfla 1.16x; bfe 1.17x; clz 1.23x); nothing on this card is emulated above a compiler sequence; at 4 points of 64 no family moves the ALU time by over 1% (argued) on a hash bound by DRAM readsthe family-live measurement at each unlock rehearsal; nothing to change in the order for NVIDIA
    AMD user (RX 9070 XT, 16 GB)owed: no row todaythe RTX 5090 machine 1 job when the desk is free
    A rig or a pool userthe same per-card figures; no family changes the dependent-read boundnothing until a family is live
    A chipevery candidate but mm8 is a 32-bit datapath structure (barrel shifter, byte crossbar, popcount tree, 32-lane shuffle crossbar: docs/plans/counter-asic-3-reserve.md section 3 names them with approximate areas); none is licensable as a block the way an int8 matrix unit isthe reserve order of that document
    +
    TierWhat the rows meanWhat is being done
    Apple user (M-series laptop or desktop, the app's Metal worker)six of the seven candidates (shl, shr, bfe, andn, popc, sel) cost at most the live rotr step; clz the same as the reference; perm 1.13x (emulated); shfla 1.91x, the only candidate over the live shfl's cost by more than 2x on this card. At 4 points of 64 a 1.91x op costs under 1% of the program's ALU time, itself a small share of a latency-bound hash (approximate: argued, measured when live)the proposed order puts shfla after the plain datapath families (R6), so Apple pays it last; mm8 stays last
    NVIDIA user (8 to 32 GB card)every candidate is native and costs 0.95x to 1.23x the live rotr step (andn, the shifts, perm, sel under 1.0x; popc 1.14x; shfla 1.16x; bfe 1.17x; clz 1.23x); nothing on this card is emulated above a compiler sequence; at 4 points of 64 no family moves the ALU time by over 1% (argued) on a hash bound by DRAM readsthe family-live measurement at each unlock rehearsal; nothing to change in the order for NVIDIA
    AMD user (RX 9070 XT, 16 GB)owed: no row todaythe the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job when the desk is free
    A rig or a pool userthe same per-card figures; no family changes the dependent-read boundnothing until a family is live
    A chipevery candidate but mm8 is a 32-bit datapath structure (barrel shifter, byte crossbar, popcount tree, 32-lane shuffle crossbar: docs/plans/counter-asic-3-reserve.md section 3 names them with approximate areas); none is licensable as a block the way an int8 matrix unit isthe reserve order of that document

    6 October 2026, Counter ASIC 3.0 gate run, the hash side

    Branch ca3-v4-hash, worker "v4-hash", on ca3-coord 3213ee9. The candidate class v4 mx8+sh256x27 composed with the era as the chain composes it (mx8-era<hex>+sh256x27, generator 3), on the devnet epoch-0 and day seeds at the genesis era (v4-devnet-epoch0) and at the six test eras of 2.0 (v4-era-0 to v4-era-5), with the class v3 control mx8-devnet-epoch0 re-exported beside them (proto-cuda/packs-ca3-v4/). Gates G1, G2 and G3 of docs/plans/counter-asic-2-rollout.md section 7 and the pinned verifier benchmark; the evidence tables and one JSON per run in docs/plans/counter-asic-3-gate/ (hash-gates.md). G4, G5 and G6 are the node's and the release's.

    G1, bit-exact (with-lock.sh run, 15:49:29 to 15:50:02Z, load 6.8 to 6.7). packbench --pack <dir> --batches 1 --batch-log2 24 --group 256 (Metal) and igneum-bench-cl --bench-pack --pack <dir> --batches 1 --batch-log2 24 (Apple OpenCL), both built from this branch: on all eight packs the cache FNV 448274a57f508cbc PASS, the dataset head and last PASS, vectors 3 of 3 standalone and 3 of 3 in batch (Metal), 96 of 96 lanes (Apple OpenCL), and one fingerprint per pack across both harnesses. The control reproduces 2.0's 90f794dd556f7a3b (the harness fired on a known case).

    -
    PackClassFingerprint 2^24 at base 0 (Metal = Apple OpenCL)RTX 5090 (CUDA NVRTC, PC 2)RX 9070 XT
    mx8-devnet-epoch0 (control)mx8-erad810f22d90f794dd556f7a3b90f794dd556f7a3bPC 1 job 1
    v4-devnet-epoch0mx8-erad810f22d+sh256x27f410c731b6bc2d31f410c731b6bc2d31PC 1 job 1
    v4-era-0mx8-erab2ed8a89+sh256x27b115c410e08be6cab115c410e08be6caPC 1 job 1
    v4-era-1mx8-era676a17fc+sh256x27edc2b18fc67e9d1cedc2b18fc67e9d1cPC 1 job 1
    v4-era-2mx8-era843155d7+sh256x27604ed87109570559604ed87109570559PC 1 job 1
    v4-era-3mx8-erad6367bfe+sh256x279541e2a41dde2ee69541e2a41dde2ee6PC 1 job 1
    v4-era-4mx8-era4488f3ed+sh256x27a9ffa2b67bd2e366a9ffa2b67bd2e366PC 1 job 1
    v4-era-5mx8-eraf897c84e+sh256x271f34e9c4659452491f34e9c465945249PC 1 job 1
    -

    The PC 2 job (run-ca3-v4-gates-pc2-20261006, tools/ca3-v4/pc2-v4-gates.ps1, 15:52:23 to 15:52:49Z, exit 0, 26 s, the installed 0.3.11 igneum-worker-cuda.exe through NVRTC on each pack's own text, beside the app's miner, the prover untouched, no card switched off: bit-exactness is not load sensitive) ran G1 (--bench --batches 5 --batch-log2 24) and G2 on all eight packs in one job. The intake's report keeps the last 200 KB of job.log and the 8 x 1,024 G2 found lines filled it; the G1 lines came home through a collect whose command filters job.log (collect-ca3-v4-g1only-20261006, 16:12Z): self-test PASS on every pack, every fingerprint equal to the Apple M5 Max's (the column above), NVRTC 180 to 274 ms per pack, the 1 GiB build 38 to 45 ms. G1 is GREEN on NVIDIA and Apple; AMD is PC 1 job 1.

    -

    G2, the verifier exact on 1,024 hashes per card (with-lock.sh run, 15:53:54 to 15:54:22Z, load 6.8 to 8.9). One serve-mode job per card and pack, job g2 00..01 ffffffffffffffff 0 1024 <epoch> <day> class=v3 era=<hex> (Metal after prepare <epoch> <day> <pack> class=v3 era=<hex>), every nonce a found line, re-hashed with igneum-pow hash-bound --prehash 00..01 --nonce 0 --count 1024 on the same pack (--count ported from ca2-era). Metal 1,024 of 1,024 on all eight packs; Apple OpenCL 1,024 of 1,024 on all eight; RTX 5090 (igneum-worker-cuda.exe --serve --pack <dir> --race off, the same job) 1,024 of 1,024 on all eight packs, every found line equal to the Apple M5 Max's verifier; RX 9070 XT: PC 1 job 1. G2 is GREEN on NVIDIA and Apple.

    +
    PackClassFingerprint 2^24 at base 0 (Metal = Apple OpenCL)RTX 5090 (CUDA NVRTC, the RTX 5090 Windows rig)RX 9070 XT
    mx8-devnet-epoch0 (control)mx8-erad810f22d90f794dd556f7a3b90f794dd556f7a3bthe three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-devnet-epoch0mx8-erad810f22d+sh256x27f410c731b6bc2d31f410c731b6bc2d31the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-era-0mx8-erab2ed8a89+sh256x27b115c410e08be6cab115c410e08be6cathe three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-era-1mx8-era676a17fc+sh256x27edc2b18fc67e9d1cedc2b18fc67e9d1cthe three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-era-2mx8-era843155d7+sh256x27604ed87109570559604ed87109570559the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-era-3mx8-erad6367bfe+sh256x279541e2a41dde2ee69541e2a41dde2ee6the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-era-4mx8-era4488f3ed+sh256x27a9ffa2b67bd2e366a9ffa2b67bd2e366the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    v4-era-5mx8-eraf897c84e+sh256x271f34e9c4659452491f34e9c465945249the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1
    +

    The the RTX 5090 Windows rig job (run-ca3-v4-gates-pc2-20261006, tools/ca3-v4/pc2-v4-gates.ps1, 15:52:23 to 15:52:49Z, exit 0, 26 s, the installed 0.3.11 igneum-worker-cuda.exe through NVRTC on each pack's own text, beside the app's miner, the prover untouched, no card switched off: bit-exactness is not load sensitive) ran G1 (--bench --batches 5 --batch-log2 24) and G2 on all eight packs in one job. The intake's report keeps the last 200 KB of job.log and the 8 x 1,024 G2 found lines filled it; the G1 lines came home through a collect whose command filters job.log (collect-ca3-v4-g1only-20261006, 16:12Z): self-test PASS on every pack, every fingerprint equal to the Apple M5 Max's (the column above), NVRTC 180 to 274 ms per pack, the 1 GiB build 38 to 45 ms. G1 is GREEN on NVIDIA and Apple; AMD is the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1.

    +

    G2, the verifier exact on 1,024 hashes per card (with-lock.sh run, 15:53:54 to 15:54:22Z, load 6.8 to 8.9). One serve-mode job per card and pack, job g2 00..01 ffffffffffffffff 0 1024 <epoch> <day> class=v3 era=<hex> (Metal after prepare <epoch> <day> <pack> class=v3 era=<hex>), every nonce a found line, re-hashed with igneum-pow hash-bound --prehash 00..01 --nonce 0 --count 1024 on the same pack (--count ported from ca2-era). Metal 1,024 of 1,024 on all eight packs; Apple OpenCL 1,024 of 1,024 on all eight; RTX 5090 (igneum-worker-cuda.exe --serve --pack <dir> --race off, the same job) 1,024 of 1,024 on all eight packs, every found line equal to the Apple M5 Max's verifier; RX 9070 XT: the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1. G2 is GREEN on NVIDIA and Apple.

    G3, the soundness suite on the class. cargo test -j4 --release in igneum-pow (with-lock.sh build, nice 19, cargo 1.99.0, 15:49:29 to 15:50:01Z, load 6.8): 59 + 7 + 4 + 19 + 7 = 96 of 96. The mixer harness now takes the class (IGNEUM_MIXER_CLASS) in the fuzz, the stats and the determinism test, an era to compose (IGNEUM_MIXER_ERA=igneum-era-test/<n>), and a shadow contract (S instructions, no load, every field in range, the base program equal to the class's without the shadow draw for draw); the edge test is the dataset's alone and takes no class. On mx8+sh256x27 (15:54:25 to 15:55:39Z, load 9.1): fuzz 200 programs, 800 units, 200 in the top 256 nonces; stats avalanche 49.96 and 49.98 percent, worst bit z 2.65 and 3.56, 0 duplicates (v2 49.87 and 49.98, z 2.25 and 2.30); edge pass; determinism two builds equal and equal to the pinned packs-ca3-shadow/sh256x27. With era test/0 composed (50 programs, 200 units, 15:56:35 to 15:57:03Z, load 12.6): 4 of 4, avalanche 50.03 and 50.11, z 2.65 and 3.76. The GPU fuzz on the written packs (packbench --batches 1 --batch-log2 9 --batch-base 4294967040, every tenth on Apple OpenCL --batch-log2 10, with-lock.sh run, 15:55:42 to 15:58:21Z, load 11.3 to 12.3): Metal 200 of 200 and 50 of 50, Apple OpenCL 20 of 20 and 5 of 5. Known-failed case: the first era-composed run FAILED (1 failed, 15:55:42Z) on assert_ne!(p.program_id(), base.program_id()), which is the finding below.

    The verifier (with-lock.sh measure, one session, 15:54:27 to 15:54:31Z, load 9.1 to 9.4; one core on a loaded box, within 3 percent of the quiet figures). igneum-pow bench --seed igneum-genesis --day 2026-10-03 --warps 20 --class <c>, two rounds:

    Classms per 32-lane warp, avg of 20 (round 1 / round 2)Worst cold single runAgainst x82019-class core by the 2.5x rule (approximate)Gate
    v20.655 / 0.6480.674about 1.6 ms10 ms
    x8 (mx8)2.149 / 2.1202.5261about 5.4 ms10 ms
    mx8+sh256x272.326 / 2.3072.559+0.18 ms, +8.5 percentabout 5.8 ms (worst cold about 6.4)10 ms, about 4 ms spare

    Per tier: 73 microseconds per hash on an M5 Max core, so a pool checks about 13,700 shares per second per such core and about 5,500 per 2019-class core (approximate); a node on any tier verifies a warp inside the gate; no tier is slower than under x8 by more than 8.5 percent.

    -

    Findings. (1) Under the chain's path a generator-3 program's id is program_id(3, seed, attempt), class-independent: the seven exported packs carry 73bcbfe8ccf988f1 with and without the shadow, and 50 of 50 fuzz seeds agree. A node and a miner could agree on the id while running different classes, and 2.0's G4 check program_ids_differ_across_the_switch would not fire across a v4 activation: the v4 seam (G4, G6) must stamp its own generator version or put the class in the id. The hash needs nothing for it; the cut must not go without it. (2) The report cap: a G2 playbook that prints 8,192 found lines loses its own G1 lines; the tooling fix is a found-lines file plus a count and digest on stdout, with a collect. Owed: AMD (PC 1 job 1), the 2019-class core (O-1.14).

    +

    Findings. (1) Under the chain's path a generator-3 program's id is program_id(3, seed, attempt), class-independent: the seven exported packs carry 73bcbfe8ccf988f1 with and without the shadow, and 50 of 50 fuzz seeds agree. A node and a miner could agree on the id while running different classes, and 2.0's G4 check program_ids_differ_across_the_switch would not fire across a v4 activation: the v4 seam (G4, G6) must stamp its own generator version or put the class in the id. The hash needs nothing for it; the cut must not go without it. (2) The report cap: a G2 playbook that prints 8,192 found lines loses its own G1 lines; the tooling fix is a found-lines file plus a count and digest on stdout, with a collect. Owed: AMD (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job 1), the 2019-class core (O-1.14).

    6 October 2026, 00:4xZ, the empty /api/state reply (proving v1 branch)

    -

    Reported by the aggregation-cost agent: PC 2's /api/state answered {} (2 bytes) at 22:22Z, 22:41Z and 00:18Z. Not measured on PC 2 (no job); derived from the app source and node 1's RPC, read-only on the Apple M5 Max:

    +

    Reported by the aggregation-cost agent: the RTX 5090 Windows rig's /api/state answered {} (2 bytes) at 22:22Z, 22:41Z and 00:18Z. Not measured on the RTX 5090 Windows rig (no job); derived from the app source and node 1's RPC, read-only on the Apple M5 Max:

    FigureValueSource
    Paid shards, devnet, all provers663curl -s 127.0.0.1:26790 -d '{"jsonrpc":"2.0","id":1,"method":"igneum_getProvingStatus","params":[]}' at tip DAA 0x22caf
    Paid wei, all provers0x2c2961a69990745400 = 814.64 IGNsame call
    Average per paid shard1.23 IGN (approximate: the mean over 663)814.64 / 663
    u64::MAX in IGN18.452^64 - 1 over 1e18
    Paid shards per app start before the reply empties15 (approximate: at the mean payout)18.45 / 1.23

    Cause: ProvingState.paid_wei: u128 and serde_json to_value (1.0.151, value/ser.rs serialize_u128: u64 range or an error); the error became json!({}). Fix: the field serialises as a decimal string; state_json logs the error once. Test a_paid_total_over_u64_max_still_serialises_the_whole_state (cargo test --offline -q paid_wei, 1 passed).

    The fast-time 3-node harness (tools/proving-v1/net.mjs, 29950+, suffix 956, every node in trust mode, three vmine voters, v0 at DAA 60, v1 at DAA 120, 4 blocks a segment, unproven after 60 DAA, a tenth to the aggregator; fork b177718e built on this Mac)run 2, 19:13:01Z to 19:16:19Z, under the run lock: PASSED, 21 checks in 197.3 s (tools/proving-v1/report-2026-10-05.json). v1 start = chain block 119 on all three nodes; the native statement identical on all three. Known-finished: segment 119..122's fresh-chain record submitted to n1 at t=131.1 s, relayed, verified (trust) and PAID on n0 1.0 s later at chain block 129, 253,611,648,000,000,000 wei = a tenth of the four credits, the same on every node, the payout address holding it. Chain rule: segment 123..126's fresh-chain record refused ("does not chain to segment 119..122 ... proven (record paid at chain block 129)"), the continuing one (chain_len 8) accepted and paid. Known-failed: segment 127..130 left without a record: a fresh-chain record for 131..134 refused while 127..130 was pending ("pending until DAA 191"); at DAA 192 the status read unproven, a late record for 127..130 refused ("unproven: carried after the deadline"), the fresh-chain record for 131..134 accepted and paid with chain_len 4; segmentsInWindow proven 3, unproven 1. The shard side: a v1 shard's shardWei = 90% of its block's credit. Run 1 (19:10Z) failed in its own tooling (the signer's argument order), fixed

    5 October 2026 (night), aggregation cost on the RTX 5090: what a per-block aggregation spends and what each lever gives (proving engineer, agg-cost)

    -

    the maintainers, 5 October 2026: "fix everything else in the numbers tonight". The number under test: the chained segment aggregation cost 9.6 to 9.7 s a block on PC 2's 5090 while the card mined (chain-pc2-pv1c, the entry above), 2.2 s on 4 October with the card to itself. Target: under 3 s a block, the miner's slowdown of the prover under 1.5x, the proof statement unchanged. Branch agg-cost (worktree igneum-wt-agg-cost, from proving-v1 219517f). Host changes (statement untouched, elf/ untouched): the aggregation's stdin build timed apart from the prove call, the deferred-proof count and the SP1 knobs in the RESULT lines, --mode chain --save-shards (every shard's compressed proof written next to the results, so --mode aggregate re-runs the same proofs under other settings). Jobs: agg-cost-pc2-1 (21:01:20Z to 21:25:11Z, tools/proving-v1/pc2-agg-cost.ps1, the package igneum-prove-wsl2-aggcost.zip fetched by fetch-prove-aggcost 20:55:39Z, built in WSL2 against the live target dir in 5 s, installed to <server path>, the live <server path> untouched, --mode id the pinned pair) and agg-cost-pc2-2 (21:34:00Z, the same script). The live prover was switched OFF for the runs (its sp1-gpu-server would otherwise be shared through /tmp/sp1-cuda-0.sock and carry its own environment; gpu_server_before running=0) and ON again at the end. Fixtures: four consecutive live blocks cut from PC 2's own node (86165..86168 at tip 86195, one empty shard each, every one MATCHES natively), the same four for every phase of job 1. App 0.3.9 on PC 2 throughout.

    +

    the maintainers, 5 October 2026: "fix everything else in the numbers tonight". The number under test: the chained segment aggregation cost 9.6 to 9.7 s a block on the RTX 5090 Windows rig's 5090 while the card mined (chain-pc2-pv1c, the entry above), 2.2 s on 4 October with the card to itself. Target: under 3 s a block, the miner's slowdown of the prover under 1.5x, the proof statement unchanged. Branch agg-cost (worktree igneum-wt-agg-cost, from proving-v1 219517f). Host changes (statement untouched, elf/ untouched): the aggregation's stdin build timed apart from the prove call, the deferred-proof count and the SP1 knobs in the RESULT lines, --mode chain --save-shards (every shard's compressed proof written next to the results, so --mode aggregate re-runs the same proofs under other settings). Jobs: agg-cost-pc2-1 (21:01:20Z to 21:25:11Z, tools/proving-v1/pc2-agg-cost.ps1, the package igneum-prove-wsl2-aggcost.zip fetched by fetch-prove-aggcost 20:55:39Z, built in WSL2 against the live target dir in 5 s, installed to <server path>, the live <server path> untouched, --mode id the pinned pair) and agg-cost-pc2-2 (21:34:00Z, the same script). The live prover was switched OFF for the runs (its sp1-gpu-server would otherwise be shared through /tmp/sp1-cuda-0.sock and carry its own environment; gpu_server_before running=0) and ON again at the end. Fixtures: four consecutive live blocks cut from the RTX 5090 Windows rig's own node (86165..86168 at tip 86195, one empty shard each, every one MATCHES natively), the same four for every phase of job 1. App 0.3.9 on the RTX 5090 Windows rig throughout.

    Known-finished case of the host changes before the GPU (this Mac, CPU, run lock, 20:41Z to 20:44Z): --mode chain over fixtures/chain/block-81046.json with --save-shards (shard 38.5 s, aggregate 43.4 s, the proof file written), then --mode aggregate over that saved shard proof with SP1_WORKER_VERIFY_INTERMEDIATES=false (46.6 s, the same statement 0x3dedb8ea...), --mode verify-segment VERIFIED in 0.027 s; known-failed: a wrong statement NOT VERIFIED in 0.027 s. Unit tests: cargo test --release -p igneum-prove-core -p igneum-prove-host: core 8 passed, host 9 passed and 1 ignored (build lock, 20:53Z).

    Lever 1, the profile: where a per-block aggregation goes

    WhatMeasured (job agg-cost-pc2-1)
    The host's own share of an aggregation (the stdin build: the AggInput, the proof clones into the request)0.000 s on every block, mining or idle (the stdin field of every RESULT chain block line): everything is inside the one prove().compressed() call to the GPU server
    The GPU server's log at RUST_LOG=info (phase A0, the same chain of 1, stderr captured)1 line: sp1-gpu-server 6.8.1 prints no spans and no timings, so the step costs below are read from the deferred-proof count, not from a profiler
    Aggregation with 1 deferred proof (the first block, no previous proof) against 2 (every chained block), the card mining7.9 s against 9.6, 9.6, 9.8 s: the second deferred proof costs 1.7 to 1.9 s under the miner
    The same, the miners paused (phase C, the same fixtures, 21:05:51Z)1.7 s against 2.1, 2.1, 2.2 s: the second deferred proof costs 0.4 to 0.5 s alone
    The shard proof of an empty shard7.4 to 7.8 s mining, 1.9 to 2.2 s alone
    A whole block (one empty shard plus its aggregation)17.1 to 17.3 s mining (end to end 67.4 s for 4 blocks), 4.1 s alone (16.4 s for 4)
    GPU utilisation over the phase (1-s nvidia-smi samples)93.9% mining (80 samples, the miner's), 15.8% alone (32 samples): the prover alone keeps the card busy a sixth of the time. Its work is short GPU bursts between CPU phases (the executor, the witness and recursion-program generation run on the CPU inside the server), and the miner's kernels fill the gaps
    GPU memory peak16,195 MiB mining (the miner's 3.4 GB resident), 14,483 MiB alone
    The slowdown by the miner, same fixtures, same host, 2 min apartshards 3.6x, the first aggregation 4.6x, a chained aggregation 4.5x, a block 4.2x
    Setup per host process (client plus two key setups)13.0 to 15.7 s, mining or not
    @@ -761,19 +718,19 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    Reading. A batch fold halves to quarters the per-block aggregation but changes the aggregator's statement (AggInput carries one block's shards and the guest asserts one block hash), so it is a new pinned guest and a new program id: a provers-off drain and a rollout (proving/README.md, pinned guests). It does not reach 3 s on a mining card by itself (2.8 s at K = 8 is on the line), and the shard proof beside it stays 7.4 s a block on a mining card. The lever that moves both is the card's other job, lever 4. A tree fold gains nothing here because the fixed part of a call (the core shard and the lift) dominates the per-proof part 4 to 1.

    Levers 3 and 4, two streams and the miner's kernels (job agg-cost-pc2-2 and the re-run)

    Job agg-cost-pc2-2 (21:34:00Z to 21:49:22Z) ran with the 5090 idle throughout: job 1's /api/resume had left the worker off (below), so the rows that needed the miner (the batch-log2 curve, the two streams beside the miner, the time-slice policy, the chosen combination) are void and wait for a re-run; the idle rows are measured.

    -
    WhatMeasured (job agg-cost-pc2-2, card idle)
    Aggregate-only over job 1's four saved shard proofs (--mode aggregate --proofs b1;b2;b3;b4 --parent ..., one process, the same statement 0x3a995f24... as the chain run), default knobs (phase B0, then C1)1.7, 2.0, 2.0, 2.0 s (1, 2, 2, 2 deferred proofs), 8.1 s for four; C1: 1.8, 2.1, 2.1, 2.1 s, 8.3 s
    The same with SP1_WORKER_VERIFY_INTERMEDIATES=false (phase B; the server inherits the host's environment, the knob printed in the sp1 knobs line)1.7, 2.0, 2.0, 2.0 s, 7.8 s for four: no gain (0.3 s over four, inside the run-to-run spread of 0.2 s). The knobs that change the recursion shape (SP1_WORKER_MAX_COMPOSE_ARITY, MAX_REDUCE_ARITY) were not tried: a different shape is a different recursion key set and the pinned verifier would refuse the proof
    A 4-deferred aggregation (block-344-shards4, four prototype shards of 6.75 M pgas, phase C2)shards 42.8 s (10.7 s each, the 4 October 10.2 to 10.7 s), aggregation 2.4 s with 4 deferred proofs; GPU peak 28,402 MiB (the prototype shard's 28.3 GB), utilisation 27.7% over the phase. With 1.7 s at one deferred proof and 2.0 to 2.1 s at two: 0.25 s per further deferred proof alone, so a batch of 8 would cost about 3.5 s a call, 0.45 s a block (estimate, the pinned statement forbids it)
    Two host processes at once on the one card (phase G0: chains of 2 on disjoint blocks, started 2 s apart)both connected to ONE sp1-gpu-server (the first process's child; the socket is per device, /tmp/sp1-cuda-0.sock): process 1 shard 2.2 and 3.5 s, aggregation 3.0 and 4.0 s (12.9 s for 2 blocks against 8.2 s alone); process 2 shard 3.3 s, aggregation 3.6 s, then its second block died with CudaClientError: Failed to read the response: early eof when process 1 finished and its server exited. GPU 24,911 MiB, utilisation 12.4% and 13.1%. Two streams through SP1 6.8.1's server are serialised on one socket and the second dies with the first: no throughput gain (3 blocks in 33 s against 4 in 16.4 s) and a failure mode; lever 3 is closed on this SP1 version
    Job 3 (agg-cost-pc2-3, 22:41:15Z, app 0.3.10, the same script with the socket rule and a card switch): phase A, the app's 5090 miner at 117.0 MH/s mean (n 3, STATUS lines 22:44:45Z to 22:46:11Z), four fresh live blocks 90896..90899shards 8.0, 7.8, 7.6, 7.8 s; aggregations 8.0 s (1 deferred), 10.0, 10.0, 10.0 s (2 deferred); 69.5 s for four, 17.8 s a block; GPU 93.8%, peak 16,245 MiB: the job-1 baseline reproduced 100 min later on other blocks
    Job 3's own-miner phasesvoid: the state reads came back empty (the class below), the card switch did nothing, phase D launched my miner beside the app's (the app's dropped to 62.2 MH/s, mine read 60.6 MH/s), then PC 2's app restarted at 23:03:30Z and the job died with it; no curve point
    The GPU time-slice policy (nvidia-smi compute-policy --set-timeslice, the restore job agg-cost-restore-1, 23:16:53Z)"Not Supported" on PC 2 (RTX 5090, driver 13.3, the Windows nvidia-smi, not elevated): the lever is closed on this driver; an elevated try is not worth a slot, the error is the driver's, not a permission's
    The own-miner phases of job 2void: no 5090 miner was running to copy the command line from (the worker off since 21:25Z)
    -

    The curve, job agg-cost-pc2-6 (01:12:09Z to 01:24:14Z, app 0.3.11, PC 2 to itself; every phase closed before the next job landed on PC 2 at 01:24:21Z). The app's 5090 miner switched off through /api/cards (the keys from settings.json; the worker was still alive after 120 s, /api/pause as the fallback stopped it in 5 s), then the job's OWN miner on the 5090 with the app's command line (igneum-miner mine ... --worker igneum-worker-cuda.exe --identities 8 --worker-args "--device 0 --pack packs\devnet --race off [--batch-log2 B]", the base variant, its STATUS line every 10 s), the same four live blocks 96556..96559 (one empty shard each) proven by --mode chain under it, the miner's rate from its own now= field (the first two lines skipped). --batch-log2 B sets the worker's nonces per kernel launch (2^B; 22 is the worker's default, 4,194,304 nonces, about 35 ms a launch at 120 MH/s; proto-cuda/nvrtc/worker.cpp).

    +
    WhatMeasured (job agg-cost-pc2-2, card idle)
    Aggregate-only over job 1's four saved shard proofs (--mode aggregate --proofs b1;b2;b3;b4 --parent ..., one process, the same statement 0x3a995f24... as the chain run), default knobs (phase B0, then C1)1.7, 2.0, 2.0, 2.0 s (1, 2, 2, 2 deferred proofs), 8.1 s for four; C1: 1.8, 2.1, 2.1, 2.1 s, 8.3 s
    The same with SP1_WORKER_VERIFY_INTERMEDIATES=false (phase B; the server inherits the host's environment, the knob printed in the sp1 knobs line)1.7, 2.0, 2.0, 2.0 s, 7.8 s for four: no gain (0.3 s over four, inside the run-to-run spread of 0.2 s). The knobs that change the recursion shape (SP1_WORKER_MAX_COMPOSE_ARITY, MAX_REDUCE_ARITY) were not tried: a different shape is a different recursion key set and the pinned verifier would refuse the proof
    A 4-deferred aggregation (block-344-shards4, four prototype shards of 6.75 M pgas, phase C2)shards 42.8 s (10.7 s each, the 4 October 10.2 to 10.7 s), aggregation 2.4 s with 4 deferred proofs; GPU peak 28,402 MiB (the prototype shard's 28.3 GB), utilisation 27.7% over the phase. With 1.7 s at one deferred proof and 2.0 to 2.1 s at two: 0.25 s per further deferred proof alone, so a batch of 8 would cost about 3.5 s a call, 0.45 s a block (estimate, the pinned statement forbids it)
    Two host processes at once on the one card (phase G0: chains of 2 on disjoint blocks, started 2 s apart)both connected to ONE sp1-gpu-server (the first process's child; the socket is per device, /tmp/sp1-cuda-0.sock): process 1 shard 2.2 and 3.5 s, aggregation 3.0 and 4.0 s (12.9 s for 2 blocks against 8.2 s alone); process 2 shard 3.3 s, aggregation 3.6 s, then its second block died with CudaClientError: Failed to read the response: early eof when process 1 finished and its server exited. GPU 24,911 MiB, utilisation 12.4% and 13.1%. Two streams through SP1 6.8.1's server are serialised on one socket and the second dies with the first: no throughput gain (3 blocks in 33 s against 4 in 16.4 s) and a failure mode; lever 3 is closed on this SP1 version
    Job 3 (agg-cost-pc2-3, 22:41:15Z, app 0.3.10, the same script with the socket rule and a card switch): phase A, the app's 5090 miner at 117.0 MH/s mean (n 3, STATUS lines 22:44:45Z to 22:46:11Z), four fresh live blocks 90896..90899shards 8.0, 7.8, 7.6, 7.8 s; aggregations 8.0 s (1 deferred), 10.0, 10.0, 10.0 s (2 deferred); 69.5 s for four, 17.8 s a block; GPU 93.8%, peak 16,245 MiB: the job-1 baseline reproduced 100 min later on other blocks
    Job 3's own-miner phasesvoid: the state reads came back empty (the class below), the card switch did nothing, phase D launched my miner beside the app's (the app's dropped to 62.2 MH/s, mine read 60.6 MH/s), then the RTX 5090 Windows rig's app restarted at 23:03:30Z and the job died with it; no curve point
    The GPU time-slice policy (nvidia-smi compute-policy --set-timeslice, the restore job agg-cost-restore-1, 23:16:53Z)"Not Supported" on the RTX 5090 Windows rig (RTX 5090, driver 13.3, the Windows nvidia-smi, not elevated): the lever is closed on this driver; an elevated try is not worth a slot, the error is the driver's, not a permission's
    The own-miner phases of job 2void: no 5090 miner was running to copy the command line from (the worker off since 21:25Z)
    +

    The curve, job agg-cost-pc2-6 (01:12:09Z to 01:24:14Z, app 0.3.11, the RTX 5090 Windows rig to itself; every phase closed before the next job landed on the RTX 5090 Windows rig at 01:24:21Z). The app's 5090 miner switched off through /api/cards (the keys from settings.json; the worker was still alive after 120 s, /api/pause as the fallback stopped it in 5 s), then the job's OWN miner on the 5090 with the app's command line (igneum-miner mine ... --worker igneum-worker-cuda.exe --identities 8 --worker-args "--device 0 --pack packs\devnet --race off [--batch-log2 B]", the base variant, its STATUS line every 10 s), the same four live blocks 96556..96559 (one empty shard each) proven by --mode chain under it, the miner's rate from its own now= field (the first two lines skipped). --batch-log2 B sets the worker's nonces per kernel launch (2^B; 22 is the worker's default, 4,194,304 nonces, about 35 ms a launch at 120 MH/s; proto-cuda/nvrtc/worker.cpp).

    batch-log2Shard proof (4, s)Aggregation (1 deferred, then 2) (s)A block (s)GPU util. (%)GPU peak (MiB)Own miner (MH/s wall, n)Against the card alone (4.1 s a block)
    22 (the default), phase D8.1, 7.8, 7.9, 7.88.4; 10.3, 10.0, 10.418.195.516,580103.9 (9)4.4x
    20, E208.1, 7.8, 7.8, 7.88.4; 10.3, 10.1, 10.118.094.916,461103.7 (8)4.4x
    18, E187.0, 6.7, 6.7, 6.77.2; 8.9, 8.8, 8.815.691.516,48799.3 (7), minus 4.4%3.8x
    16, E165.1, 4.9, 4.9, 4.95.0; 6.1, 6.2, 6.211.185.316,51983.8 (6), minus 19%2.7x
    16 again, phase H (the job's own choice: the shortest chain)5.0, 4.9, 4.8, 4.94.9; 6.1, 6.2, 6.211.185.716,48784.0 (6)2.7x
    -

    Reading. Between 2^22 and 2^20 nothing moves: the card's time-slice scheduler alternates the two contexts whatever the kernel length above a few milliseconds. From 2^18 down the miner's launches get short enough (about 2 ms at 2^18, 0.5 ms at 2^16) that the prover's bursts find the card sooner, and the miner pays in launch overhead and idle gaps: at 2^16 the prover runs 1.6x faster (18.1 to 11.1 s a block, the chained aggregation 10.2 to 6.2 s) for a fifth of the hash rate, and it is still 2.7x slower than on a card to itself. The trade is about 1 MH/s per 0.37 s of block time at the 2^16 point, and the 3-s aggregation and the 1.5x slowdown are not reachable on a mining card by the kernel length; a 2^14 point (approximate, extrapolated) would be about 8 s a block at about 65 MH/s. The phase E0 (a 4-deferred aggregation under the miner) failed in 0.1 s: its proof paths pointed at / where job 1 had left its shard proofs, but job 2's block-344 proofs sit in job 2's own folder ($JOB was exported from job 2 on); the 4-deferred cost under the miner stays an estimate (lever 2 above). The app's own 5090 miner ran at 117 MH/s (job 3, 22:44Z) and 110 to 129 MH/s (its STATUS lines at 01:10Z) with the prover beside it, against my miner's 104 MH/s at the default batch: my miner runs the base variant with --race off (no tuning file on PC 2), so the curve's rates are relative to each other, not to the app's.

    +

    Reading. Between 2^22 and 2^20 nothing moves: the card's time-slice scheduler alternates the two contexts whatever the kernel length above a few milliseconds. From 2^18 down the miner's launches get short enough (about 2 ms at 2^18, 0.5 ms at 2^16) that the prover's bursts find the card sooner, and the miner pays in launch overhead and idle gaps: at 2^16 the prover runs 1.6x faster (18.1 to 11.1 s a block, the chained aggregation 10.2 to 6.2 s) for a fifth of the hash rate, and it is still 2.7x slower than on a card to itself. The trade is about 1 MH/s per 0.37 s of block time at the 2^16 point, and the 3-s aggregation and the 1.5x slowdown are not reachable on a mining card by the kernel length; a 2^14 point (approximate, extrapolated) would be about 8 s a block at about 65 MH/s. The phase E0 (a 4-deferred aggregation under the miner) failed in 0.1 s: its proof paths pointed at / where job 1 had left its shard proofs, but job 2's block-344 proofs sit in job 2's own folder ($JOB was exported from job 2 on); the 4-deferred cost under the miner stays an estimate (lever 2 above). The app's own 5090 miner ran at 117 MH/s (job 3, 22:44Z) and 110 to 129 MH/s (its STATUS lines at 01:10Z) with the prover beside it, against my miner's 104 MH/s at the default batch: my miner runs the base variant with --race off (no tuning file on the RTX 5090 Windows rig), so the curve's rates are relative to each other, not to the app's.

    Lever 5, the host side under WSL2 (what the chain-mode numbers leave out)

    -
    WhatMeasured
    The export (igneum_exportSegments 0..tip, 75 to 77 MB over curl.exe to a file on C:)1.1 to 1.5 s
    The cut (igneum-prove-export replaying from genesis, then --mode native), four blocks18 s for four including the native checks (21:01:28Z to 21:01:46Z), about 4 s a block; the export's file sits on /mnt/c
    The key setup per host process13.0 to 15.7 s on PC 2 (8.0 to 8.5 s on the Apple M5 Max CPU): --mode chain and --mode aggregate pay it once per process, the app's loop pays it per shard
    The proof file write through the WSL2 bridgethe 4 October entry ("shard proving on the RTX 5090"): 24 min of unbuffered save across /mnt/c, fixed by the 4 MB buffer; tonight --save-shards wrote the four 1.27 MB proofs inside the chain phase with no visible gap (the A phase's 80.4 s wall against 67.4 s of proving plus 13.0 s of setup)
    Native Linuxnot measured: no native Linux machine with an NVIDIA card exists in the project tonight, and the 4 October numbers were also WSL2 (Ubuntu 24.04 under PC 2's Windows). The WSL2 cost inside a prove() call is not separable from here; the host-side pieces above are what a native box would also skip or keep
    +
    WhatMeasured
    The export (igneum_exportSegments 0..tip, 75 to 77 MB over curl.exe to a file on C:)1.1 to 1.5 s
    The cut (igneum-prove-export replaying from genesis, then --mode native), four blocks18 s for four including the native checks (21:01:28Z to 21:01:46Z), about 4 s a block; the export's file sits on /mnt/c
    The key setup per host process13.0 to 15.7 s on the RTX 5090 Windows rig (8.0 to 8.5 s on the Apple M5 Max CPU): --mode chain and --mode aggregate pay it once per process, the app's loop pays it per shard
    The proof file write through the WSL2 bridgethe 4 October entry ("shard proving on the RTX 5090"): 24 min of unbuffered save across /mnt/c, fixed by the 4 MB buffer; tonight --save-shards wrote the four 1.27 MB proofs inside the chain phase with no visible gap (the A phase's 80.4 s wall against 67.4 s of proving plus 13.0 s of setup)
    Native Linuxnot measured: no native Linux machine with an NVIDIA card exists in the project tonight, and the 4 October numbers were also WSL2 (Ubuntu 24.04 under the RTX 5090 Windows rig's Windows). The WSL2 cost inside a prove() call is not separable from here; the host-side pieces above are what a native box would also skip or keep

    What went wrong, measured

    -
    WhatFixed
    Job 1's per-phase command ran with $JOB empty (the bash variables of vars.sh were set, not exported, and the command runs in a child bash): --out /results-A.json, the saved shard proofs in / on the WSL root, so the aggregate-only phases B0, B, C1 and the prototype-shard phase C2 failed in 0.0 s ("No such file")export in vars.sh; job 2 reads the proofs from /
    Job 1's own-miner phases launched the iGPU miner (the first igneum-miner mine process matched; the 5090's is the second) and if (StartMiner ...) was always true (PowerShell: a function's emitted RESULT strings are part of its output), so D and E ran with the 5090 idle and the AMD iGPU at 3.4 MH/s: three more idle replicates of the chain (2.0 to 2.2 s shards, 1.8 and 2.2 s aggregations), no curvethe miner matched on igneum-worker-cuda, the outcome in a script-scope flag, --race off for the own miner (no tuning file on PC 2; a race costs up to 120 s a start)
    Job 1's /api/resume at 21:25:11Z answered ok and the 5090 miner stayed off (card state off, hash 0.0, 1,760 MiB on the card) until the 0.3.10 restart; job 2 waited its full 600 s for a hash rate and ran its mining phases voidthe restore job tools/proving-v1/pc2-agg-cost-restore.ps1 also posts /api/start; the Counter ASIC coordinator opened a task chip for the resume defect
    Jobs 3 and 4 (agg-cost-pc2-3 22:41Z on app 0.3.10, agg-cost-pc2-4 00:18Z on 0.3.11): every /api/state read came back as the two bytes {} (job 4's raw-body print: raw_len=2; the same reads gave the full state on 0.3.9 at 21:01Z and the AMD agent saw the empty reply at 22:22Z), so the card switch found no card, the app's 5090 miner kept mining, and job 3 ran a second miner beside it (two miners at about 60 MH/s each) while job 4's double-mining guard voided its own-miner phases. The class is the app's, not the reader's: state_json() (engine.rs:180) does serde_json::to_value(st).unwrap_or(json!({})), and the value that fails is ProvingState.paid_wei: u128 (serde_json 1.0.151 refuses a u128 over u64::MAX, 18.45 IGN; the proving-v1 agent's diagnosis): a paid shard averages 1.23 IGN, so the reply empties about 15 paid shards after every app start and comes back at the next restart, which matches the times (full at 21:01Z with paid_wei 0, empty from 22:22Z after the prover had paid from 22:02Z). Fixed on the app branch proving-v1 at 6714a45 (paid_wei as a decimal string, the error logged, an {"error":...} reply on any future failure)job 5 reads the card keys from the app's settings.json (cards: key to enabled and identities), restores the 5090's 8 identities first (the restore job of 23:16:53Z had set 2: its parser read the next card's value), refuses before any pause when it cannot name the card, waits on the CUDA worker process count for the card to stop, and checks the worker is back at the end
    Job 5 (agg-cost-pc2-5, 01:10:44Z) failed at PowerShell's parse in 1 s: $RestoreIdentities: inside a double-quoted string (a drive-qualified variable); no card or miner touched${RestoreIdentities}:; the other $name: shapes are inside single-quoted bash here-strings
    Job 6's identities step found settings.json already at 8 identities under the active key nvidia:0:NVIDIA GeForce RTX 5090 (a stale key nvidia:NVIDIA GeForce RTX 5090 carries 2), so no change was sent; job 6's /api/cards with the 5090 disabled answered ok but the worker ran on for 120 s, /api/pause stopped it in 5 s, and at the end /api/resume brought it back in 5 s on 0.3.11the card switch keeps the pause as its fallback; the resume path works on 0.3.11
    PC 2 ran three jobs at once from 01:24Z (run-prover-on-pc2-20261006 at 01:24:21Z, the ledger suites build at 01:26:15Z, while agg-cost-pc2-6's closing report was still being uploaded): the app does not serialise jobs, "one job per machine at a time" holds only by the coordinator's word; job 6 had closed at 01:24:14Z, so its rows are cleannothing of mine to fix; a rule for the job runner
    The make-package gate ran the exporter's side files (block-N.json.node-plan.json) as fixtures and failed; its execute step took the exclusive measure lock for a cycle count and queued 25 min behind a packbench runthe glob skips .node-plan.json; the execute step runs under the run lock (a count, not a time)
    +
    WhatFixed
    Job 1's per-phase command ran with $JOB empty (the bash variables of vars.sh were set, not exported, and the command runs in a child bash): --out /results-A.json, the saved shard proofs in / on the WSL root, so the aggregate-only phases B0, B, C1 and the prototype-shard phase C2 failed in 0.0 s ("No such file")export in vars.sh; job 2 reads the proofs from /
    Job 1's own-miner phases launched the iGPU miner (the first igneum-miner mine process matched; the 5090's is the second) and if (StartMiner ...) was always true (PowerShell: a function's emitted RESULT strings are part of its output), so D and E ran with the 5090 idle and the AMD iGPU at 3.4 MH/s: three more idle replicates of the chain (2.0 to 2.2 s shards, 1.8 and 2.2 s aggregations), no curvethe miner matched on igneum-worker-cuda, the outcome in a script-scope flag, --race off for the own miner (no tuning file on the RTX 5090 Windows rig; a race costs up to 120 s a start)
    Job 1's /api/resume at 21:25:11Z answered ok and the 5090 miner stayed off (card state off, hash 0.0, 1,760 MiB on the card) until the 0.3.10 restart; job 2 waited its full 600 s for a hash rate and ran its mining phases voidthe restore job tools/proving-v1/pc2-agg-cost-restore.ps1 also posts /api/start; the Counter ASIC coordinator opened a task chip for the resume defect
    Jobs 3 and 4 (agg-cost-pc2-3 22:41Z on app 0.3.10, agg-cost-pc2-4 00:18Z on 0.3.11): every /api/state read came back as the two bytes {} (job 4's raw-body print: raw_len=2; the same reads gave the full state on 0.3.9 at 21:01Z and the AMD agent saw the empty reply at 22:22Z), so the card switch found no card, the app's 5090 miner kept mining, and job 3 ran a second miner beside it (two miners at about 60 MH/s each) while job 4's double-mining guard voided its own-miner phases. The class is the app's, not the reader's: state_json() (engine.rs:180) does serde_json::to_value(st).unwrap_or(json!({})), and the value that fails is ProvingState.paid_wei: u128 (serde_json 1.0.151 refuses a u128 over u64::MAX, 18.45 IGN; the proving-v1 agent's diagnosis): a paid shard averages 1.23 IGN, so the reply empties about 15 paid shards after every app start and comes back at the next restart, which matches the times (full at 21:01Z with paid_wei 0, empty from 22:22Z after the prover had paid from 22:02Z). Fixed on the app branch proving-v1 at 6714a45 (paid_wei as a decimal string, the error logged, an {"error":...} reply on any future failure)job 5 reads the card keys from the app's settings.json (cards: key to enabled and identities), restores the 5090's 8 identities first (the restore job of 23:16:53Z had set 2: its parser read the next card's value), refuses before any pause when it cannot name the card, waits on the CUDA worker process count for the card to stop, and checks the worker is back at the end
    Job 5 (agg-cost-pc2-5, 01:10:44Z) failed at PowerShell's parse in 1 s: $RestoreIdentities: inside a double-quoted string (a drive-qualified variable); no card or miner touched${RestoreIdentities}:; the other $name: shapes are inside single-quoted bash here-strings
    Job 6's identities step found settings.json already at 8 identities under the active key nvidia:0:NVIDIA GeForce RTX 5090 (a stale key nvidia:NVIDIA GeForce RTX 5090 carries 2), so no change was sent; job 6's /api/cards with the 5090 disabled answered ok but the worker ran on for 120 s, /api/pause stopped it in 5 s, and at the end /api/resume brought it back in 5 s on 0.3.11the card switch keeps the pause as its fallback; the resume path works on 0.3.11
    the RTX 5090 Windows rig ran three jobs at once from 01:24Z (run-prover-on-pc2-20261006 at 01:24:21Z, the ledger suites build at 01:26:15Z, while agg-cost-pc2-6's closing report was still being uploaded): the app does not serialise jobs, "one job per machine at a time" holds only by the coordinator's word; job 6 had closed at 01:24:14Z, so its rows are cleannothing of mine to fix; a rule for the job runner
    The make-package gate ran the exporter's side files (block-N.json.node-plan.json) as fixtures and failed; its execute step took the exclusive measure lock for a cycle count and queued 25 min behind a packbench runthe glob skips .node-plan.json; the execute step runs under the run lock (a count, not a time)

    6 October 2026, 07:12Z to 07:17Z, the host's chain mode with --save-shards records and --prev, on the Apple M5 Max's CPU

    -

    tools/lock/with-lock.sh run, SP1_PROVER=cpu igneum-prove-host --mode chain --chain proving/fixtures/chain/block-81046.json,block-81047.json --save-shards --out chain-a.json, then --chain block-81048.json --save-shards --prev segment-81047-aggregated.bin --out chain-b.json (the app branch at ce8f34a, Apple M5 Max, CPU prover). The flags the app's segment path needs, before PC 2 (approximate figures: a CPU run, one sample each):

    +

    tools/lock/with-lock.sh run, SP1_PROVER=cpu igneum-prove-host --mode chain --chain proving/fixtures/chain/block-81046.json,block-81047.json --save-shards --out chain-a.json, then --chain block-81048.json --save-shards --prev segment-81047-aggregated.bin --out chain-b.json (the app branch at ce8f34a, Apple M5 Max, CPU prover). The flags the app's segment path needs, before the RTX 5090 Windows rig (approximate figures: a CPU run, one sample each):

    StepValue
    Shard proof, CPU, empty block34.7 s and 36.3 s
    Aggregation, CPU, 1 then 2 deferred proofs39.1 s, 50.8 s
    Chain of 2, end to end160.9 s
    Per-shard records written2 (number, block_hash, shard, statement, proof_sha256, proof_bytes 1,272,897, proof_file, prove_seconds)
    --prev run: base_chain_len, final chain_len2, 3 (the chain continued; a wrong previous proof is refused by number and parent hash)
    -

    6 October 2026, 07:52Z to 08:24Z, the segment-aligned prover beside the miner on PC 2's RTX 5090 (job segments-pc2-pv1c)

    -

    tools/proving-v1/pc2-segments.ps1 (app branch 330207d; the host from the package igneum-prove-wsl2-segal, built on PC 2 in 7 s warm to <server path>, pinned guests unchanged); the app's own prover OFF for the run through /api/prove, ON again at the end; the app's miner running (8 identities, batch-log2 22); SP1_PROVER=cuda, the stock 6.8.1 GPU server; a 1-s nvidia-smi sampler under every chain. Payouts read on node 1 (read-only, igneum_getProofRecords per block at 08:30Z). The miner's rate from the app's uploaded log (status: ... MH/s every 30 s, run win-1ccfe586-20261005-235130).

    +

    6 October 2026, 07:52Z to 08:24Z, the segment-aligned prover beside the miner on the RTX 5090 Windows rig's RTX 5090 (job segments-pc2-pv1c)

    +

    tools/proving-v1/pc2-segments.ps1 (app branch 330207d; the host from the package igneum-prove-wsl2-segal, built on the RTX 5090 Windows rig in 7 s warm to <server path>, pinned guests unchanged); the app's own prover OFF for the run through /api/prove, ON again at the end; the app's miner running (8 identities, batch-log2 22); SP1_PROVER=cuda, the stock 6.8.1 GPU server; a 1-s nvidia-smi sampler under every chain. Payouts read on node 1 (read-only, igneum_getProofRecords per block at 08:30Z). The miner's rate from the app's uploaded log (status: ... MH/s every 30 s, run win-1ccfe586-20261005-235130).

    FigureValueNote
    Segments claimed in 30 min9 (114470, 114654, 114862, 115022, 115198, 115366, 115542, 115710, 115870)one every 210 s; 32.1 min of loop
    Candidates per pass32 to 38 whole segments inside the marginmargin 580 to 589 DAA at claim
    Export (the chain to the segment's last block)99.6 to 100.6 MB in 1.4 to 1.6 sonce per segment
    Cut (8 fixtures, the exporter)45.1 to 46.0 sthe exporter replays from genesis per block; the next lever
    Chain run wall (8 shards, 8 aggregations, one key setup)159.7 to 160.6 shost --mode chain --save-shards
    Shard proofs, 8 per segment63.0 to 63.5 s (7.9 s a shard)empty blocks
    Aggregation, 8 chained80.4 to 81.1 s (10.1 s a block)the fixed cost per block beside the miner
    End to end per segment (export, cut, chain, sign, submit)210.0 to 211.2 s
    GPU memory peak during a chain16,484 to 17,573 MiB (miner resident)the 24 GB tier's gate holds
    GPU utilisation during a chain94.9 to 95.3%
    Shard records accepted72 of 728 per segment
    Shard records paid on chain72 of 720.905 to 2.719 IGN a shard (90% of the credit); carried 180 to 226 blocks after the block
    Segment records accepted0 of 9every one refused: "does not chain to segment N-8..N-1 (chain_len 8), which is pending until DAA ..."
    Miner alone (the app's prover off), 07:25 to 07:51Z117.86 MH/s mean (n=52)min 46.37 is the switch-off dip at 07:22Z
    Miner beside the segment prover, 07:55 to 08:24Z104.90 MH/s mean (n=58, min 98.39, max 119.24)12.96 MH/s = 11.0% of the miner, at 95% GPU utilisation from the prover
    The 0.3.11 prover as shipped beside the miner (5 October row)5.0 MH/s = 4.0%one shard per 46 s; this run proves 8 shards per 210 s, 2.8x the shards
    Node 1's v1 window at 08:24Zpending 59, proven 0, unproven 16, paid segments 0unchanged by the run: the chain rule

    What the refusal is (the fork, igneum/exec/src/proving.rs check_segment_record): a fresh record (chain_len = N) is valid only when the previous segment is UNPROVEN at the carrier, and the record's own deadline is the previous segment's deadline plus one segment length in DAA, so a fresh record is valid for 8 DAA (about 8 s) per segment and must be carried inside them. With one prover every previous segment is pending at proof time. Fixed on the fork branch behind proving_v1_fresh_rule_daa (0f0dda95): from the switch a fresh record is valid whenever the previous segment is not proven; the app holds a refused record and offers it again every pass until the deadline (272b025).

    Run b (segments-pc2-pv1b, 07:20Z to 07:51Z) claimed nothing in 88 passes: the driver's segment keys were doubles against int64 hashtable keys (fixed in 330207d); its 30 minutes are the miner-alone baseline above.

    @@ -788,10 +745,18 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

    The fix (four changes, 5a339733): ingest_certificate ignores an index below keep_from (counted, debug: the echo stops at its source once the seed runs it); the router's overflow policy for IgneumFinality is Drop with a counted warn once per 10 s per peer, never a disconnect; the finality route is subscribed with 4,096 (a checkpoint's worst case is MAX_VOTES_PER_BLOCK 48 votes on each of 30 blocks plus the certificates); the relay flow skips votes while IBD runs (counted, said once per 30 s; certificates still go in and land pending). No consensus change, no digest change. Tests: the overflow-policy table (p2p 33 of 33), the flows crate (19 of 19), a certificate below the window submitted twice (ignored, no gossip, counter 2; an index inside goes the normal way) with the finality tests (12 of 12).

    After, on the fixed binary against the still-unfixed seed (203ae727, same run, 13:15:31 to 13:20:31Z): 63,628 certificates received (the seed's echo had grown to 3,032 per 10 s at the peak as more fleet nodes joined), 0 route errors, 0 drops, 4 connections kept (the seed and three peers learned from it), 168 votes skipped during IBD. The receiver side of the fix holds under a storm five times the morning's; the source side (the guard) cannot show on the seed until 0.3.13 runs there, and the fresh node's own guard never fires during IBD (its window starts at genesis), which is correct. Harness s7 on the fixed binary (--quick --live-only): PASS, 192 blocks accepted in 60 s under a 50 blocks/s flood from one peer, honest template p50/p95/max 0.4/0.6/1.4 ms, rss 306 to 321 MB.

    Per tier: a home miner joining today sees the warning and the peers=0 flicker every checkpoint until the seed runs 0.3.13; a rig the same once; a pool user nothing; a fleet operator gets a node that keeps its only peer, and a seed that stops amplifying old certificates to every peer (13,354 lines of work it did not need in seven minutes). Owed: the fleet agent's synced-node reading; a receiver-side limit on certificates per index per minute as a second belt once the seed is fixed; the formatter's reflow of finality.rs (taken out of the commit).

    -

    6 October 2026, 16:01Z: Ember run 6 on PC 1 (ember-tune-pc1-6, 0.3.13 + kit-6 = 564bdea, elevated, one click)

    +

    6 October 2026, 16:01Z: Ember run 6 on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (ember-tune-pc1-6, 0.3.13 + kit-6 = 564bdea, elevated, one click)

    The helper registered inside the run but on the scratch copy (fixed: task_exe, the reregister verb; see the plan's run 6 notes). RTX 5090: chosen 1854 MHz at 100% = 127.71 MH/s at 226.8 W, 0.563 MH/W, against 127.9 at 311.0 W (0.411) untuned: 84 W saved for 0.15% of rate. Every cap step 60 to 100% read 311 to 313 W (the cap never binds). The clock ladder: 2781 MHz 298.8 W 0.428; 2472 MHz 262.0 W 0.488; 2163 MHz 239.9 W 0.533; 1854 MHz 226.8 W 0.563 (the floor, not the optimum: the next cut's ladder goes to 45%). RTX 4070: caps 100 to 60% all 106.0 W 28.71 MH/s (0.271); 50% 99.1 W 28.70 (0.290); clock 2794 MHz at 50% 99.1 W (0.290); 2484 MHz 81.1 W 28.73 (0.354); further rows and the 9070 XT ladder below once the run closes.

    -

    Run 6 closed 16:39:37Z, exit 0, 2317 s, 19 rows. RTX 4070 chosen 1863 MHz at 50% = 28.78 MH/s at 75.6 W (0.381) against 28.72 at 106.0 W (0.271): 30 W saved for no rate lost; its clock ladder at 50%: 2794 MHz 99.1 W 0.290; 2484 MHz 81.1 W 0.354; 2173 MHz 77.7 W 0.370; 1863 MHz 75.6 W 0.381 (the floor). RX 9070 XT: aborted at step 1, "card reports 0 W, acknowledged true" = the applied rule demanded watts from a card that reports offsets (fixed bd7fcf4); the draw itself was read on every tick (amd_watts_source=engine_telemetry, 363 samples). The helper registered on the scratch copy (fixed 200362a: task_exe, the reregister verb). PC 1 mined through the installed app again by 16:44Z: 170.6 MH/s over the three cards, 0 faults.

    -

    Re-point and proof, 16:48 to 16:53Z: the Power Helper task re-pointed by the helper itself ("1 reregister ok: the task now runs ...Programs\Igneum Miner\igneum-app.exe --power-helper"), then the installed app's caps through the task with no prompt ("-pl 460: set to 460.00 W from 575.00 W", "-pl 160: set to 160.00 W from 100.00 W"). Task Running, Highest, user Admin. Cards: 5090 221 W at 1845 MHz, 4070 75.8 W at 1860 MHz, 9070 XT 202 W, all mining through the installed app. Ember closed 16:53Z.

    +

    Run 6 closed 16:39:37Z, exit 0, 2317 s, 19 rows. RTX 4070 chosen 1863 MHz at 50% = 28.78 MH/s at 75.6 W (0.381) against 28.72 at 106.0 W (0.271): 30 W saved for no rate lost; its clock ladder at 50%: 2794 MHz 99.1 W 0.290; 2484 MHz 81.1 W 0.354; 2173 MHz 77.7 W 0.370; 1863 MHz 75.6 W 0.381 (the floor). RX 9070 XT: aborted at step 1, "card reports 0 W, acknowledged true" = the applied rule demanded watts from a card that reports offsets (fixed bd7fcf4); the draw itself was read on every tick (amd_watts_source=engine_telemetry, 363 samples). The helper registered on the scratch copy (fixed 200362a: task_exe, the reregister verb). the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) mined through the installed app again by 16:44Z: 170.6 MH/s over the three cards, 0 faults.

    +

    Re-point and proof, 16:48 to 16:53Z: the Power Helper task re-pointed by the helper itself ("1 reregister ok: the task now runs ...Programs\Igneum Miner\igneum-app.exe --power-helper"), then the installed app's caps through the task with no prompt ("-pl 460: set to 460.00 W from 575.00 W", "-pl 160: set to 160.00 W from 100.00 W"). Task Running, Highest, user Admin. Cards: 5090 221 W at 1845 MHz, 4070 75.8 W at 1860 MHz, 9070 XT 202 W, all mining through the installed app. Ember closed 16:53Z.

    +

    Prover tiers on real cards: the rented fleet, 6 October 2026 (branch gpu-fleet)

    +

    From 11:50 UTC, Vast.ai containers (nvidia/cuda:12.8.1-devel-ubuntu24.04, the host's driver), one card each, the 0.3.12 Linux node 83089544 on the ten-field override, the 0.3.12 CUDA worker, the patched SP1 server built on each box from proving/prover-floor/sp1-gpu-6.8.1-floor.patch v4 (e81cb0d0...) for the card's own arch, the cuda host with the pinned ids 0x2b1a81cb... and 0x474678f3...; the v1 shard (fees-v1-shards2.json shard 0, 4,717,439 cycles); every proof VERIFIED by the host's own SDK verifier; peak = nvidia-smi memory.used sampled once a second (a per-second loop, not -l 1, which buffers and ignores SIGTERM in a container); own = peak minus the reading before the point; beside = the card's miner running (its resident set is the base). Runner tools/fleet/box-matrix.sh, collector tools/fleet/collect.py, raw logs fleet/<instance>/, the analysis docs/analysis/prover-tiers-real-cards.md.

    +
    CardVRAM GBIdle MiBMinerStock SP1 6.8.1Patched, proves alone (own)Beside the miner (peak)Core-only beside the miner (own)Verdict
    RTX 306012123.78 MH/s at 103.7 W, 1.4 GBrefused: thread 'tokio-rt-worker' (48952) panicked at sp1-gpu/crates/7.4 GB, 14.4 s (alone-comp-26-v1)8.9 GB peak, 37.5 s5.6 GB, 27.2 smines and proves
    RTX 3080101140.82 MH/s at 204.9 W, 1.5 GBrefused: thread 'tokio-rt-worker' (49593) panicked at sp1-gpu/crates/8.0 GB, 7.1 s (alone-comp-26-v1)9.2 GB peak, 25.6 s5.9 GB, 19.2 smines and proves
    RTX 309024137.79 MH/s at 228.8 W, 1.5 GBnot measured: the SDK's server download stalled (killed at 553 s)7.7 GB, 14.9 s (alone-comp-26-v1)9.3 GB peak, 19.9 s5.8 GB, 13.3 smines and proves
    RTX 4060 Ti 16 GB16017.58 MH/s at 72.3 W, 1.4 GBrefused: thread 'tokio-rt-worker' (49293) panicked at sp1-gpu/crates/7.8 GB, 11.6 s (alone-comp-26-v1)9.0 GB peak, 34.6 s5.8 GB, 25.9 smines and proves
    RTX 4060 Ti 8 GB8019.07 MH/s at 72.6 W, 1.4 GBrefused: thread 'tokio-rt-worker' (43763) panicked at sp1-gpu/crates/7.6 GB, 9.6 s (alone-comp-26-v1)no GB peak, s5.8 GB, 26.3 smines and proves core-only
    RTX 40608217.07 MH/s at 0.0 W, 1.4 GBrefused: thread 'tokio-rt-worker' (48510) panicked at sp1-gpu/crates/7.4 GB, 18.4 s (alone-comp-26-v1)no GB peak, s5.6 GB, 22.1 smines and proves core-only
    RTX 407012924.99 MH/s at 91.1 W, 1.4 GBrefused: thread 'tokio-rt-worker' (47475) panicked at sp1-gpu/crates/7.6 GB, 12.1 s (alone-comp-26-v1)10.1 GB peak, 27.3 s5.6 GB, 14.3 smines and proves
    RTX 409024152.25 MH/s at 183.1 W, 1.7 GBproved 5.6 s at 17.4 GB7.9 GB, 6.3 s (alone-comp-26-v1)10.7 GB peak, 26.1 s6.1 GB, 10.6 smines and proves
    RTX 507012241.89 MH/s at 137.0 W, 2.7 GBrefused: thread 'tokio-rt-worker' (53680) panicked at sp1-gpu/crates/7.6 GB, 4.8 s (alone-comp-26-v1)10.2 GB peak, 37.2 s5.8 GB, 19.8 smines and proves
    RTX 509032298.48 MH/s at 258.2 W, 1.8 GBproved 8.4 s at 18.3 GB8.0 GB, 6.3 s (alone-comp-26-v1)9.9 GB peak, 10.7 s6.3 GB, 7.4 smines and proves
    RTX A500024147.7 MH/s at 222.7 W, 1.5 GBproved 6.4 s at 17.2 GB7.7 GB, 8.3 s (alone-comp-26-v1)10.5 GB peak, 34.6 s6.0 GB, 18.2 smines and proves
    +

    Also measured: the stock SP1 6.8.1 server refuses every card under 24 GB at builder.rs:38 and proves the v1 shard on the 4090 (5.6 s, 17.4 GB), the A5000 (6.4 s, 17.2 GB) and the 5090 (8.4 s, 18.3 GB); 2^27 does not fit a 10 or 8 GB card and the v4 server hangs at the card's limit (568 and 904 s until killed) where v5 aborts in 13 s ("FLOOR abort: a device allocation failed at slop/crates/tensor/src/inner.rs:51 ... AllocError { size: 486586112 }", exit 70; the known-failed case of the prover-floor gate, on the 3080); the miner beside a prover costs 1.7x (5090) to 7.7x (5070) on the proof's time and 5 to 20% of the miner's rate; the empty-shard fixture (block-72854, a first block with a genesis witness) proves slower than the v1 shard on every card (24 to 55 s) and is not an empty live shard; Ember's two knobs are refused in the containers, so the ladders are baseline rows (docs/plans/ember-tune.md, fleet priors).

    +

    Rental cost of hash, 6 October 2026 (branch gpu-fleet): what a GH/s costs by the hour against the devnet

    +

    Measured on the rented fleet (RunPod community pods, list prices, 18:45Z): 38 wave pods (4090, A4000, L4, 3090, 3070, 4070 Ti, A5000, 4000 Ada) ran 1,748 MH/s inside jobs (median pod 28 MH/s) for USD 20.44 an hour, USD 0.0117 per MH/s-hour; the 8x 4090 rig 459 MH/s at 1,636 W for USD 5.92 an hour, USD 0.0129 per MH/s-hour; a single 5090 pod 98 to 128 MH/s for USD 0.41 to 0.74 an hour. The live devnet's difficulty read 1,156,040,186 at 1 block a second at 19:00Z, so the whole network was about 1.16 GH/s, and the rented fleet was most of it. The live litepaper's line ("2 GH/s for USD 13/h vs 280 MH/s devnet") is corrected to: 1.75 GH/s for USD 20 an hour on community pods, against a devnet of 1.16 GH/s.

    +
    BuyerWhat USD 20/h buysAgainst the devnet (1.16 GH/s)Against mainnet scale
    Home miner, 8 to 12 GB card (11 to 28 MH/s)nothing: the card is owned, 0.15 to 0.2 kWone card is 1 to 2 percent of the devnetone card is noise at a TH/s
    Rig, 8x 4090 (459 MH/s, USD 5.92/h rented)1.7 rigsone rig is 40 percent of the devnetone rig is 0.05 percent of a TH/s
    Renter at RunPod list prices1.75 GH/s while cards exist150 percent of the devnet: overtaken for USD 15/ha TH/s costs USD 11,700 an hour and the market cannot supply it: asked for 20 pods of any of 8 card types at 18:59Z to 19:15Z, RunPod gave 0 ("no instances currently available")
    +

    Consequence: the devnet's hash is rentable for the price of a dinner, so nothing on it is a security result; the counter-ASIC and finality work is tested there for correctness, not for cost. The cost argument only starts at the TH/s scale, where the rental market's supply (not its price) is the limit, and that number belongs in the litepaper with this caveat.

    Generated from the repository at build time. Times are UTC. Machine names are model names.

    @@ -800,7 +765,7 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -836,10 +801,23 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + \ No newline at end of file diff --git a/site/block.html b/site/block.html index 2eab39af9..a786a3eb5 100644 --- a/site/block.html +++ b/site/block.html @@ -29,9 +29,10 @@ + + @@ -168,10 +99,9 @@ main{padding-bottom:var(--sec)} @@ -223,7 +165,7 @@ main{padding-bottom:var(--sec)}
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -259,10 +201,23 @@ main{padding-bottom:var(--sec)}
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + @@ -144,10 +88,9 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin @@ -191,27 +146,27 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin
    - + - - + + - + - + - + @@ -220,7 +175,7 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin - +
    #ClaimStatusVersion or commitReproducible testResult, date, machineIndependent verification
    1A new mining program every hour, compiled by the miner, with no human in the loop and no pause in mining
    Homepage hero and "This hour's program"; litepaper Mining
    tested by the teamigneum-pow 0.2.0; repo b27da39, 1292110, 100c5d7; fork devnet-v4 6457ca95The live devnet v4: the node announces next_epoch_seed 150 DAA past the seed score, igneum-miner sends prepare to its worker, the worker builds the next program while the current one mines; Metal (proto-metal/igneum-bench), CUDA and OpenCL workers; bench-log "first hourly program swap on the live devnet"Epoch boundary at DAA 3,600 (10:05:07 UTC, 4 October 2026) crossed live on three vendors: the Apple M5 Max M5 Max (Metal) compiled the next program in 82 ms, 449 DAA before the boundary, swapped in 0.01 ms, 26.7 MH/s before and after; the RTX 5090 compiled in 1,285 ms, swapped in 0.00 ms, 121.8 before and 123.4 MH/s after; the integrated AMD chip 2.74 MH/s before and after. 0 restarts, 0 rejected blocks, 0 rebuilds. The epoch seed is the epoch block hash; the delay of row 2 is not wired in. At a later boundary (DAA 18,000) one OpenCL worker on PC 2 stayed on the previous epoch after an app reinstall and answered 514 jobs with a seed mismatch; fixed in the miner (3bfe346f, workers emit a need line), the swap time of that forced prepare not measurednone yet
    1A new mining program every hour, compiled by the miner, with no human in the loop and no pause in mining
    Homepage hero and "This hour's program"; litepaper Mining
    tested by the teamigneum-pow 0.2.0; repo b27da39, 1292110, 100c5d7; fork devnet-v4 6457ca95The live devnet v4: the node announces next_epoch_seed 150 DAA past the seed score, igneum-miner sends prepare to its worker, the worker builds the next program while the current one mines; Metal (proto-metal/igneum-bench), CUDA and OpenCL workers; bench-log "first hourly program swap on the live devnet"Epoch boundary at DAA 3,600 (10:05:07 UTC, 4 October 2026) crossed live on three vendors: the Apple M5 Max M5 Max (Metal) compiled the next program in 82 ms, 449 DAA before the boundary, swapped in 0.01 ms, 26.7 MH/s before and after; the RTX 5090 compiled in 1,285 ms, swapped in 0.00 ms, 121.8 before and 123.4 MH/s after; the integrated AMD chip 2.74 MH/s before and after. 0 restarts, 0 rejected blocks, 0 rebuilds. The epoch seed is the epoch block hash; the delay of row 2 is not wired in. At a later boundary (DAA 18,000) one OpenCL worker on the RTX 5090 Windows rig stayed on the previous epoch after an app reinstall and answered 514 jobs with a seed mismatch; fixed in the miner (3bfe346f, workers emit a need line), the swap time of that forced prepare not measurednone yet
    2The program seed passes through a 10-minute verifiable delay from a certified checkpoint, so nobody can grind the seed
    Litepaper Mining, vs RandomX ("Closed by a verifiable delay")
    implementedrepo 792776e; proto-vdf/proto-vdf full 10-minute runs and the tamper cases in proto-vdf/README.md; bench-log "proto-vdf"Class group 1024-bit: 163,000 squarings per second, 10-min eval 585.4 s, prove 9.1 s on 12 threads, verify 4.47 ms, 516-byte proof; wrong checkpoint, flipped seed bit and T+1 all rejected; grinding model gains 0 blocks per epoch with the delay against +3.62 at a 30% advantage without it. 3 October 2026, Apple M5 Max, one core. Prototype only: not in the node on 4 October either, not reviewed against chiavdf (O-4.1)none yet
    3The dataset is memory-hard: computing an item costs more than loading it, and every hash does 128 distinct dataset reads
    Litepaper Mining and vs RandomX; homepage vs RandomX ("Memory 2 GB, growing")
    tested by the teamrepo 58a5a63 (memory-hard), b27da39 (generator 2); igneum-pow 0.2.0 (memhard.rs, generator.rs, accept.rs); spec 01 sections 1.4.2 to 1.4.6; proto-metal/MEMHARD.mdproto-metal/igneum-bench --inline-dataset against the honest run at 1 GiB and 256 MiB; igneum-census --gen v2 --warps 64 over 20,000 programs; bench-log "memory-hard dataset" and "generator version 2 adopted"Honest 45.2 Mhash/s, inline (never reads the dataset) 9.49 Mhash/s, ratio 0.21 at 1 GiB, 0.10 at 256 MiB. 3 October 2026, Apple M5 Max. Generator 2, 4 October 2026: 20,000 programs, 128 static loads on every program, distinct addresses per hash mean 127.9, minimum 120.1; 5.2% of candidates rejected by the acceptance rule. The price of the 128 fresh reads is the hash rate: Apple OpenCL 45.0 MH/s on a version 1 program with 80 distinct loads against 27.5 to 27.9 on version 2; the RTX 5090 229 MH/s on a 104-load version 1 program at 1 GiB (3 October) against 121.8 to 124.2 MH/s mining version 2 on the live devnet (4 October). Apple only for the shortcut ratio (O-1.5); the on-die cache question of ledger M16 is unchangednone yet
    4The same program produces identical hashes on three GPU vendors, cache and dataset included
    Litepaper vs RandomX ("Bit-exact on Apple, NVIDIA and AMD, measured"), For miners; homepage
    tested by the teamrepo f2e903e, 0f1fdaf (version 1 packs), b27da39 (version 2 packs igneum-genesis-mh, igneum-devnet-v4-epoch0); igneum-pow 0.2.0The 96 test vectors of a pack through proto-metal/igneum-bench, proto-cuda/host.cu, proto-opencl/host.c; batch fingerprint at --batch-log2 24; the miner's CPU re-check of every share a GPU worker finds on the devnet; bench-log entries "RTX 5090, memory-hard dataset", "AMD gfx1036", "RTX 5090 through NVIDIA OpenCL", "generator version 2 adopted", "the gfx1036 worker fault"Version 1: 96/96 on Apple Metal (M5 Max), NVIDIA CUDA and NVIDIA OpenCL (RTX 5090, Windows), AMD OpenCL (Ryzen 7 9800X3D integrated gfx1036, 1 compute unit), Apple OpenCL, pocl and two CPU references; batch fingerprint 98af644e993239e2 over 16.7 million nonces identical on the AMD chip and the 5090, 3 October 2026. Version 2: 96/96 on Apple Metal, Apple OpenCL and the CUDA and OpenCL emulators with identical fingerprints; on real NVIDIA and AMD silicon the version 2 vectors have not run as a pack, but both mined accepted blocks on the live devnet with the CPU re-check clean on every share (RTX 5090 at 124.2 MH/s, gfx1036 at 3.3 MH/s), 4 October 2026. The AMD device is an integrated chip; no discrete AMD card and no Intel card has run anything (O-1.15)none yet
    5A CPU verifies one hash in under 10 ms by simulating one warp
    Litepaper Mining ("about ten milliseconds"), vs RandomX; roadmap gate 2
    tested by the teamrepo 75cac18, b27da39; igneum-pow 0.2.0 (verify.rs)cargo test and the crate bench in igneum-pow/; bench-log "igneum-pow: Rust crate bit-exact with proto-metal" and "generator version 2 adopted"0.411 to 0.579 ms per 32-lane warp steady, 0.41 to 0.87 ms cold, average of 20, 1 GiB dataset, cache held, one M5 Max performance core, 3 October 2026; version 2 units 0.631 ms (average of 20), cold 0.67 to 0.81 ms, 4 October 2026. Gate margin about 16x on this core. Not measured on a 2019-class laptop core (O-1.14)none yet
    6The hash is bound to the header: one nonce serves one header, and a wrong nonce is rejected
    Spec 1.6; litepaper Mining (implied by "checks a hash")
    tested by the teamrepo 33f7b33, 9812466, b27da39; igneum-pow 0.2.0 (bind.rs, bound vectors re-cut for version 2, 39 crate tests)igneum-miner bad-nonce against a devnet node; igneum-pow hash-bound for the 96-nonce job across the 2^32 lane boundary; bench-log "first devnet blocks on the real lottery hash" and "generator version 2 adopted"833 blocks accepted by igneum-lottery-v1-bound on 3 nodes, 0 rejections; bad-nonce gave Reject(BlockInvalid); Metal, OpenCL and CUDA (emulated) workers bit-exact with the crate on the lane-boundary job, 3 October 2026, Apple M5 Max. Version 2: the node's engine reports igneum-lottery-v2-bound, 39 of 39 crate tests, and the live devnet v4 accepts its blocks under it, 4 October 2026none yet
    7The devnet runs at one block a second
    Homepage stats ("1 / s"); litepaper Speed; roadmap phase 3
    tested by the teamrepo 9812466, e9328c6, 8dae48b; fork devnet-v4 dc749905The merged node's 3-node test network (igneum-devnet-880, 960 s); the live devnet v4 record sim/difficulty/records/live-2026-10-04.csv; the 12-node cloud network's arrival logs; bench-log "devnet-v4 integration", "difficulty rule v2", "first devnet blocks"Merged node, 4 October 2026, Apple M5 Max: 1,055 blocks in 960 s, 1.03 blocks/s, sink identical on 3 nodes at 31 of 31 samples, 0 rejected. Live devnet v4 the same day: 49 to 81 blocks a minute while two RTX 5090s joined and left (row 12), 1.1 to 1.2 blocks/s in the oscillating window, then within 1.3% per minute with one PC and the Apple M5 Max. The 12-node cloud network at one block a second: 644 blocks in a 10-minute window. The 3 October CPU devnet: 1.29 blocks/s over 641 s, 1.03 after the first retarget. The phase 3 gate also asks for proofs under 60 s behind the tip; no proof is on the chain (row 15)none yet
    8Blocks are mined by GPUs on Apple and NVIDIA
    Homepage live strip; journey phase 3 ("GPU miners on three vendors")
    tested by the teamrepo 9812466, e9328c6, d7e1f89, 2309c8d; fork devnet-v4Metal worker proto-metal/igneum-bench --serve driven by igneum-miner --worker; the live devnet v4 hash-rate record sim/difficulty/records/live-2026-10-04-hashrate.csv (587 worker STATUS lines by run id); bench-log "first devnet blocks", "devnet v4 cut-over", "difficulty rule v2", "first machine on the Igneum Miner app"Metal: 506 jobs, 5,636 blocks found and accepted, 0 rejected, 0 CPU/GPU mismatches, 28.2 MH/s wall, 3 October 2026. Live devnet v4, 4 October 2026: PC 1's RTX 5090 at 122 MH/s with 8 identities, PC 2's at 124 MH/s with 8 identities (117 to 119 MH/s inside the one-click app, 34 accepted blocks in its first minute, CPU re-check OK on every share), the Apple M5 Max's Metal worker at 26.7 MH/s; 17 vote keys signed the first finality lock (row 10); from the afternoon an Apple silicon laptop outside the project at 21.0 MH/s through the app (row 30). Two RTX 5090s and two Apple chips; no other NVIDIA model has minednone yet
    9Blocks are mined by a GPU on AMD
    Journey phase 3 ("three vendors")
    tested by the teamrepo 2c4b30f (generic OpenCL worker, --pack), 112acf6 (fault guards); bound kernel kernel_bound.cl in the packigneum-worker-opencl.exe --pack on PC 2's integrated Radeon against the live devnet v4 through the Windows package; bench-log "the gfx1036 worker fault", "first hourly program swap", "first machine on the Igneum Miner app"PC 2's integrated gfx1036 (1 compute unit) mined on the live devnet on 4 October 2026: 8 accepted blocks at 3.3 MH/s over 577 s with the CPU re-check clean, and 2.74 MH/s through the hourly program swap with 0 rejected. At about 600 s the AMD runtime began answering every call with success while running nothing (906 jobs became 56,384 in 30 s, 4.3 GH/s of phantom work); not reproduced on Apple OpenCL in 4,565 jobs with 0 leaked objects; the worker and miner now refuse a job 20x faster than the mean or an unchanged output buffer and restart (112acf6), and the next gfx1036 run names the guard that fires. One integrated chip; no discrete AMD card has run anythingnone yet
    8Blocks are mined by GPUs on Apple and NVIDIA
    Homepage live strip; journey phase 3 ("GPU miners on three vendors")
    tested by the teamrepo 9812466, e9328c6, d7e1f89, 2309c8d; fork devnet-v4Metal worker proto-metal/igneum-bench --serve driven by igneum-miner --worker; the live devnet v4 hash-rate record sim/difficulty/records/live-2026-10-04-hashrate.csv (587 worker STATUS lines by run id); bench-log "first devnet blocks", "devnet v4 cut-over", "difficulty rule v2", "first machine on the Igneum Miner app"Metal: 506 jobs, 5,636 blocks found and accepted, 0 rejected, 0 CPU/GPU mismatches, 28.2 MH/s wall, 3 October 2026. Live devnet v4, 4 October 2026: the three-card Windows rig's RTX 5090 at 122 MH/s with 8 identities, the RTX 5090 Windows rig's at 124 MH/s with 8 identities (117 to 119 MH/s inside the one-click app, 34 accepted blocks in its first minute, CPU re-check OK on every share), the Apple M5 Max's Metal worker at 26.7 MH/s; 17 vote keys signed the first finality lock (row 10); from the afternoon an Apple silicon laptop outside the project at 21.0 MH/s through the app (row 30). Two RTX 5090s and two Apple chips; no other NVIDIA model has minednone yet
    9Blocks are mined by a GPU on AMD
    Journey phase 3 ("three vendors")
    tested by the teamrepo 2c4b30f (generic OpenCL worker, --pack), 112acf6 (fault guards); bound kernel kernel_bound.cl in the packigneum-worker-opencl.exe --pack on the RTX 5090 Windows rig's integrated Radeon against the live devnet v4 through the Windows package; bench-log "the gfx1036 worker fault", "first hourly program swap", "first machine on the Igneum Miner app"the RTX 5090 Windows rig's integrated gfx1036 (1 compute unit) mined on the live devnet on 4 October 2026: 8 accepted blocks at 3.3 MH/s over 577 s with the CPU re-check clean, and 2.74 MH/s through the hourly program swap with 0 rejected. At about 600 s the AMD runtime began answering every call with success while running nothing (906 jobs became 56,384 in 30 s, 4.3 GH/s of phantom work); not reproduced on Apple OpenCL in 4,565 jobs with 0 leaked objects; the worker and miner now refuse a job 20x faster than the mean or an unchanged output buffer and restart (112acf6), and the next gfx1036 run names the guard that fires. One integrated chip; no discrete AMD card has run anythingnone yet
    10Checkpoints lock every 30 s of chain at two thirds of all 30-day weight, and the floor stops conflicting locks in partitions and eclipses for as long as neither side's own new blocks carry it past two thirds of its window (about 10 days of a 30-day window at a 50/50 split)
    Litepaper Finality, "What Igneum does not claim"; homepage "locked every 30 seconds"
    tested by the teamrepo a3a9833 (2/3 floor, O-3.15), bbb264a (simulation), c16ccf1; fork devnet-v4 6457ca95 (FLOOR_NUM / FLOOR_DEN 2/3), da1eb889 (F17 by-weight sortition, F1 first-month gate min_daa = window); spec 3.3, 3.3.1, 3.7, 3.9The live devnet v4 (getFinalityCheckpoints, tools/observer/observer.mjs, /api/checkpoint); sim/finality_v2.py --floor 1.0, scenarios A to L; the three-node, six-voter partition runs igneum-devnet-921 to -923; tools/finality-attacks scenarios 1 to 6 and 8; bench-log "first finality lock on the live devnet", "finality floor 2/3", "finality v2 attack harness", "finality fixes F17 and F1"Live: the first lock on the live devnet was checkpoint 242 at 11:03:44 UTC on 4 October 2026, two hours after genesis (the window and min_daa are 7,200 DAA), with 77.4% of all weight and of active weight signed by 12 aggregated votes from 17 vote keys; observer.mjs saw it 0.7 s after the miner's own lock line. By 13:21 UTC the observer held 280 certificates, indices 241 to 522 (DAA 7,229 to 17,982), 17 to 27 voters, no index with two hashes. Test networks, 4 October 2026, Apple M5 Max: a 4/2 split locked on the 4 side (67.9%) 2 to 8 s after the cut and never on the 2 side, 0 conflicts; a 3/3 split locked on neither side for 150 s with 0 conflicts, where the 3 October floor (56.7%) would have locked both sides at 76 and 106 s; the rule guarantees one lock history for partitions shorter than the window bound W / (3R) (200 s on that test network's 1,800-DAA window, about 40 minutes on the devnet, about 10 days at the 30-day mainnet window); beyond that bound each side can reach two thirds of its own window, so the next finality rule freezes the weight table at the last certified checkpoint and pauses instead. Simulator with the 2/3 floor: 0 conflicts up to a 33% equivocator (34% splits a 50/50 partition), silent weight pauses locks from 34%, a 50/50 partition locks alone from day 10.1. Harness: equivocating keys stripped on every node, Sybil dust at zero weight, a pulsed miner's weight equal to its block share (ratio 0.96 to 1.0), the first-month gate stops a young window locking under one key. Not demonstrated: certificate injection on the wire, an eclipse with a private fork, the 2-hour presence window at mainnet lengthnone yet
    11Hashrate that arrived today has almost no vote: ten days of the whole network's hashrate to reach a third of the weight, twenty for two thirds; 51% never reaches two thirds while honest miners stay
    Litepaper Finality; homepage firsts
    tested by the teamrepo bbb264a; sim/finality_v2.pyScenario B of sim/finality_v2.py, seeds 7 and 11share(t) = (t/30) x a/(1+a) holds to 0.04 points; a renter equal to the whole honest network (a = 1) crosses 1/3 on day 20 and never reaches 2/3; a = 9 crosses 1/3 on day 11.1 and 2/3 on day 22.2. The ten-day figure is a = infinity, honest miners gone. 3 October 2026, Apple M5 Max. A model with 1,000 Pareto keys and no DAG; the live devnet's window is two hours old, so the claim has no live measurement yetnone yet
    12The difficulty rule recovers from a hashrate step within minutes, where Kaspa's sampled rule never settles. A step inside an epoch set the rule oscillating on the live devnet on 4 October 2026; rule v2 removes it in the simulator and on a test network and is built but not yet rolled out
    Spec 2.3; litepaper Speed (implied); bench page
    tested by the teamrepo e9328c6, abb5a5d (attacks), 67bf226 (rule v2); fork difficulty branch (timestamp fix) and devnet-v4 a21ff239 (difficulty_v2_activation_daa, REF_WINDOW_V2 = 600); sim/difficulty/sim.py --liveThe live record sim/difficulty/records/live-2026-10-04.csv (8,090 headers, pull_live.py) and the hash-rate record beside it; sim/difficulty/sim.py on the synthetic set and the DAG replay; sim/difficulty/attacks/attacks.py; sim/difficulty/testnet_v2.py (3 nodes, activation at DAA 900); cargo test --release -p kaspa-consensus --lib difficulty (15 pass); bench-log "difficulty controller", "difficulty rule under attack", "timestamp attack fixed", "difficulty rule v2"Live devnet v4, 4 October 2026 (UTC): a second RTX 5090 joining 7 minutes into an epoch (about 152 to 280 MH/s) hardened the difficulty 70M to 144M in 90 s and then swung by about a third for 40 minutes around the true level of 139M while the epoch-long reference lane carried the join; that card leaving for 4 minutes eased 116M to 67M and back to 106M; the epoch boundary with both PCs restarting took 152M to 77M in 3 minutes, after which the rule held within 1.3% per minute with no flips. Cause: the reference lane covered the whole epoch, so a mid-epoch step polluted it for the hour and the 25% trigger flipped on the short lane's noise. The DAG replay reproduces the record (std of log difficulty 0.115 against 0.134, 4.3 peaks against 4). Rule v2 (reference window 600 DAA) on the replay: std 0.026, 0 flips, mean 142.6M against 139M true; on a 3-node test network the v2 nodes eased a leave with no peak and held a rejoin within 3% after 60 s, and a node without the activation height forked off at it as designed. Rule v2 rolled onto the 12-node cloud network on 4 October (all nodes crossed the height on one chain; a hash-rate step then settled in 160 to 270 s with no swing) and activates on the devnet at DAA 33,000 the same evening. Timestamp forging (ledger M23) fixed the same day: a 50% forger drifts the rate under 1.1% where the 3 October rule gave it a 9.9x difficulty. Simulator, settled seconds: x50 step 62 to 66 (Kaspa 1,542), /50 step 657 to 753 (Kaspa 12,296). Apple M5 Max under load 7 to 442; the DAG model is fitted on one scale; the pool hopper's 0.7-point excess over Kaspa's rule stays opennone yet
    13Every node executes the ordered transactions natively and reaches the same state root
    Litepaper Proving ("Every node executes ... natively"), Building ("runs on Igneum unchanged")
    tested by the teamrepo f5f8c80, 8dae48b; fork devnet-v4 dc749905; revm 43.0.3node tools/evm-smoke/smoke.mjs against a 3-node igneumd; igneum-exec-diff seq.json; bench-log "execution layer devnet v3" and "devnet-v4 integration"Simnet, 3 October 2026: 87 of 87 viem checks, state roots identical on 3 nodes at four heights, 57 executed and 19 skipped transactions agree with plain revm, 0 mismatches. Merged node on real proof of work, 4 October 2026: 84 of 85 checks (the miss needs parallel blocks the network did not produce in 36 s), 59 transfers in 10 chain blocks, state roots identical on 3 nodes, igneum-exec-diff 0 mismatches over 59 transactions; the live devnet v4 runs this execution layer. Apple M5 Max. The prover is a stub; state is rebuilt from genesis at start; no EVM transaction relay between nodesnone yet
    14Ethereum bytecode runs unchanged, with the documented differences of spec 7.1
    Homepage Build card; litepaper Building
    tested by the teamas 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 nodenone yet
    15Every 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
    implementedrepo 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.6proving/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 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 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 onenone yet
    15Every 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
    implementedrepo 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.6proving/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 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 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 onenone yet
    16A 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
    designedspec 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 cardnone yet
    17The chip resistance claim: the strongest recompute chip under 1x per chip against an RTX 5090; the stored-dataset chip 1.2x per chip and 5x to 9x per joule in the model (2.1x to 4.8x by the Ethash precedent); the latency-shadow lever, measured and in its gates, brings it to about 2x
    Homepage hero and litepaper abstract (draft (a) of docs/plans/counter-asic-3-status.md section 6, chosen 6 October 2026), litepaper "What Igneum does not claim"
    tested by the team (the model), designed (the target)program class v3 (Counter ASIC 2.0, 5 October 2026): branches ca2-v3 d233fa1 and after, ca2-mixer 1ab8b21, ca2-era 78c0ee4; docs/analysis/chip-model-v3.md, docs/analysis/sram-mirror.md, docs/analysis/scratch-soundness.mdThe m16 recompute model re-run on the measured v3 rates and verifier times; the on-die-cache chip rowThe on-die-cache recompute chip against the RTX 5090's measured 136.1 MH/s: class v2 2.4x; class v3 (mixer x8) 0.31x bare, 0.92x with a 3x fixed-function allowance (approximate), 0.76x at equal silicon; margin 8% on the allowance, 9% on the budget. 5 October 2026, M5 Max, RTX 5090, RX 9070 XT. The 2x target is a target: no chip has been built; the bounty stands (O-1.17)none yet
    18The 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 teamreadwidth 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 loadLatency-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 2026none yet
    19The 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 teamca2-mixer 1ab8b21 (tests/mixer.rs, tests/scratch.rs), ca2-era 78c0ee4, ca2-soundness a465881 (docs/analysis/scratch-soundness.md), igneum-pow/tests/packs.rsThe 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 cardClass 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
    19The 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 teamca2-mixer 1ab8b21 (tests/mixer.rs, tests/scratch.rs), ca2-era 78c0ee4, ca2-soundness a465881 (docs/analysis/scratch-soundness.md), igneum-pow/tests/packs.rsThe 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 cardClass 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)none yet
    20No 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
    implementedrepo 6ac80a3; fork "igneum-node devnet v0"; consensus/core/src/igneum.rs, coinbase.rscargo 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 happenednone yet
    21The proving pool's 20% reaches shard provers and aggregators
    Litepaper Economics; homepage "20% provers"
    tested by the teamspec 5.3; proving/igneum-prove carries the prover's payout address in every shard proof (ledger P12)None. The pool output exists (row 20); the payout from it against proof records is unwritten. Since 5 October 2026: the payout rule is live on the devnet (proving.rs shard_payouts, the carrying segment pays the first valid record per shard its part of the segment's pool credit)The escrow accumulated on the simnet (92.55 IGN at the end of the v3 run) and nothing can draw it. Rule decided: per block, divided among shards by consensus proving cost, sortition to 8 provers for 10 s then open (spec 7.2). The economy model of 4 October 2026 (sim/economy, 1,000 operators, 30 days) kept every block proven within 60 s under six stress scenarios; a model, not hardware Live devnet, 5 October 2026: 388 shards paid by 16:02 UTC, 446.13 IGN from the pool to PC 2's payout address, 0.8813 IGN per mergeset block of the proven segment (bench-log entries of 5 October: "the first shards proven, verified and paid" and "real transactions, the first non-empty shard proven and paid")none yet
    21The proving pool's 20% reaches shard provers and aggregators
    Litepaper Economics; homepage "20% provers"
    tested by the teamspec 5.3; proving/igneum-prove carries the prover's payout address in every shard proof (ledger P12)None. The pool output exists (row 20); the payout from it against proof records is unwritten. Since 5 October 2026: the payout rule is live on the devnet (proving.rs shard_payouts, the carrying segment pays the first valid record per shard its part of the segment's pool credit)The escrow accumulated on the simnet (92.55 IGN at the end of the v3 run) and nothing can draw it. Rule decided: per block, divided among shards by consensus proving cost, sortition to 8 provers for 10 s then open (spec 7.2). The economy model of 4 October 2026 (sim/economy, 1,000 operators, 30 days) kept every block proven within 60 s under six stress scenarios; a model, not hardware Live devnet, 5 October 2026: 388 shards paid by 16:02 UTC, 446.13 IGN from the pool to the RTX 5090 Windows rig's payout address, 0.8813 IGN per mergeset block of the proven segment (bench-log entries of 5 October: "the first shards proven, verified and paid" and "real transactions, the first non-empty shard proven and paid")none yet
    22The base fee is burned in full and the priority fee splits 80% to the miner and provers, 20% to the apps whose code ran
    Homepage Economics caption and Build card; litepaper "Where fees go"
    tested by the teamrepo f5f8c80; fork worktree vendor/igneum-node-exectools/evm-smoke/smoke.mjs receipt checks; bench-log "execution layer devnet v3"Transfer receipt: burnedProvingFee 200 gwei, minerTip 16,800 gwei (80%), unregistered developer share 4,200 gwei burned; contract call: 80% to the miner, 20% credited to the payee the constructor registered, balance delta equal. 3 October 2026, Apple M5 Max simnet. The provers' part of the 80% is not split out (no provers exist); the base fee stayed at the 1 gwei floor throughoutnone yet
    23No fee to any team, foundation or fund; 0 admin keys in consensus
    Homepage Economics tiles and caption; litepaper "No fund, no foundation" and Governance
    designedspec 5.5, 5.6 (decided 3 October 2026); spec 08Reading: no coinbase output, fee route or consensus key in the fork names any party (coinbase.rs, docs/fork-divergence.md)The emission code has two outputs (row 20) and the fee code has three routes (row 22), none to a team. The 1% fee of the official client is a client setting, not a protocol rule, and is not implemented. The release key of spec 08 signs client updates (the Igneum Miner app's over-the-air manifest since 4 October 2026, Ed25519) and holds no consensus power; its custody policy is open (O-8.1)none yet
    24External proving jobs pay 90% to the provers who delivered and burn 10%, once settled in IGN
    Homepage "IGN burned from jobs, phase two"; litepaper Proving and Economics
    designedspec 5.4None. Needs the proof bridge (spec 7.3, phase two) and the settlement switch (O-5.2)At launch jobs are paid on the customer's chain in the customer's currency and nothing is burned (ledger P10). No job market code existsnone yet
    27The node survives malformed input, floods, withholding, partitions and eclipses
    Litepaper Speed ("GHOSTDAG, the BlockDAG consensus proven on Kaspa"); spec 2
    tested by the teamrepo 394030c, 8dae48b, 6b5bd92; fork worktree vendor/igneum-node-harness and devnet-v4; tools/harness/; infra/cloud-devnet/experiments/partition.shtools/harness/ against a private igneumd test network; the merged node's harness scenarios 2 and 5; the cloud network's 10-minute partition of Singapore (results/2026-10-04/partition-sin-20261004-110906/partition.md); bench-log "consensus attack harness", "devnet-v4 integration"3 October 2026, Apple M5 Max: 63 malformed cases, node up on every one; withholding at 10% to 45% within 2 sigma of share; partitions of 120 s to 3,700 s healed to one chain in 10 s; eclipse victims rejoined in 10 s; 50x floods left template p95 under 4 ms; one FAIL, a 45% withholder releasing every 20 blocks took 50.7% of blues (bound 47.4%). Merged node, 4 October 2026: 63 cases, node up, 0 cache builds; the 10 s timestamp floor and future bound exact. Cloud network, 4 October 2026: 12 nodes in five locations on their own chain, Singapore cut off by iptables for 10 minutes; the two minority nodes adopted the majority chain 10 and 14 s after the heal with reorgs of 445 and 516 blocks, the majority's deepest reorg was 2 blocks, 0 conflicting locks (none were possible: the weight window stood at DAA 3,030 of 7,200). CPU miners only; the finality rules under partition are row 10none yet
    28Headers are validated cheaply before the lottery engine runs, so forged timestamps cannot force 256 MiB cache builds
    Spec 2.4; ledger M15
    tested by the teamrepo 0953ec7, 8dae48b; fork worktree vendor/igneum-node-r3 branch r3-fixes at 5166ee26, merged into devnet-v4measure_m15_attack_before_and_after (ignored test, release, --features igneum-pow); kaspa-pow 8, header_processor 1, p2p pow_guard 2 tests; harness scenario 5 on the merged node50 forged headers: before, 50 cold builds in 10,595 ms and the live day evicted; after, 0 builds, all 50 rejected in 14 ms, 3 October 2026, Apple M5 Max under load 60 to 110. Merged node, 4 October 2026: 63 harness cases with 0 cache builds (the node log shows one build, the honest day) and the M15 p2p cases disconnected by the strike guard; the live devnet v4 runs it. Measured through the validate path with skip_proof_of_work, not the daemon RPCnone yet
    29Blocks reach every node well inside GHOSTDAG's delay bound across continents
    Litepaper Speed (GHOSTDAG at one block a second); spec 03 C1 (lock latency); infra/cloud-devnet/README.md
    tested by the teamrepo 6b5bd92; infra/cloud-devnet/experiments/latency.sh, analyze.py; the Linux cross-build infra/cross/build-linux.sh12 igneumd nodes on cloud VMs in Helsinki, Falkenstein, Ashburn, Hillsboro and Singapore (own chain igneum-devnet-20, one CPU trickle miner each), a ping matrix, then 10 minutes of per-node arrival logs joined on block hash; results/2026-10-04/latency/propagation.md and rtt-by-region.md644 blocks in the window, 642 seen by at least 80% of nodes; arrival at a node minus the first arrival anywhere: p50 343 ms, p90 497 ms, p99 666 ms, max 2,313 ms; by region p50 239 ms (Falkenstein) to 413 ms (Singapore), p90 455 to 632 ms; inter-region RTT 35 ms (Helsinki to Falkenstein) to 289 ms (Ashburn to Singapore); first arrival minus header time median 490 ms. 4 October 2026. The network is the project's own: 12 nodes not 20 (a new account's limits), CPU hash rate only, clocks by chrony, one evening of data; the 5 s bound behind GHOSTDAG k is a design parameter this run did not challengenone yet
    30One click: install, press start, the card mines; the app looks after its node
    Homepage Mine section ("One click: install, press start"); litepaper "One click, for everyone else"; journey phase 5
    tested by the teamrepo 3bb50d6, 2c4b30f, 6461540 (package 0.3.0: prebuilt NVRTC CUDA worker and generic OpenCL worker, driver only), a1a33cb, 7c794df, 0d4498e, 6c083db (Igneum Miner 0.3.0), 78903cd (0.3.1, over-the-air updates)Igneum-Miner-Setup-0.3.0.exe (runner-built, unsigned) on a an RTX 5090 on Windows with an RTX 5090 and no toolchain; proto-cuda/nvrtc/emu/serve-check.sh on the Apple M5 Max; proto-cuda/windows-app/TEST.md; bench-log "one-click Windows workers", "first machine on the Igneum Miner app", "a node 60 s behind the clock is silently dead", "the gfx1036 worker fault"Four machines by 14:45 UTC on 4 October 2026: PC 2, then PC 1 (RTX 5090 at 110 MH/s under the 80% power cap), the project's Apple M5 Max (25 MH/s) and the outside Apple silicon laptop (row 29), all on Igneum Miner 0.3.1. The NVRTC worker compiled the pack on the card with no toolchain installed and mined at 124.2 MH/s, equal to the nvcc-built worker, 0 rejected, CPU re-check clean; inside the app 117 to 119 MH/s with 34 accepted blocks in the first minute, the integrated AMD chip at 3.3 MH/s beside it (row 9). Two defects found by the install, both fixed the same hour: a clock 62 s slow after a power cut made the node reject every relayed block for 12 minutes with no visible reason (the app now reads the skew from the node's warnings, the block timestamps over the EVM RPC and an HTTPS Date header, warns over 5 s and blocks Start over 10 s, with a one-click clock sync; checked on the Apple M5 Max with a fake 60 s skew; a one-line node warning is filed), and the node card said "syncing" while the miner was already accepted. The Mac could only emulate the NVIDIA path (17 of 17 sampled hashes) and the AMD path on Apple OpenCL (15 of 15). Over-the-air updates were dry-run on a private devnet (0.3.0 to 0.3.1 and back), not on a user's machine. The installer is unsigned (SmartScreen "run anyway"). Second machine, the same afternoon: a friend of the project installed Igneum Miner 0.3.1 from the DMG on an Apple silicon laptop with no toolchain and no instructions beyond five steps; the node synced from the seed, the Metal worker reported ready, 33 accepted blocks and 0 rejected in 7 minutes at 21.0 MH/s average, CPU re-check OK on every share, uploads arriving every minute under its per-install id. That laptop is not the project's hardware, but the result is observed through the project's own log intake and reported by the project, so it stays tested by the team until an outsider publishes a run of their own. The devnet's other GPU machines (PC 1 and the Apple M5 Max) run the same workers through the launcher, not the appnone yet
    30One click: install, press start, the card mines; the app looks after its node
    Homepage Mine section ("One click: install, press start"); litepaper "One click, for everyone else"; journey phase 5
    tested by the teamrepo 3bb50d6, 2c4b30f, 6461540 (package 0.3.0: prebuilt NVRTC CUDA worker and generic OpenCL worker, driver only), a1a33cb, 7c794df, 0d4498e, 6c083db (Igneum Miner 0.3.0), 78903cd (0.3.1, over-the-air updates)Igneum-Miner-Setup-0.3.0.exe (runner-built, unsigned) on a an RTX 5090 on Windows with an RTX 5090 and no toolchain; proto-cuda/nvrtc/emu/serve-check.sh on the Apple M5 Max; proto-cuda/windows-app/TEST.md; bench-log "one-click Windows workers", "first machine on the Igneum Miner app", "a node 60 s behind the clock is silently dead", "the gfx1036 worker fault"Four machines by 14:45 UTC on 4 October 2026: the RTX 5090 Windows rig, then the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) (RTX 5090 at 110 MH/s under the 80% power cap), the project's Apple M5 Max (25 MH/s) and the outside Apple silicon laptop (row 29), all on Igneum Miner 0.3.1. The NVRTC worker compiled the pack on the card with no toolchain installed and mined at 124.2 MH/s, equal to the nvcc-built worker, 0 rejected, CPU re-check clean; inside the app 117 to 119 MH/s with 34 accepted blocks in the first minute, the integrated AMD chip at 3.3 MH/s beside it (row 9). Two defects found by the install, both fixed the same hour: a clock 62 s slow after a power cut made the node reject every relayed block for 12 minutes with no visible reason (the app now reads the skew from the node's warnings, the block timestamps over the EVM RPC and an HTTPS Date header, warns over 5 s and blocks Start over 10 s, with a one-click clock sync; checked on the Apple M5 Max with a fake 60 s skew; a one-line node warning is filed), and the node card said "syncing" while the miner was already accepted. The Mac could only emulate the NVIDIA path (17 of 17 sampled hashes) and the AMD path on Apple OpenCL (15 of 15). Over-the-air updates were dry-run on a private devnet (0.3.0 to 0.3.1 and back), not on a user's machine. The installer is unsigned (SmartScreen "run anyway"). Second machine, the same afternoon: a friend of the project installed Igneum Miner 0.3.1 from the DMG on an Apple silicon laptop with no toolchain and no instructions beyond five steps; the node synced from the seed, the Metal worker reported ready, 33 accepted blocks and 0 rejected in 7 minutes at 21.0 MH/s average, CPU re-check OK on every share, uploads arriving every minute under its per-install id. That laptop is not the project's hardware, but the result is observed through the project's own log intake and reported by the project, so it stays tested by the team until an outsider publishes a run of their own. The devnet's other GPU machines (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) and the Apple M5 Max) run the same workers through the launcher, not the appnone yet
    31Card lifetime: a 4 GB card mines about four years and an 8 GB card about twelve, under the dataset's step schedule (2 GB at genesis, doubling at years 4, 12, 28, 60) with the cache freed after the daily build
    Litepaper Hardware and vs RandomX ("Dataset" row); homepage Mine card and "Memory" row
    designeddocs/analysis/card-lifetime-2026-10-05.md (branch card-lifetime 1fecfe2); spec 1.13.3 option (b) recommended to the owner 5 October 2026 (docs/plans/counter-asic-2-rollout.md 6c)The per-tier working-set arithmetic of that document (GTX 1650, RTX 3050, RTX 3060, RTX 4090 tiers) against the step scheduleA design claim: under the continuous mapping (a) a 4 GB card is out within 1 to 1.5 years and an 8 GB card at 6 to 7.5 years, so the sentence is true only under the step schedule (b), which the spec has not yet fixed (O-1.13)none yet

    Click a column heading to sort; click again to reverse. Versions: igneum-pow is the Rust crate at version 0.2.0 (generator version 2, 4 October 2026); repo commits are this repository's; fork commits are the node fork and its worktrees, named by message as the engineering log names them. Source of every number: the engineering log. The source of this page is docs/evidence.md in the repository.

    @@ -239,7 +194,7 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -275,10 +230,23 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + @@ -167,10 +98,9 @@ main{padding-bottom:var(--sec)} @@ -244,7 +186,7 @@ main{padding-bottom:var(--sec)}
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -280,10 +222,23 @@ main{padding-bottom:var(--sec)}
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + @@ -136,10 +80,9 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo @@ -204,7 +159,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -240,10 +195,23 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + @@ -305,10 +159,9 @@ pre{margin:0;font-family:var(--f-mono);font-size:13px;line-height:1.6;color:var(
    +
    -
    -
    -
    GPUs are back · for good
    -

    Mined by GPUs.
    Proven by fire.

    -

    Built for graphics cards. A new mining program every hour, compiled on the card. In our public model the strongest chip reaches 5x to 9x per joule against an RTX 5090 today, about 2x once the lever now in its gates ships: the numbers. Every card mines; today's app proves on a 24 GB NVIDIA card and mines and proves on 32 GB. Measured on 6 October 2026 on eleven rented cards with the patched server: every NVIDIA card from 8 GB proves, 10 GB and up mine and prove (the log); ships when the packaging row lands. AMD and Apple cards mine. No premine, no stake, no foundation.

    - -
    -
    -
    -
    This tab · light client
    -
    PREVIEW
    -
    -
    -
    -
    -

    Browser checks Igneum

    -

    A checkpoint certificate, verified in this tab. Voter list from the node.

    +
    +
    +
    GPUs are back · for good
    +

    Mined by GPUs.
    Proven by fire.

    +

    A proof-of-work chain built for graphics cards. The mining program rewrites itself every hour and is compiled on the card, so a chip built for one hour is useless the next. The same cards prove every block. No premine, no stake, no foundation.

    + +

    Every card mines; today's app proves on a 24 GB NVIDIA card and mines and proves on 32 GB. Measured on 6 October 2026 on eleven rented cards with the patched server: every NVIDIA card from 8 GB proves, 10 GB and up mine and prove (the log); ships when the packaging row lands. AMD and Apple cards mine. The chip model is public: the numbers.

    -
    -
    BLOCK PROOF
    not yet
    -
    CHECKPOINT
    checking
    -
    PROOF SYSTEM
    BLS aggregate, version 1
    -
    VERIFIED IN THIS TAB
    checking
    -
    - -
    -
    - -
    -
    0
    vote keys active in 10 min (a card runs several)
    -
    0.0
    blocks / s
    -
    0.0 MH/s
    hash rate
    -
    0
    chain block
    +
    +
    +
    This tab · light client
    +
    PREVIEW
    +
    +
    +
    +
    +

    Browser checks Igneum

    +

    A checkpoint certificate, verified in this tab. Voter list from the node.

    +
    +
    +
    +
    Block proof
    not yet
    +
    Checkpoint
    checking
    +
    Proof system
    BLS aggregate, version 1
    +
    Verified in this tab
    checking
    +
    +
    +
    +
    1 / s
    blocks, rising to 10
    +
    ~60 s
    to a proof at launch, the target. First GPU proof of a block: 1.4 s on an RTX 5090, 4 Oct 2026
    +
    0
    premine
    +
    4B
    IGN hard cap, ever
    +
    +

    100% of emission goes to miners and provers; the protocol carries no fee.

    -
    +
    -
    1 / s
    blocks, rising to 10
    -
    ~60 s
    to a proof at launch, the target. First GPU proof of a block: 1.4 s on an RTX 5090, 4 Oct 2026
    -
    0
    premine
    -
    4B
    IGN hard cap, ever
    -
    100%
    of emission to miners and provers; the protocol carries no fee
    -
    -
    - -
    -
    -
    +
    +
    The chain, now

    Watch the chain prove itself

    Blocks every second, proven in shards, locked every 30 seconds. First live lock 4 Oct 2026: checkpoint 242, 77.4% of all weight, two hours after genesis.

    -
    -
    -
    simulated preview
    -
    blocks 0proven 0locked 0
    +
    +
    +
    connecting to the devnet observer
    +
    chain block pendingshards proven pendinglast lock pendingvote keys in 10 min pendinghash rate pending
    - -
    - mined - shards being proven - proven - locked checkpoint, final +
    + + +
    - -
    -
    -
    This hour's program
    next in 59:59
    -
    
    -        

    A new program every hour. Last hour's chip is already obsolete. First live swap 4 Oct 2026: Apple, NVIDIA and AMD kept hashing through it, 0 rejected blocks.

    +
    +
    +
    This hour's program
    +
    
    +        

    A new program every hour: a chip wired for one program is useless. A programmable chip is met by the latency-shadow work and the price per joule, not by surprise. First live swap 4 Oct 2026: Apple, NVIDIA and AMD kept hashing through it, 0 rejected blocks.

    -
    +
    Proofs sold to other chains
    -
    rollup · batch proofat testnet
    -
    bridge · state proofat testnet
    -
    rollup · fault proofat testnet
    -
    IGN burned from jobsphase two
    +
    rollup · batch proofat testnet
    +
    bridge · state proofat testnet
    +
    rollup · fault proofat testnet
    +
    IGN burned from jobsphase two
    -

    The same cards sell proofs to rollups and bridges. Jobs are paid on the customer's chain at launch; settlement in IGN with a 10% burn follows the proof bridge in phase two. Live rows arrive with the public testnet, August 2027.

    +

    The same cards sell proofs to rollups and bridges. Jobs are paid on the customer's chain at launch; settlement in IGN with a 10% burn follows the proof bridge in phase two. Live rows arrive with the public testnet, August 2027.

    - Read more in the litepaper +

    Read more in the litepaper

    -
    +
    -
    -

    Monero's idea, finished for GPUs

    -

    The random program that has kept chips off Monero since 2019 (approximate), rebuilt for graphics cards.

    +
    +
    For the sceptic
    +

    Three things to check

    +

    Igneum states its limits first. Each of these is measured, published and open to anyone who wants to break it.

    -
    - - - - - - - - -
    PropertyRandomXIgneum
    Who minesCPUsGPUs
    Program changesEvery hashEvery hour
    Memory2 GB, fixed2 GB, growing (the proposed schedule, fixed at the testnet genesis: 2 GB, doubling at years 4, 12 and 28)
    Verified byAny CPUAny CPU
    +
    +
    +
    Chip economics
    +

    The chip model is public

    +

    In our public model the strongest chip reaches 5x to 9x per joule against an RTX 5090 today, about 2x once the lever now in its gates ships. The model, its inputs and what it does not cover are in the engineering log.

    + The numbers +
    +
    +
    Monero's technique, applied to GPUs
    +

    A program that keeps changing

    +

    The random program that has kept chips off Monero since 2019 (approximate), rebuilt for graphics cards. The program keeps changing on a schedule fixed at genesis; nobody touches it.

    +
    + + + + + + + +
    PropertyRandomXIgneum
    Who minesCPUsGPUs
    Program changesEvery hashEvery hour
    Memory2 GB, fixed2 GB, growing (the proposed schedule, fixed at the testnet genesis: 2 GB, doubling at years 4, 12 and 28)
    Verified byAny CPUAny CPU
    + Igneum vs RandomX +
    +
    +
    Every criticism
    +

    What Igneum does not claim

    +

    Proof lag, chip economics, the market size, and the one rule external review will try hardest to break: the litepaper states the limits, and the ledger carries every criticism, answered or conceded.

    + The limits + The ledger +
    -

    The program keeps changing on a schedule fixed at genesis. Nobody touches it.

    - Read more in the litepaper -

    Built on the shoulders: Kaspa's GHOSTDAG and node, Monero's RandomX idea, Chia's class-group VDF, Ethereum's EVM, Succinct's SP1, BLS12-381 and Bitcoin's address format.
    What changed, why, and how it is measured: the provenance section of the litepaper.

    +

    Built on the shoulders: Kaspa's GHOSTDAG and node, Monero's RandomX idea, Chia's class-group VDF, Ethereum's EVM, Succinct's SP1, BLS12-381 and Bitcoin's address format. What changed, why, and how it is measured: the provenance section of the litepaper.

    -
    +
    -

    One chain, three jobs

    -
    -
    - +
    +
    Igneum Ember · one click
    +

    Install. Start. The card mines.

    +

    Igneum Ember finds your GPU, makes a wallet for you and runs the node, the miner and the prover as one app. The card mines; a 24 GB NVIDIA card proves as well.

    +
    +
    +
    + +

    Devnet. Coins have no value and the chain may be reset.

    +

    Public testnet: not yet open; the devnet build is here for people who want to look.

    +

    Read more about the miner. The protocol carries no fee. The Ember software takes an optional 1% dev fee, like other GPU miners, off with one flag. Download only from this domain. Nobody from Igneum will ask for your seed.

    +
    +

    NVIDIA, AMD, Apple silicon

    Found by itself. One worker per card, several identities each.

    +

    A new program every hour, no pause

    Compiled ahead and swapped in 0.01 ms on the live devnet, 0 rejected blocks.

    +

    Signed updates at a safe moment

    The card keeps mining through the download. The old version comes back if the new one fails to start.

    +

    Four pages: Mine, Earnings, Prove, Settings

    Every card is one row: rate, watts, MH per watt, pounds a day at your electricity price, a Tune button. The node is one line.

    +

    Ember Tune, measured

    An RTX 5090 from 311 W to 227 W for 0.15% of its rate; an RTX 4070 from 106 W to 76 W for none (the Windows rig, 6 Oct 2026). Every number in the bench table.

    +
    +
    +
    + The Mine page of Igneum Miner 0.3.14 on a three-card PC: 169 MH/s at 532 W, one row per card with its rate, watts, MH per watt, temperature, tune line, Tune button and switch +
    Igneum Ember (the app window still says Igneum Miner) 0.3.14 on a Windows rig with an RTX 5090, RTX 4070 and RX 9070 XT, live devnet, 6 Oct 2026.
    +
    +
    +
    + What you agree to when you run the testnet miner +
    +

    No value. Testnet IGN cannot be sold, bought or redeemed, now or at mainnet. There is no airdrop, no points scheme and no promise tied to testnet balances. Mainnet starts from an empty genesis.

    +

    Resets. The chain restarts from a fresh genesis when a consensus rule changes. Every reset is announced at least seven days ahead on this page and in the app. Balances, contracts and history do not carry over. The devnet that runs today resets without notice.

    +

    What the app sends home. The app version, a random machine id made at install, your operating system, the node version, the hash rate, and the app, node and miner logs (which name the address the card mines to). They go to the project's log intake, a service Igneum runs on Vercel, and are read by the maintainers to find faults. Never your seed phrase, never a key, never a file you did not make with the app. Nothing is sold or shared.

    +
    +

    Wallet set-up for MetaMask: chain id, RPC and the one-click button. The miner software takes an optional 1% fee, off with one flag; the protocol carries no fee to anyone.

    +
    +
    +
    + +
    +
    +
    +
    How it works
    +

    One chain, three jobs

    +
    +
    +
    +

    Mine

    Any 4 GB card at launch, 8 GB from about year 4 under the proposed schedule, fixed at the testnet genesis: 2 GB, doubling at years 4, 12 and 28, approximate. 80% of each block to its finder.

    - About the miner + About the miner
    -
    - +
    +

    Prove

    The same card proves shards and sells proofs to other chains.

    - How proving pays + How proving pays
    -
    - +
    +

    Build

    Ethereum bytecode, with the differences documented. Proofs of any computation from the miners' cards, verified by the chain itself. 20% of priority fees to the contracts that ran, stated at the fee levels that exist.

    - Deploy on Igneum + Deploy on Igneum
    - Read more in the litepaper +

    Read more in the litepaper

    -
    +
    -
    -

    One click. The card mines; a 24 GB NVIDIA card proves as well.

    -

    Igneum Ember finds your GPU, makes a wallet for you and runs the node, the miner and the prover as one app.

    -
    -
    -
    -
    -
    Igneum Miner
    - The Mine page of Igneum Miner 0.3.14 on a three-card PC: 169 MH/s at 532 W, one row per card with its rate, watts, MH per watt, temperature, tune line, Tune button and switch -
    Igneum Ember (the app window still says Igneum Miner) 0.3.14 on PC 1 (RTX 5090, RTX 4070, RX 9070 XT), live devnet, 6 Oct 2026.
    -
    -
    -
    -
    -
    NVIDIA, AMD, Apple siliconFound by itself. One worker per card, several identities each.
    -
    A new program every hour, no pauseCompiled ahead and swapped in 0.01 ms on the live devnet, 0 rejected blocks.
    -
    Signed updates at a safe momentThe card keeps mining through the download. The old version comes back if the new one fails to start.
    -
    Four pages: Mine, Earnings, Prove, SettingsEvery card is one row: rate, watts, MH per watt, pounds a day at your electricity price, a Tune button. The node is one line.
    -
    Ember Tune, measuredAn RTX 5090 from 311 W to 227 W for 0.15% of its rate; an RTX 4070 from 106 W to 76 W for none (PC 1, 6 Oct 2026). Every number in the bench table.
    +
    +
    +
    Igneum Wallet · desktop
    +

    Your coins, your wallet

    +

    Igneum Wallet holds the key the miner makes for you and verifies finality itself. MetaMask works too.

    +
    + pending waiting for a block + in a block carried, not yet covered + final, checkpoint 5 under a checkpoint this wallet verified
    -
    - Windows v0.3.14 · 45.4 MB - macOS v0.3.14 · 41.9 MB - Linux · HiveOS +
    +

    Sealed on your machine

    24 words, three typed back, a password. Argon2id and XChaCha20-Poly1305. Nothing leaves.

    +

    Rewards in one history

    Block rewards, proving payouts and transfers. Send with the fee shown. Receive by a QR drawn locally.

    +

    Reads your own node

    When the miner is installed, the wallet uses its node. Nobody else sees your balance.

    -

    Devnet: coins have no value and the chain may be reset.

    -

    Public testnet: not yet open; the devnet build is here for people who want to look.

    -

    Read more about the miner. The protocol carries no fee. The Ember software takes an optional 1% dev fee, like other GPU miners, off with one flag. Download only from this domain. Nobody from Igneum will ask for your seed.

    -
    -
    -
    -
    Testnet terms
    -

    What you agree to when you run the testnet miner

    -
    -
    -

    No value. Testnet IGN cannot be sold, bought or redeemed, now or at mainnet. There is no airdrop, no points scheme and no promise tied to testnet balances. Mainnet starts from an empty genesis.

    -
    -
    -

    Resets. The chain restarts from a fresh genesis when a consensus rule changes. Every reset is announced at least seven days ahead on this page and in the app. Balances, contracts and history do not carry over. The devnet that runs today resets without notice.

    -
    -
    -

    What the app sends home. The app version, a random machine id made at install, your operating system, the node version, the hash rate, and the app, node and miner logs (which name the address the card mines to). They go to the project's log intake, a service Igneum runs on Vercel, and are read by the maintainers to find faults. Never your seed phrase, never a key, never a file you did not make with the app. Nothing is sold or shared.

    -
    -
    -

    Wallet set-up for MetaMask: chain id, RPC and the one-click button. The miner software takes an optional 1% fee, off with one flag; the protocol carries no fee to anyone.

    -
    -
    -
    - -
    -
    -
    -

    Your coins, your wallet

    -

    Igneum Wallet holds the key the miner makes for you and verifies finality itself. MetaMask works too.

    -
    -
    -
    -
    -
    pendingwaiting for a block
    -
    in a blockcarried, not yet covered
    -
    final · cp 5under a checkpoint this wallet verified
    -
    -
    -
    Sealed on your machine24 words, three typed back, a password. Argon2id and XChaCha20-Poly1305. Nothing leaves.
    -
    Rewards in one historyBlock rewards, proving payouts and transfers. Send with the fee shown. Receive by a QR drawn locally.
    -
    Reads your own nodeWhen the miner is installed, the wallet uses its node. Nobody else sees your balance.
    -
    -
    - Read more about the wallet + -

    macOS first, Windows next. Public testnet first. Download only from this domain. Nobody from Igneum will ask for your seed.

    -
    -
    -
    -
    Igneum Wallet
    - The wallet window: a balance in IGN, an example address with Send and Receive, node and finality panels, and a history of block rewards -
    Igneum Wallet on a private test network, 5 Oct 2026. The address is an example.
    -
    +

    macOS first, Windows next. Public testnet first. Download only from this domain. Nobody from Igneum will ask for your seed.

    +
    + The wallet window: a balance in IGN, an example address with Send and Receive, node and finality panels, and a history of block rewards +
    Igneum Wallet on a private test network, 5 Oct 2026. The address is an example.
    +
    -
    +
    -
    -
    -

    Where Igneum is right now

    -
    LOADING
    -
    +
    +
    The journey
    +

    Where Igneum is right now

    +
    loading

    Thirteen months, four public gates, each a measurement published pass or fail.

    -
    -

    The log below is the engineering log's dated entries, newest first. Day one was 3 October 2026; several entries can share a date because the work is logged as it is run.

    -
    - Read more in the litepaper +
    +

    The log below is the engineering log's dated entries, newest first. Day one was 3 October 2026; several entries can share a date because the work is logged as it is run.

    +
    +

    Read more in the litepaper

    -
    +
    -
    -
    +
    +
    +
    Economics

    Every coin, mined

    -

    Hard cap of 4 billion IGN, halving every two years for ever.

    -
    -
    -
    - 80% miners - 20% provers - 0% anyone else in the protocol -
    +

    Hard cap of 4 billion IGN, halving every two years for ever.

    +
    +
    + 80% miners + 20% provers + 0% anyone else in the protocol
    -
    +
    0
    premine
    0
    stake, anywhere
    0
    admin keys in consensus
    90%
    of blocks must signal to upgrade
    -

    No premine, no stake, no fee to any team in the protocol. Base fee burned. The one payment to the project is the Ember software's optional 1% dev fee, off with one flag. On the devnet today the coinbase's 20% output is burned under the tag igneum-proving-pool-v0, and provers are paid from a separate escrow in the execution state credited with the same 20%.

    - Read more in the litepaper +

    No premine, no stake, no fee to any team in the protocol. Base fee burned. The one payment to the project is the Ember software's optional 1% dev fee, off with one flag. On the devnet today the coinbase's 20% output is burned under the tag igneum-proving-pool-v0, and provers are paid from a separate escrow in the execution state credited with the same 20%.

    +

    Read more in the litepaper

    -
    +

    Read what Igneum does not claim.

    -

    The litepaper states the limits before anyone else does. Proof lag, chip economics, the market size, and the one rule external review will try hardest to break.

    +

    The litepaper states the limits first. Proof lag, chip economics, the market size, and the one rule external review will try hardest to break.

    - Litepaper + The litepaper
    @@ -633,7 +498,7 @@ pre{margin:0;font-family:var(--f-mono);font-size:13px;line-height:1.6;color:var(
    - IGNEUM + IGNEUM

    Mined by GPUs. Proven by fire.

    @@ -669,225 +534,60 @@ pre{margin:0;font-family:var(--f-mono);font-size:13px;line-height:1.6;color:var(
    Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
    + + - + + diff --git a/site/journey.json b/site/journey.json index 397dd412b..eca0cfc9b 100644 --- a/site/journey.json +++ b/site/journey.json @@ -50,6 +50,11 @@ } ], "log": [ + { + "date": "2026-10-06", + "text": "16:01Z: Ember run 6 on the three-card Windows rig", + "short": "16:01Z: Ember run 6 on the three-card Windows rig" + }, { "date": "2026-10-06", "text": "Counter ASIC 3.0 item 2: the per-day derivation", @@ -72,8 +77,8 @@ }, { "date": "2026-10-06", - "text": "16:01Z: Ember run 6 on PC 1", - "short": "16:01Z: Ember run 6 on PC 1" + "text": "16:01Z: Ember run 6 on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT)", + "short": "16:01Z: Ember run 6 on the three-card Windows rig (RTX 5090, RTX 4070" }, { "date": "2026-10-06", @@ -87,8 +92,8 @@ }, { "date": "2026-10-06", - "text": "07:52Z to 08:24Z, the segment-aligned prover beside the miner on PC 2's RTX 5090", - "short": "07:52Z to 08:24Z, the segment-aligned prover beside the miner on PC…" + "text": "07:52Z to 08:24Z, the segment-aligned prover beside the miner on the RTX 5090 Windows rig's RTX 5090", + "short": "07:52Z to 08:24Z, the segment-aligned prover beside the miner on the…" }, { "date": "2026-10-06", @@ -100,6 +105,16 @@ "text": "12:25 to 13:20Z, the finality route: why 26 fresh nodes lost the seed every checkpoint", "short": "12:25 to 13:20Z, the finality route: why 26 fresh nodes lost the…" }, + { + "date": "2026-10-05", + "text": "Ember Tune: the two-knob efficiency tune, the fleet prior, and what the three-card Windows rig could measure tonight", + "short": "Ember Tune: the two-knob efficiency tune, the fleet prior" + }, + { + "date": "2026-10-05", + "text": "The SP1 CPU prover on the three-card Windows rig beside the miners, and the backend survey: no zkVM proves on AMD", + "short": "The SP1 CPU prover on the three-card Windows rig beside the miners,…" + }, { "date": "2026-10-05", "text": "The 9070 XT on the eGPU: why 17.9 MH/s, and what moved", @@ -107,7 +122,7 @@ }, { "date": "2026-10-05", - "text": "Ember Tune: the two-knob efficiency tune, the fleet prior, and what PC 1 could measure tonight", + "text": "Ember Tune: the two-knob efficiency tune, the fleet prior, and what the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) could measure tonight", "short": "Ember Tune: the two-knob efficiency tune, the fleet prior" }, { @@ -127,8 +142,8 @@ }, { "date": "2026-10-05", - "text": "The SP1 CPU prover on PC 1 beside the miners, and the backend survey: no zkVM proves on AMD", - "short": "The SP1 CPU prover on PC 1 beside the miners, and the backend survey" + "text": "The SP1 CPU prover on the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) beside the miners, and the backend survey: no zkVM proves on AMD", + "short": "The SP1 CPU prover on the three-card Windows rig (RTX 5090, RTX…" }, { "date": "2026-10-05", @@ -182,7 +197,7 @@ }, { "date": "2026-10-05", - "text": "The program id split: why the Apple M5 Max rejected PC 2's proofs, and the verifier at 114 s", + "text": "The program id split: why the Apple M5 Max rejected the RTX 5090 Windows rig's proofs, and the verifier at 114 s", "short": "The program id split" }, { @@ -234,21 +249,6 @@ "date": "2026-10-04", "text": "Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine", "short": "Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine" - }, - { - "date": "2026-10-04", - "text": "First finality lock on the live devnet: checkpoint 242 at 77.4% of all weight, two hours after genesis", - "short": "First live finality lock: 77.4% of weight, 17 voters" - }, - { - "date": "2026-10-04", - "text": "A node 60 s behind the clock is silently dead", - "short": "A node 60 s behind the clock is silently dead" - }, - { - "date": "2026-10-04", - "text": "First machine on the Igneum Miner app: PC 2's RTX 5090 at 118 MH/s, via Setup.exe", - "short": "First machine on the one-click app: a 5090 at 118 MH/s" } ] } diff --git a/site/ledger.html b/site/ledger.html index 14bf00a2a..7b35d0f30 100644 --- a/site/ledger.html +++ b/site/ledger.html @@ -4,13 +4,13 @@ Igneum ledger: every criticism, answered - + - + @@ -18,7 +18,7 @@ - + @@ -29,9 +29,10 @@ + + + @@ -222,10 +134,9 @@ body.all .pager{display:none} @@ -260,7 +183,7 @@ body.all .pager{display:none}
    A proof-of-work chain whose miners also prove every block, run Ethereum's apps, and are protected from specialised chips by a program that changes every hour.
    - Published 3 October 2026 · updated 5 October 2026 + Published 3 October 2026 · updated 6 October 2026 Coin IGN · cap 4,000,000,000 Status devnet live, pre-testnet Method one founder with AI systems · external review before gate 3 @@ -291,14 +214,14 @@ body.all .pager{display:none}
  • Built on the shoulders
  • What Igneum does not claim
  • -
    +
    Latin igneum: fiery. A cupel is the vessel in which metal is proven by fire.

    Abstract

    -

    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 recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090. A memory-controller chip that stores the whole dataset reaches 1.2x per chip and, in our model, 5x to 9x per joule; the Ethash chips of this class reached 2.1x to 4.8x. The lever against it, program work in the latency shadow, is measured and in its gates: it brings the chip to about 2x. Sources: the chip model (docs/analysis/chip-model-v3.md section 5, 6 October 2026); the Ethash rows of the ASIC history (docs/analysis/asic-resistance-history.md, Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022); Counter ASIC 3.0 item 8 (100,000 ops per hash: the chip's per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at a chip core equal to the GPU's, the 5090 at 0.2% less rate, gates G1 to G6 in progress). The model is public; the claim is tested by paid independent cryptanalysis and the public benchmark.

    +

    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 recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090. A memory-controller chip that stores the whole dataset reaches 1.2x per chip and, in our model, 5x to 9x per joule; the Ethash chips of this class reached 2.1x to 4.8x. The lever against it, program work in the latency shadow, is measured and in its gates: it brings the chip to about 2x. Sources: the chip model analysis (6 October 2026); the Ethash rows of the ASIC history (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022); Counter ASIC 3.0 item 8 (100,000 ops per hash: the chip's per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at a chip core equal to the GPU's, the 5090 at 0.2% less rate, gates G1 to G6 in progress). The model is public; the claim is tested by paid independent cryptanalysis and the public benchmark.

    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.

    1 / s
    blocks, rising to 10
    @@ -351,7 +274,7 @@ body.all .pager{display:none} 1. Mining lottery A random GPU program picks who makes the next block - New program every hour, so a chip for last hour's program is useless + New program every hour: a chip wired for one program is useless @@ -395,10 +318,10 @@ body.all .pager{display:none} Mining lotteryA new program every hour on Apple, NVIDIA and AMD cards, compiled ahead, no pause and no rejected block at the boundary4 Oct 2026, first live swap BlocksAbout one a second with the full fleet; 0.65 a second over the hour to 16:00 UTC on 6 Oct 2026 with one PC off (the live page's hour count, 2,325 blocks)genesis, 3 Oct 2026 DifficultyRule v2, a 600-second reference window, switched on by height under the running chain with no fork and no restart of the chainDAA 33,000, 4 Oct 2026 - FinalityRule v2: a checkpoint every 30 s of chain, locked at two thirds of all 30-day weight. First live lock: checkpoint 242 at 77.4% of all weight, 17 vote keys4 Oct 2026 + FinalityRule v2: a checkpoint every 30 s of chain, locked at two thirds of all 30-day weight. First live lock: checkpoint 242 at 77.4% of all weight, 17 vote keys. No coin is staked. The only thing at stake is 30 days of public work: a vote key's weight is its blue blocks over the window, and equivocation strips it for 30 days4 Oct 2026 Provingv0 active: shards are assigned to miners' keys, proven on their cards, and the records are carried in blocksDAA 84,100, 5 Oct 2026 EmberThe one-click miner on the fleet, version 0.3.13 (6 Oct 2026); the app window still says Igneum Miner4 Oct 2026, first install - WalletIgneum Wallet 0.1.1 on macOS5 Oct 2026 + WalletIgneum Wallet 0.1.4 on macOS (0.1.1 first shipped 5 Oct 2026)6 Oct 2026

    Measured: engineering log, "first hourly program swap on the live devnet", "difficulty rule v2 activated on the live devnet at DAA 33,000", "first finality lock on the live devnet" (4 October 2026); the 0.3.6 release plan (5 October 2026). The block rate is the devnet record in the evidence table, row 7.

    @@ -416,11 +339,11 @@ body.all .pager{display:none} Every hashThe 128 dataset addresses depend on the nonce, so every hash reads different memory. The one-bit select inside the maths costs a chip nothing and is not a defence; the random reads areNo Every hourA new random programNo, the miner compiles whatever arrives Every dayA new datasetNo - Every six monthsA new instruction mix and memory pattern drawn by the chain from rules fixed at genesis, and a new family of instructions unlocked from a reserve written at genesis, so the program space widens every eraNo + Every six monthsA new instruction mix and memory pattern drawn by the chain from rules fixed at genesis, and a new family of instructions unlocked from a reserve written at genesis, so the program space widens every era. A schedule change against fixed datapaths and human forks, not a surprise: a programmable chip reads every drawn parameter as firmwareNo ContinuouslyThe dataset grows on a schedule fixed at genesis, slowly enough that consumer cards keep up for years. A chip is built with fixed memory, so it is on a countdown from the day it ships. Ethereum's growing dataset ran Bitmain's E3 out of memory in 2020 this way, approximate, with nobody doing anythingNo
    -

    Three ideas carry the chip resistance. The hash rewrites itself. 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. It waits on memory, not maths. 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. Miners hold the switch. Spare defences are written into the rules, switched off. A 90% miner signal turns one on. No fork.

    +

    Three ideas carry the chip resistance. The hash rewrites itself. 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). It waits on memory, not maths. 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. Miners hold the switch. Spare defences are written into the rules, switched off. A 90% miner signal turns one on. No fork.

    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: the numbers; the claim is tested by paid independent cryptanalysis and the public benchmark. Monero has run on RandomX since 2019 with no chip publicly shipped, approximate; that is precedent, not proof.

    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.

@@ -437,7 +360,7 @@ body.all .pager{display:none} Light verification256 MB cache on a CPU, milliseconds256 MB cache on a CPU (512 MB from year 4), one warp under 10 ms, the gate. Measured 2.1 ms on one Apple M5 Max core for class v3 (3.4x class v2's 0.61 ms); a 2019-class core not yet Changes over timeNone. A fixed design, unchanged for seven yearsA new program every hour, its memory pattern with it; era draws and reserved families on a schedule fixed at genesis. Nobody touches it Seed grindingNot applicable, the program comes from the hash inputClosed by a verifiable delay between seed and program - Useful workNone. Hashing onlyEvery NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md); they sell proofs to other chains. AMD and Apple cards mine, and a prover for them lands when a zkVM ships one + Useful workNone. Hashing onlyEvery NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026); they sell proofs to other chains. AMD and Apple cards mine, and a prover for them lands when a zkVM ships one Track recordNo chip publicly shipped in seven years, approximateZero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (github.com/igneum-network/spec). The node, the miner and the wallet are in a private repository until the public testnet @@ -449,7 +372,7 @@ body.all .pager{display:none}

Every Igneum block is proven with a zero-knowledge proof, and the miners produce it. Proving is a useful GPU workload that is cheaply verifiable by construction. A proof is right or it is not. Wrapped for light clients, a phone checks it in milliseconds; the wrapping cost is a phase two measurement. Measured so far, the certificate half only: the browser verifier on the home page checks a devnet finality certificate, one BLS aggregate signature over 16 keys and 21 header hashes, in 139 to 155 ms cold and 58 to 68 ms warm in a phone-sized tab on a laptop core (5 October 2026). No phone has been measured, and no wrapped block proof exists yet.

How a block gets proven

Blocks carry transactions only and make no claim about state. Every node executes the ordered transactions natively at once, so users see their transaction land in about a second. The execution is then split into shards of a fixed proving cost. Shards are assigned by lot to eight provers for ten seconds, then open to anyone; there is no bond. Provers run them on consumer cards, and the shard proofs are folded by recursive aggregation into one proof for the block. That proof lands on-chain within about a minute at launch. Because the proof computes the state from the ordered sequence, no node accepts a block with a wrong state root. Full nodes also execute every block natively and reject a proof record whose result differs from their own execution, so a forged proof is a light-client problem and never a chain split. Implemented: the native-execution check on every carried proof record, proving v0 on the devnet (specification section 7). The emergency path for a soundness bug in the proof system is a human one: a new proof-system version is written by people and activates only on miner signalling. Invalid transactions are skipped by rule, the way Kaspa skips conflicting spends.

-

Proving: every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server. Measured on eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md: the RTX 3060 (12 GB) mines at 23.78 MH/s and proves the v1 shard beside its miner at an 8.9 GB peak in 37.5 s; the RTX 4060 (8 GB) proves it alone at 7.4 GB in 18.4 s; the RTX 4090 (24 GB) proves it on the stock SP1 server in 5.6 s at 17.4 GB. The patched server that fits the smaller cards is not yet in the shipped app. AMD and Apple cards mine. A prover for them lands when a zkVM ships one.

+

Proving: every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server. Measured on eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026: the RTX 3060 (12 GB) mines at 23.78 MH/s and proves the v1 shard beside its miner at an 8.9 GB peak in 37.5 s; the RTX 4060 (8 GB) proves it alone at 7.4 GB in 18.4 s; the RTX 4090 (24 GB) proves it on the stock SP1 server in 5.6 s at 17.4 GB. The patched server that fits the smaller cards is not yet in the shipped app. AMD and Apple cards mine. A prover for them lands when a zkVM ships one.

The proving budget

Gas prices execution. Proving cost is a different number, so Igneum meters it separately: every transaction pays in both dimensions, and each block has a proving-cost budget set in consensus from measured prover throughput. A transaction that is cheap to run and expensive to prove pays for what it costs the provers. Measured on 5 October 2026 (an RTX 5090 under SP1 6.8.1's GPU prover, the shard size the chain adopts from its fee switch, 30,000 proving gas, about 4.7 million prover cycles): one full shard proves in 4.3 seconds and needs 20.4 GB of GPU memory with the card to itself, so a 24 GB card proves full shards and a 12 GB or 16 GB card does not on this prover build, whose floor is 13.9 GB for even an empty shard; mining and proving on one card needs 32 GB today (the prototype-size shard beside the miner peaked at 30.1 GB) and 24 GB once the adopted shard size is live (22.2 GB beside the miner, 13.2 seconds a shard, measured on the 32 GB card; a 24 GB card has not run it yet). The old 12 GB gate on the roadmap was withdrawn on 5 October until a prover build with a smaller floor was measured; on 6 October a patched server proved the same shard at 7.4 to 8.0 GB alone on eleven rented cards from the RTX 3060 to the RTX 5090 (the real-card table), so the gate returns as measured and the patched server is not yet in the shipped app. The first proofs exist: on 4 October 2026 an RTX 5090 proved a small two-transaction block in 1.4 seconds (2.7 seconds compressed), verified in 0.22 and 0.038 seconds, and a laptop CPU proved a three-shard block end to end in 19 minutes. Later that day the same card proved a full shard at the provisional size, 6.75 million prover gas, which executed in 60.8 million cycles: core proof 8.3 seconds, compressed proof 10.9 seconds, verified in 0.040 seconds; a four-shard block took 44.5 seconds of GPU stages end to end. Since 5 October 2026 shards are assigned and proven on the live devnet. The gate asks for a mid-range card, and an RTX 5090 is not one, so the gate stands open. Once the gate is measured, the budget rises by schedule as hardware improves. The proof system is hash-based, which is what runs on consumer cards, and sits behind a versioned interface, so Igneum can adopt a better proof system when one exists by a miner-signalled release, and runs for ever on the current one if none is adopted.

Proving for everyone else

@@ -466,7 +389,7 @@ body.all .pager{display:none}

A miner's vote weight is simply the blocks it has mined over the trailing 30 days, measured by work, so splitting into many keys buys nothing and joining a pool costs nothing. Hashrate that arrived today holds almost none of it. Even an attacker producing every block on the chain, with honest miners gone, would need ten days of mining in public to hold a third of the weight, and twenty to hold two thirds. An attacker matching the honest network needs twenty days for a third and never reaches two thirds while the honest miners keep mining. Rental is priced by the hour. The only route left is to drive honest miners off the chain and hold two thirds for a month on the public hashrate charts, which is the same limit Bitcoin lives with, with a month's warning attached. Pools carry their hashers' votes, so vote concentration equals pool concentration, and it is public.

Two further rules close the gaps. A lock needs two thirds of all 30-day weight, so finality pauses whenever less than two thirds of that weight is connected and signing, until it returns or ages out of the window, up to 30 days, and the chain runs on proof of work meanwhile. The node reports the pause. A key that stops signing is reported as absent within two hours, which is how operators see a pause coming. Beneath the latest lock the depth to rely on is the finality depth: a node never switches to a chain forked more than 12 hours of median time back, and a certified checkpoint shortens that to its own age. Kaspa's one-hour merge depth is a limit on which old blocks a new block may merge, not a reorganisation bound. Signing two different checkpoints at the same height is equivocation, provable by anyone, and it strips the key of its vote for 30 days.

What is not here

-

No stake. No coin-holder class votes on anything. No anchoring into Bitcoin or any other chain. Nothing in Igneum's consensus depends on anything outside Igneum.

+

No coin is staked. The only thing at stake is 30 days of public work: a vote key's weight is its blue blocks over the window, and equivocation strips it for 30 days. No coin-holder class votes on anything. No anchoring into Bitcoin or any other chain. Nothing in Igneum's consensus depends on anything outside Igneum.

@@ -571,9 +494,10 @@ body.all .pager{display:none} External proving jobsRollups and apps on other chains, priced in their moneyNo, but the market is small today and is upside, not a promise +

The size of that third stream today, in numbers: all of Ethereum L1's proving is about USD 36 a day at the September 2026 tracker cost (USD 0.005 a block, 7,200 blocks a day; the tracker figure is a secondary source), against about USD 13,700 a day of Igneum's year-1 emission at USD 0.005 per IGN (31.688 IGN a block, 86,400 blocks a day; the price is an input, not a forecast). So external proving is a small second income at launch and the lottery pays the bills; for proving to become the main income the paid demand would have to grow about 1,000x in dollars (the Horizon lane analysis, 6 October 2026, section 3.11; ledger E19).

The honest bear-market case rests on cost. A miner's card is already running and the power is often domestic, so Igneum miners' marginal cost in the proving market is close to power, which is an edge over data-centre provers and nothing more. Which of the two in-chain streams pays more per GPU-second depends on the size of the fleet: on the devnet of 4 October 2026, three machines at 275 million hashes a second, a second of hashing paid about 4.9x a second of proving the pool share; at 10,000 cards the same arithmetic favours proving by about 930x. That is arithmetic on measured devnet rates, approximate, not a market measurement.

Hardware

-

The dataset starts at 2 GB and grows (the proposed schedule, fixed at the testnet genesis: 2 GB, doubling at years 4, 12 and 28, the average of half a gigabyte a year), so a 4 GB card mines for about four years and an 8 GB card for about twelve, approximate. Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md). NVIDIA and AMD both work, because the mining program is generated for the architecture both share and the proof system is hash-based. Apple's chips are GPUs with unified memory, so Macs mine too, at about a fifth of a flagship card: Measured, 26.7 against 123 million hashes a second, an Apple M5 Max beside an RTX 5090 on the live devnet, 4 October 2026. A Mac is a poor miner per dollar. There is no CPU mining lane, on purpose, because CPU mining is what botnets farm. Nodes, wallets and exchanges need no GPU at all.

+

The dataset starts at 2 GB and grows (the proposed schedule, fixed at the testnet genesis: 2 GB, doubling at years 4, 12 and 28, the average of half a gigabyte a year), so a 4 GB card mines for about four years and an 8 GB card for about twelve, approximate. Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026). NVIDIA and AMD both work, because the mining program is generated for the architecture both share and the proof system is hash-based. Apple's chips are GPUs with unified memory, so Macs mine too, at about a fifth of a flagship card: Measured, 26.7 against 123 million hashes a second, an Apple M5 Max beside an RTX 5090 on the live devnet, 4 October 2026. A Mac is a poor miner per dollar. There is no CPU mining lane, on purpose, because CPU mining is what botnets farm. Nodes, wallets and exchanges need no GPU at all.

What a miner's hour looks like

The card hashes the lottery continuously. When the client sees a shard or an external job it can win, it switches the card to proving for a few seconds, posts the proof, and goes back to hashing. The client does the switching and the miner sees one balance.

The protocol carries no fee: no dev fund, no cut to any team. Ember, the miner software, takes an optional 1% dev fee, the way other GPU miners do. One block template in 100 is requested with the dev address instead of yours, by a counter, not a random draw, so it is exactly 1 in 100 and anyone can check it from the source or from the chain. One flag turns it off (--dev-fee 0, a switch in the app, a line in the HiveOS config). The miner prints the fee and the address when it starts. Any other client is welcome.

@@ -602,7 +526,7 @@ body.all .pager{display:none} DashboardPer card: rate, accepted and rejected blocks, temperature, draw, MH per watt, the kernel variant in use, the proving state, and every event. Served on this machine only, behind a per-launch token -

Source: the app's engine, detection, keys, prover, updater, jobs and watchdog modules (app/igneum-app/src), the HiveOS package (packaging/hive). Design, not yet measured on a real card: the watchdog rules and the fault guards, which were measured against a fake worker only (engineering log, "miner fault guards and the app watchdog", 4 October 2026).

+

Source: the app's engine, detection, keys, prover, updater, jobs and watchdog modules (the app source), the HiveOS package (the HiveOS package). Design, not yet measured on a real card: the watchdog rules and the fault guards, which were measured against a fake worker only (engineering log, "miner fault guards and the app watchdog", 4 October 2026).

Six levers

@@ -646,7 +570,7 @@ body.all .pager{display:none}
LeverWhat it doesState, 5 Oct 2026Measured
NextTouch ID and Windows Hello to unlock. In progress, not live. Windows build: next
-

Source: Igneum Wallet 0.1.1, 5 October 2026 (app/igneum-wallet: the vault, HD key, finality, QR and updater modules and the README). Verified: the over-the-air path end to end on one Mac against a test manifest. Not yet run: the Windows path, the rollback paths, a Developer ID signature.

+

Source: Igneum Wallet 0.1.1, 5 October 2026, now 0.1.4 on the downloads host (the wallet source: the vault, HD key, finality, QR and updater modules and the README). Verified: the over-the-air path end to end on one Mac against a test manifest. Not yet run: the Windows path, the rollback paths, a Developer ID signature.

@@ -668,16 +592,16 @@ body.all .pager{display:none} PhaseWhenWhatGate to pass 1. SpecificationOct to Nov 2026Mining generator, shard proving, finality rules, written for external review - 2. Prove the provingNov 2026 to Jan 2027Mining program prototype on GPU and CPU, shard proving benchmark on consumer cards. So far: an RTX 5090 proves a shard in 10.9 s compressed; a CPU verifies a warp in 0.41 to 0.58 ms. A mid-range card has not been measuredA mid-range GPU proves a shard in under 20 s and a CPU verifies a hash in 10 ms - 3. DevnetStarted 3 Oct 2026, 20 nodes by Mar 2027BlockDAG node with the new mining program and EVM execution, 20 nodes. Live now: 1 block a second, difficulty v2, finality v2 locks, proving v0, Ember on every machine. Not yet measured on the live chain: the proof lag behind the tip1 block a second held with proofs under 60 s behind the tip + 2. Prove the provingNov 2026 to Jan 2027Mining program prototype on GPU and CPU, shard proving benchmark on consumer cards. So far: an RTX 5090 proves a shard in 10.9 s compressed; a CPU verifies a warp in 0.61 ms (class v2) to 2.1 ms (class v3). A mid-range card has not been measuredA mid-range GPU proves a shard in under 20 s and a CPU verifies a hash in 10 ms + 3. DevnetStarted 3 Oct 2026, 20 nodes by Mar 2027BlockDAG node with the new mining program and EVM execution, 20 nodes. Live now: 1 block a second, difficulty v2, finality v2 locks, proving v0, Ember on every machine. Measured on the live chain on 6 October 2026: proofs land a median of about 380 s behind the tip (the observer, /live), against the 60 s gate1 block a second held with proofs under 60 s behind the tip 4. Finality and job marketApr to Jul 2027Sustained-mining finality, external proving jobs, miner client with auto-switchingFinality design passes external review and one rollup signs for testnet 5. Public testnetAug to Oct 2027One-click miner app on Windows, macOS and Linux, HiveOS, pools, the first rollup as a proving customer, no coin yet1,000 independent miners run 30 days and rollup proofs are delivered on time 6. Mainnet fair launchNov 2027Genesis with no premine, 30-day ramp. No listing is arranged, promised or sought by the project

Dates slip. Gates do not. Phase two decides everything. If consumer GPUs cannot prove shards fast enough, Igneum says so and does not launch on promises.

-

What ships next: Ember 0.3.6

-

The proving activation of 5 October 2026 set the next release. Each item is in the 0.3.6 plan; none is on the fleet yet.

+

The 0.3.6 release plan, 5 October 2026

+

The proving activation of 5 October 2026 set the next release. The table is the plan as written; Ember has since reached 0.3.14 (6 October 2026), and each item's state is in the engineering log.

@@ -703,11 +627,11 @@ body.all .pager{display:none}
ItemWhy
- - + + - +
WhatNumberSource
Rented NVIDIA hash, 6 October 20262 GH/s for USD 13 an hourThe fleet's bench entry (the rented cards of 6 October 2026); the entry lands tonight with the wave measurement below
The devnet's hash the same afternoon282 MH/s/api/stats, 6 October 2026, 16:40 UTC; 181 MH/s an hour earlier with one PC off
Rented NVIDIA hash, 6 October 20262 GH/s for USD 13 an hourThe rental order for the rented cards of 6 October 2026, approximate; the fleet's bench entry is not yet written
The devnet's hash the same afternoon282 MH/sthe public stats API, 6 October 2026, 16:40 UTC; 181 MH/s an hour earlier with one PC off; 2.66 GH/s at 18:16 UTC with the rented cards mining
Weight a renter holds on day one0.0%The finality simulator, table B (ledger M12)
Lock latency behind the checkpoint1,018 ms medianEngineering log, the finality harness, three nodes
A 50-miner wave against the devnet: blocks taken, locks movedmeasurement tonightThe fleet's bench entry, 6 October 2026
A 50-miner wave against the devnet: blocks taken, locks movednot yet measuredOwed to the fleet's bench entry; the rented cards joined on 6 October 2026

Finality weighted by mining history is new. New gets attacked.

@@ -750,7 +674,7 @@ body.all .pager{display:none}
  • Bitcoin's bech32 and Bitcoin Cash's CashAddr checksum. The address format, through Kaspa, with Igneum prefixes.
  • BLAKE2b, BLAKE3, SHA-256, Keccak. The hashes the node already uses, unchanged. ChaCha, SplitMix64 and FNV-1a inside the lottery hash, implemented from their definitions.
  • -

    What is Igneum's own: the hourly header-bound GPU program, the sustained-mining finality rule, two-dimensional gas with the per-frame app share, the shard market and proving precompile, and the automatic era draws. The full table, with what changed in each component, why the design needed it, and the measurement or specification section that covers it, is docs/provenance.md in the repository and is published with it at the public testnet. Licences stated from memory are marked approximate there and verified before the repository opens.

    +

    What is Igneum's own: the hourly header-bound GPU program, the sustained-mining finality rule, two-dimensional gas with the per-frame app share, the shard market and proving precompile, and the automatic era draws. The full table, with what changed in each component, why the design needed it, and the measurement or specification section that covers it, is the provenance document in the repository and is published with it at the public testnet. Licences stated from memory are marked approximate there and verified before the repository opens.

    @@ -758,7 +682,7 @@ body.all .pager{display:none}

    Here are the limits, stated before anyone else states them.

    • A proof in seconds. Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second.
    • -
    • A chip is impossible. No. A chip is a bad bet, because the target moves before it ships. The published model (5 October 2026) prices the strongest chip we can name, one with the whole cache on-die computing dataset items on the fly, at 0.92x the hash rate of an RTX 5090 per unit of silicon with a 3x fixed-function allowance, approximate. The same model, drawn out to the chip that stores the dataset (6 October 2026): The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090. A memory-controller chip that stores the whole dataset reaches 1.2x per chip and, in our model, 5x to 9x per joule; the Ethash chips of this class reached 2.1x to 4.8x. The lever against it, program work in the latency shadow, is measured and in its gates: it brings the chip to about 2x. Sources: the chip model (docs/analysis/chip-model-v3.md section 5, 6 October 2026); the Ethash rows of the ASIC history (docs/analysis/asic-resistance-history.md, Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022); Counter ASIC 3.0 item 8 (100,000 ops per hash: the chip's per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at a chip core equal to the GPU's, the 5090 at 0.2% less rate, gates G1 to G6 in progress). No hash has stayed free of chips forever; Igneum does not claim to. Monero's seven years without a public chip are precedent, not proof, and a small prize: they say nothing about the price of a chip with the 256 MB cache on its die, and that price is a cost model, not a measurement.
    • +
    • A chip is impossible. No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). The published model (5 October 2026) prices the strongest chip we can name, one with the whole cache on-die computing dataset items on the fly, at 0.92x the hash rate of an RTX 5090 per unit of silicon with a 3x fixed-function allowance, approximate. The same model, drawn out to the chip that stores the dataset (6 October 2026): The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090. A memory-controller chip that stores the whole dataset reaches 1.2x per chip and, in our model, 5x to 9x per joule; the Ethash chips of this class reached 2.1x to 4.8x. The lever against it, program work in the latency shadow, is measured and in its gates: it brings the chip to about 2x. Sources: the chip model analysis (6 October 2026); the Ethash rows of the ASIC history (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022); Counter ASIC 3.0 item 8 (100,000 ops per hash: the chip's per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at a chip core equal to the GPU's, the 5090 at 0.2% less rate, gates G1 to G6 in progress). No hash has stayed free of chips forever; Igneum does not claim to. Monero's seven years without a public chip are precedent, not proof, and a small prize: they say nothing about the price of a chip with the 256 MB cache on its die, and that price is a cost model, not a measurement.
    • A guaranteed income floor. No. External proving is a small market today. Igneum's miners' marginal cost in it is close to power, which is an edge and nothing more.
    • A memory-hard prototype on every vendor. Not yet. The 256 MB cache closed the shortcut on Apple silicon (computing items runs 4.8x slower than loading them, measured 3 October 2026). The same ratio on NVIDIA and on a discrete AMD card is Open.
    • Finality in the first month. No. No checkpoint locks until the 30-day window has 30 days of history. The first month of mainnet is proof of work with a 12-hour depth, and the text above says so wherever a day count appears.
    • @@ -778,7 +702,7 @@ body.all .pager{display:none}
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -814,10 +738,23 @@ body.all .pager{display:none}
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + + @@ -184,10 +117,9 @@ main{padding-bottom:var(--sec)}
      -
      devnet v0
      +
      live devnet

      Live devnet

      A node is read every two seconds. Every block below is real: its parents, its miner, whether it sits on the selected chain, and whether it is a locked checkpoint. A checkpoint locks when the finality rule's quorum signs it. Once the proving layer is activated, every chain block's shards show as they are planned, proven and paid.

      -

      Fees: the devnet meters with its prototype table until DAA score 210,000; from there the adopted table applies (300 pgas per transaction, 30,000-pgas shards, floors of 100 gwei per gas and 10,000 gwei per pgas) and the provers' program carries both.

      +

      Fees: from DAA score 210,000 (the chain's block-time clock, about one step a second) the adopted fee table applies: 300 proving gas per transaction, 30,000-gas shards, floors of 100 gwei per gas and 10,000 gwei per proving gas. Before it the devnet metered with its prototype table, and the provers' program carries both.

      @@ -229,37 +173,38 @@ main{padding-bottom:var(--sec)}
      Blue score
      0
      0 blocks
      Difficulty
      0
      target per block
      Hash rate
      0
      network estimate
      -
      Identities
      0
      vote keys active in 10 min, a card runs several
      +
      Identities
      0
      vote keys active in 10 min; a card runs several
      Peers
      0
      mempool 0
      -
      +
      -
      blocks, finality, proving
      -
      on screen 0chain 0identities 0last lock noneproven pending
      +
      connecting to the devnet observer
      +
      on screen 0chain 0identities 0last lock pendingproven pending
      - +
      -
      blockschainincluded, paidpendingexcludedjust arrivedselected chainone lane per miner, colour from its id; hover a block, or tap it to keep its details up
      -
      finalityfinallocked checkpointproposedreads "paused" whenever under two thirds of the weight is signing
      -
      provingshard plannedprovingverified, prover colourpaidwhere proofs land behind the tiphover a cell, or tap it to keep its details up
      + pending + includedselected chain + excluded + proven + locked checkpoint + finality band, locked, with its weight + finality band, pending
      +

      120 s of blocks on screen. One lane per miner, the busiest first; the rest share the last lane. Hover or tap a block for its hash, miner, blue score, parents and proof state. Ctrl or cmd and scroll, a pinch, or a click into the scene then scroll, changes the window; the page's ?window= fixes it.

      -

      Miners

      last 10 min
      -
      - - - -
      MinerBlocksShareLast seenEngine
      No blocks in the last 10 minutes.
      -
      -

      The short id is the first 8 hex characters of the vote key hash in each header. The engine is what the miner writes into the coinbase; the devnet miner writes nothing yet.

      +

      Miners

      last 10 min
      +
      No blocks in the last 10 minutes.
      +

      Every vote key with a block in the last 10 minutes; a card runs several. The short id is the first 8 hex characters of the vote key hash in each header.

      -

      Events

      newest first
      +

      Events

      the last five
      No events yet.
      +

      Checkpoint locks, miners going quiet and coming back, provers seen, as the observer records them.

      @@ -275,7 +220,7 @@ main{padding-bottom:var(--sec)}
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -311,12 +256,26 @@ main{padding-bottom:var(--sec)}
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + + + diff --git a/site/metamask.html b/site/metamask.html index c71a0e386..d7870ec39 100644 --- a/site/metamask.html +++ b/site/metamask.html @@ -5,13 +5,13 @@ Add Igneum to MetaMask - + - + @@ -31,9 +31,10 @@ + + @@ -135,10 +79,9 @@ pre{margin:0 0 16px;padding:16px 18px;background:var(--graphite);border-radius:v @@ -197,7 +152,7 @@ pre{margin:0 0 16px;padding:16px 18px;background:var(--graphite);border-radius:v
      RPC URL
      http://127.0.0.1:26790
      Symbol
      IGN
      Decimals
      18
      -
      Explorer
      none yet
      +
      Explorer
      igneum.network/explorer

      @@ -228,7 +183,7 @@ pre{margin:0 0 16px;padding:16px 18px;background:var(--graphite);border-radius:v

      Igneum signs transactions with the Ethereum rules (EIP-155, EIP-1559 and legacy envelopes). A transaction signed for another chain id is refused. Gas has two dimensions on Igneum, execution and proving, and the node folds the second into the price it quotes, so eth_gasPrice and eth_estimateGas work as they do on Ethereum. The litepaper has the differences.

      The app and the Igneum Wallet

      -

      The Igneum Miner app makes an address for your earnings and shows you its seed phrase once. That address is an ordinary Ethereum account: import the seed into MetaMask and the balance is there. An Igneum Wallet with the Apps tab and the explorer built in is in the roadmap; until it ships, MetaMask is the wallet.

      +

      The Igneum Ember app (still labelled Igneum Miner in its window) makes an address for your earnings and shows you its seed phrase once. That address is an ordinary Ethereum account: import the seed into MetaMask and the balance is there. Igneum Wallet 0.1.4 is out for macOS and verifies finality itself; its Apps tab is in the roadmap. MetaMask works today and is the way in on Windows and Linux.

      Testnet coin for testing: the faucet sends 10 IGN per address per day. Chain ids 4461 (mainnet), 4462 (testnet) and 4463 (devnet) are fixed in the node. The testnet RPC URL above is a placeholder until the testnet opens; this page is updated the day it does.

      @@ -237,7 +192,7 @@ pre{margin:0 0 16px;padding:16px 18px;background:var(--graphite);border-radius:v
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -273,10 +228,23 @@ pre{margin:0 0 16px;padding:16px 18px;background:var(--graphite);border-radius:v
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + + @@ -226,10 +153,9 @@ pre b{color:var(--molten);font-weight:500} @@ -275,7 +213,7 @@ pre b{color:var(--molten);font-weight:500}
      Igneum Miner
      The Mine page of Igneum Miner 0.3.14 on a three-card PC: the Stop mining button, 169 MH/s at 532 W, 84 blocks this run, and one row per card: an RTX 5090 at 122 MH/s, 222 W, 0.55 MH/W and 56 °C, an RTX 4070 at 28.7 MH/s and 76 W, an RX 9070 XT at 18.9 MH/s and 198 W, each with its tune line, Tune button and switch, and the integrated GPU off -
      Igneum Ember (the app window still says Igneum Miner) 0.3.14, Mine page, on PC 1 (RTX 5090, RTX 4070, RX 9070 XT), live devnet, 6 Oct 2026, 18:16 UTC. No electricity price set, so the £ cells ask for one. The tune lines are stopped tunes from before that afternoon's Power Helper fix.
      +
      Igneum Ember (the app window still says Igneum Miner) 0.3.14, Mine page, on a Windows rig with an RTX 5090, RTX 4070 and RX 9070 XT, live devnet, 6 Oct 2026, 18:16 UTC. No electricity price set, so the £ cells ask for one. The tune lines are stopped tunes from before that afternoon's Power Helper fix.
      @@ -311,7 +249,7 @@ pre b{color:var(--molten);font-weight:500}

      Four pages. Every card is one row.

      -

      Mine, Earnings, Prove, Settings, shipped in 0.3.14 on 6 October 2026. The screenshots are the live app: PC 1's three cards for Mine, Earnings and Settings; this team's Apple M5 Max, paused, for Prove, light and the phone width. Apple silicon reports no draw, so its row carries no watts and no pounds; an NVIDIA or AMD card's row does.

      +

      Mine, Earnings, Prove, Settings, shipped in 0.3.14 on 6 October 2026. The screenshots are the live app: the Windows rig's three cards for Mine, Earnings and Settings; this team's Apple M5 Max, paused, for Prove, light and the phone width. Apple silicon reports no draw, so its row carries no watts and no pounds; an NVIDIA or AMD card's row does.

      @@ -331,7 +269,7 @@ pre b{color:var(--molten);font-weight:500}
      Earnings
      - The Earnings page on PC 1: pounds earned with the devnet reason, IGN from proofs, 64,778 blocks lifetime and 84 this run, 532 W of electricity waiting for a price, the dev fee switch, the rewards address with Copy, Change address and Show my key + The Earnings page on the Windows rig: pounds earned with the devnet reason, IGN from proofs, 64,778 blocks lifetime and 84 this run, 532 W of electricity waiting for a price, the dev fee switch, the rewards address with Copy, Change address and Show my key
      Money first. £ earned reads 0.00 on devnet and says why; 532 W waits for a price. The dev fee switch lives here. Change address and Show my key ask in place, no dialogs.
      @@ -345,7 +283,7 @@ pre b{color:var(--molten);font-weight:500}
      Settings
      - The Settings page on PC 1: Tuning with the goal at Balanced (about 560 W), Ember Tune and Power control on, Hill climb off, the electricity price, the last tune 6 h ago with the next check on 13 Oct; This machine with start at login, remote jobs running a signed job, the name and appearance + The Settings page on the Windows rig: Tuning with the goal at Balanced (about 560 W), Ember Tune and Power control on, Hill climb off, the electricity price, the last tune 6 h ago with the next check on 13 Oct; This machine with start at login, remote jobs running a signed job, the name and appearance
      Plain rows, one sentence each: Tuning, This machine, one update card, Logs, Advanced. Ember Tune and Power control on; the electricity price every £ figure uses is set here.
      @@ -386,7 +324,7 @@ pre b{color:var(--molten);font-weight:500}
      Windows, macOS, Linux

      An installer on Windows, a disk image on macOS, a package on Linux. No toolchain, no driver work: the GPU workers are prebuilt.

      HiveOS package

      A custom miner for farms: the Linux miner, node and both GPU workers with the four Hive hooks. Hive itself is untested: report what breaks.

      First outside machine

      An Apple silicon laptop, no instructions beyond the five steps: 33 accepted blocks in 7 minutes, 0 rejected, 21.0 MH/s average.

      log · 4 Oct 2026
      -
      First card on the app

      An RTX 5090 on Windows from the installer: 117 to 119 MH/s, 34 accepted blocks in the first minute, CPU re-check OK on every share.

      log · 4 Oct 2026
      +
      First card on the app

      An RTX 5090 on Windows from the installer: 117 to 119 MH/s, 34 accepted blocks in the first minute, CPU re-check OK on every share.

      log · 4 Oct 2026
      @@ -430,7 +368,7 @@ pre b{color:var(--molten);font-weight:500}
      Ember Tune

      Tunes every card for hashes per watt: once after install, then every 7 days, and after a driver or program change. The app steps the power limit and the core clock on the live kernel, 60 seconds a step, and keeps the point with the best MH per watt within 1% of the card's top rate. The memory clock is never touched; a step with a rejected hash, a hot GPU or a dragged memory clock is reverted and marked. Every result feeds a fleet prior per card model that the next card of that model starts from. One goal for all cards: Efficiency, Balanced or Maximum, with about how many pounds a day at that goal.

      log · 6 Oct 2026, Ember run 6
      Power control: one approval, then no prompts

      Setting an NVIDIA power or clock limit needs administrator rights on Windows. The app asks once, when you turn Power control on, and registers a helper task; every cap after that is set through the task with no prompt. Off, NVIDIA cards are measured only. AMD cards are set through the app's own helper with no prompt at all.

      log · 6 Oct 2026, the task re-pointed and two caps set with no prompt
      - Ember Tune measured, PC 1, 6 Oct 2026 + Ember Tune measured on the Windows rig, 6 Oct 2026
      On the rowWhat it saysWhen it is not shown
      @@ -439,7 +377,7 @@ pre b{color:var(--molten);font-weight:500}
      CardUntunedTunedSaved

      The chosen clocks are the floor of the ladder, not the optimum: the next cut's ladder goes lower. The pounds are arithmetic from the saved watts at 28p per kWh; the app uses your price. The RX 9070 XT's run aborted at step 1 on a rule that asked a card reporting offsets for watts, fixed the same hour; its row is owed.

      - log · 6 Oct 2026, Ember run 6 on PC 1 (job ember-tune-pc1-6, 0.3.13 + kit 6, elevated, one click) + log · 6 Oct 2026, Ember run 6 on the Windows rig (0.3.13 + tuning kit 6, elevated, one click)
      Latency work

      A block built on a stale tip earns less. The miner is moving from polling to a template subscription and shorter jobs, so a new tip reaches the card in milliseconds. In progress, no number published yet.

      Remote signed jobs, opt in

      Our own fleet only. A switch, "Allow remote jobs from Igneum (signed)", with the key's fingerprint beside it. Off aborts the running job and stops polling. Jobs run at most once each and only on the machines they name.

      @@ -452,7 +390,7 @@ pre b{color:var(--molten);font-weight:500}
      Watchdog per card

      No status line for 90 seconds, or a hash rate of 0 for 60 seconds while synced: the miner is restarted once. If it recurs, that card is marked faulted with the reason and the other cards keep mining.

      log · 4 Oct 2026
      Watchdog per node

      A node that answers nothing for 120 seconds is restarted by the app, with a growing delay when it repeats. Measured: silent node to mining again in 160.0 s.

      log · 4 Oct 2026
      Restart in order

      Miners first, then the node, on quit and on update. What crashes comes back. A worker that restarts itself is left alone, so nothing is restarted twice.

      -
      Clock check

      A clock 60 seconds slow kept a node silently dead for 12 minutes. Now the app reads block times and an HTTPS Date header: over 5 seconds a warning, over 10 seconds Start is blocked and a Sync clock button appears.

      log · 4 Oct 2026
      +
      Clock check

      A clock 60 seconds slow kept a node silently dead for 12 minutes. Now the app reads block times and an HTTPS Date header: over 5 seconds a warning, over 10 seconds Start is blocked and a Sync clock button appears.

      log · 4 Oct 2026
      Recoveries measured, 4 Oct 2026
      @@ -491,7 +429,7 @@ pre b{color:var(--molten);font-weight:500} - + @@ -578,7 +516,7 @@ pre b{color:var(--molten);font-weight:500}
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -614,10 +552,23 @@ pre b{color:var(--molten);font-weight:500}
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + + @@ -141,10 +87,9 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
      -
      3 entries, newest at the bottom
      +
      6 measured rows, 0 fleet tuning models

      GPU bench table

      Measured hash rates per card on the Igneum lottery hash, with the generator version, the miner version, the date and the log entry behind each number.

      @@ -185,13 +142,13 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

      Every row names the engineering log entry or the job it came from. "Measured by the team" means our own hardware and our own log. "Reported by the fleet" means a machine we do not own, read from the status lines its miner uploads.

      MH per watt needs the card's power draw during the run. The app reads it on NVIDIA cards through the driver. Rows get the figure when a run records it.

      There is no other Igneum miner to compare with yet, so this table compares cards, not miners. The app that produces these rows: the miner page.

      -

      Rows: 6. Source file: site/miner-bench.json in the repository.

      +

      Rows: 6. Each row names the engineering log entry it came from.

      Fleet tuning priors

      Ember Tune runs on every card the app mines with: the power limit and the core clock are stepped on the live program and the card keeps the point with the best MH per watt within 1% of its top rate. Every finished tune is reported back without anything that identifies the owner, and the fleet's median point per card model, driver major and program class comes back down inside the signed update manifest as the starting point for the next card of that model. A model needs 5 reports before its prior is used.

      No tune reports yet. The first rows appear once five machines with the same card model have reported.

      Measured by the team

      • NVIDIA GeForce RTX 5090 (driver 617, class l128w0, 2026-10-06, job ember-tune-pc1-6): 1854 MHz core cap, power limit 100% (575 W). 84 W saved for 0.15% of rate: 127.71 MH/s at 226.8 W (0.563 MH/W) against 127.9 MH/s at 311 W untuned (0.411 MH/W), 37% more hashes per watt. The chosen clock is the ladder's floor (60% of the maximum), not the optimum; the next cut's ladder goes to 45% and the climb walks on from here.
      • NVIDIA GeForce RTX 4070 (driver 617, class l128w0, 2026-10-06, job ember-tune-pc1-6): 1863 MHz core cap, power limit 50% (100 W). 30 W saved for no rate lost: 28.78 MH/s at 75.6 W (0.381 MH/W) against 28.72 MH/s at 106 W untuned (0.271 MH/W), 41% more hashes per watt. The chosen clock is the ladder's floor (60% of the maximum), not the optimum; the next cut's ladder goes to 45%.
      -

      Rows: 0. Source file: site/miner-priors.json in the repository, written from the fleet records by tools/tuning.mjs --priors --site.

      +

      Rows: 0. Written from the fleet's tune records at build time.

      Generated from the repository at build time. Times are UTC. Machine names are model names.

      @@ -200,7 +157,7 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -236,10 +193,23 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + + \ No newline at end of file diff --git a/site/partials/footer.html b/site/partials/footer.html index 348ad04ba..96fed4158 100644 --- a/site/partials/footer.html +++ b/site/partials/footer.html @@ -2,7 +2,7 @@
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -38,7 +38,20 @@
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + + \ No newline at end of file diff --git a/site/partials/head.html b/site/partials/head.html index 0d4de444a..5ccac9439 100644 --- a/site/partials/head.html +++ b/site/partials/head.html @@ -1,8 +1,9 @@ + + \ No newline at end of file diff --git a/site/partials/nav.html b/site/partials/nav.html index ac1baf05e..323997824 100644 --- a/site/partials/nav.html +++ b/site/partials/nav.html @@ -2,10 +2,9 @@ diff --git a/site/scenes.html b/site/scenes.html new file mode 100644 index 000000000..f6a51b043 --- /dev/null +++ b/site/scenes.html @@ -0,0 +1,212 @@ + + + + + +Igneum scenes, a lab + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      +
      +
      A lab, not linked
      +

      Three scenes, one feed

      +

      The same live devnet reply, drawn three ways. Every mark is a block the observer stored; the words are the ledger's.

      +
      +
      connecting to the devnet observer
      +
      +
      +
      +

      A · Forge

      embers rise
      + +

      Blocks arrive as embers from the hearth, one column per miner, and cool as they go: pending molten, included ember, proven bone. A lock is the dark band sweeping up; everything under it is final.

      +
      +
      +

      B · Lattice

      a slow isometric DAG
      + +

      Time runs left to right, each miner one step deeper, so parents stand behind their children. The selected chain is the lit spine; a checkpoint is a ring that closes around it when it locks. The camera drifts at chain speed.

      +
      +
      +

      C · Pulse

      the tip at the centre
      + +

      The tip is the centre and time runs outward, a ring every 30 seconds. Each miner is a ray; a block is a bead on it that drifts outward, filling when proven. A lock is a ring that hardens from dashed to solid.

      +
      +
      +
      + pending + included + excluded + proven + locked checkpoint +
      +

      One node is read every 2 s; the window is the last 120 s. Under reduced motion each scene draws a still frame on every reply. Add ?only=a, b or c to the address for one scene full width.

      +
      +
      +
      + + + + + + + + + + + + diff --git a/site/scenes/feed.js b/site/scenes/feed.js new file mode 100644 index 000000000..178353b0b --- /dev/null +++ b/site/scenes/feed.js @@ -0,0 +1,40 @@ +/* One poll of /api/live every 2 s, pushed to every scene on the page (docs/plans/site-ui-3.md, the scenes lab, 6 Oct 2026). + IgneumFeed.start({ url, window, onState, subs: [scene, ...] }); each scene has push(reply). The state words are the site's: + connecting, live, stale (observer offline, last update N ago), failed (live feed unavailable). */ +(function (root) { + 'use strict'; + function fmtAge(sec) { sec = Math.round(sec); return sec < 90 ? sec + ' s' : sec < 5400 ? Math.round(sec / 60) + ' min' : Math.round(sec / 3600) + ' h'; } + function start(opts) { + var subs = opts.subs || [], failures = 0, state = 'connecting', reason = 'connecting'; + function set(s, r) { if (s === state && r === reason) return; state = s; reason = r; if (opts.onState) opts.onState(s, r); } + function poll() { + if (document.hidden) return; + fetch((opts.url || '/api/live') + '?window=' + (opts.window || 120), { cache: 'no-store' }).then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }).then(function (d) { + if (!d || !d.ok || !d.state || !d.blocks) throw new Error('bad reply'); + failures = 0; + if (d.state.stale) set('stale', 'observer offline, last update ' + (d.state.age_s !== null && d.state.age_s !== undefined ? fmtAge(d.state.age_s) + ' ago' : 'unknown')); else set('live', null); + subs.forEach(function (s) { s.push(d); }); + }).catch(function () { failures++; if (failures >= 2) set('failed', 'live feed unavailable'); }); + } + poll(); var t = setInterval(poll, 2000); + document.addEventListener('visibilitychange', function () { if (!document.hidden) poll(); }); + return { stop: function () { clearInterval(t); }, state: function () { return { state: state, reason: reason }; } }; + } + // shared helpers for the three scenes + function cssVar(name, fallback) { try { var v = getComputedStyle(document.documentElement).getPropertyValue(name).trim(); return v || fallback; } catch (e) { return fallback; } } + function theme() { return { ember: cssVar('--ember', '#F2541B'), molten: cssVar('--molten', '#FFB35C'), bone: cssVar('--bone', '#F4F1EC'), ash: cssVar('--ash', '#9A9A9E'), line: cssVar('--line', '#2A2A30'), row: cssVar('--row', '#111114'), ink2: cssVar('--ink-2', '#C9C7C2') }; } + function rgba(hex, a) { var h = hex.replace('#', ''); if (h.length !== 6) return hex; return 'rgba(' + parseInt(h.slice(0, 2), 16) + ',' + parseInt(h.slice(2, 4), 16) + ',' + parseInt(h.slice(4, 6), 16) + ',' + a + ')'; } + // the ledger's word for a block + function word(b) { return b.locked ? 'locked' : b.proven ? 'proven' : (b.chain || b.color === 'blue') ? 'included' : b.color === 'red' ? 'excluded' : 'pending'; } + function hash32(s) { var h = 2166136261; for (var i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); } return (h >>> 0) / 4294967296; } + function sizer(canvas, ctx) { var dpr = Math.min(root.devicePixelRatio || 1, 2); return function () { var W = canvas.clientWidth, H = canvas.clientHeight; canvas.width = Math.round(W * dpr); canvas.height = Math.round(H * dpr); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); return { W: W, H: H }; }; } + function loop(draw, canvas) { + var reduce = root.matchMedia && root.matchMedia('(prefers-reduced-motion: reduce)').matches, running = false, inView = true; + function frame(t) { if (!running) return; draw(t); if (reduce || document.hidden || !inView) { running = false; return; } requestAnimationFrame(frame); } + function kick() { if (!running) { running = true; requestAnimationFrame(frame); } } + if ('IntersectionObserver' in root) new IntersectionObserver(function (es) { es.forEach(function (e) { inView = e.isIntersecting; if (inView) kick(); }); }, { threshold: 0.05 }).observe(canvas); + document.addEventListener('visibilitychange', function () { if (!document.hidden) kick(); }); + return { kick: kick, reduce: reduce }; + } + root.IgneumFeed = { start: start, theme: theme, rgba: rgba, word: word, hash32: hash32, sizer: sizer, loop: loop }; +})(window); diff --git a/site/scenes/forge.js b/site/scenes/forge.js new file mode 100644 index 000000000..eb509c8f4 --- /dev/null +++ b/site/scenes/forge.js @@ -0,0 +1,61 @@ +/* Scene A, Forge. Blocks arrive as embers rising from the bottom, one column per miner. A block cools as its word changes: + pending is molten, included is ember, proven is bone. A lock is a dark band that sweeps up the scene at the newest locked + checkpoint; everything below it is final and settles to ash. Every ember is a block the observer stored. */ +(function (root) { + 'use strict'; + var F = root.IgneumFeed; + function mount(canvas, opts) { + opts = opts || {}; + var ctx = canvas.getContext('2d'), size = F.sizer(canvas, ctx), dims = size(), T = F.theme(); + var blocks = [], byHash = {}, lanes = {}, laneN = 0, lockBlue = null, lockY = null, lockTarget = null, lastT = 0; + var WIN = opts.window || 120; // seconds from the hearth to the top; a block's height is its header age, its glow is its arrival + function vnow() { return Date.now() - 2500; } + root.addEventListener('resize', function () { dims = size(); L.kick(); }); + function laneX(id) { if (!(id in lanes)) lanes[id] = laneN++; var n = Math.max(1, laneN); var i = lanes[id]; return 24 + ((i * 0.618034) % 1) * (dims.W - 48); } + function push(d) { + var now = performance.now(); + d.blocks.forEach(function (b) { + var e = byHash[b.hash]; + if (e) { e.src = b; e.word = F.word(b); return; } + e = { hash: b.hash, src: b, word: F.word(b), x: laneX(b.miner || '?') + (F.hash32(b.hash) - 0.5) * 10, born: now, ts: b.ts, glow: 1, settle: 0 }; + byHash[b.hash] = e; blocks.push(e); + }); + var cps = (d.finality && d.finality.checkpoints) || [], locked = cps.filter(function (c) { return c.state === 'locked'; }); + lockBlue = locked.length ? locked[locked.length - 1].blue_score : null; + blocks.forEach(function (e) { e.final = lockBlue !== null && e.src.blue_score !== null && e.src.blue_score <= lockBlue; }); + var cut = vnow() - WIN * 1000 - 8000; + blocks = blocks.filter(function (e) { if (e.ts < cut) { delete byHash[e.hash]; return false; } return true; }); + L.kick(); + } + function yOf(e) { return dims.H - 16 - ((vnow() - e.ts) / 1000) * ((dims.H - 32) / WIN); } + function draw(t) { + var W = dims.W, H = dims.H; T = F.theme(); + ctx.clearRect(0, 0, W, H); + // the hearth: a faint warm floor + var g = ctx.createLinearGradient(0, H, 0, H - 90); g.addColorStop(0, F.rgba(T.ember, 0.16)); g.addColorStop(1, F.rgba(T.ember, 0)); ctx.fillStyle = g; ctx.fillRect(0, H - 90, W, 90); + // the lock band: the lowest final block's height, eased + var target = null; blocks.forEach(function (e) { if (e.final) { var y = yOf(e); if (target === null || y > target) target = y; } }); + if (target !== null) { lockY = lockY === null ? target : lockY + (target - lockY) * 0.08; } + if (lockY !== null) { var band = ctx.createLinearGradient(0, lockY - 70, 0, lockY); band.addColorStop(0, F.rgba(T.row, 0)); band.addColorStop(1, F.rgba(T.row, 0.9)); ctx.fillStyle = band; ctx.fillRect(0, lockY - 70, W, 70); ctx.fillStyle = F.rgba(T.row, 0.9); ctx.fillRect(0, 0, W, Math.max(0, lockY - 70)); + ctx.strokeStyle = F.rgba(T.ember, 0.6); ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(0, lockY); ctx.lineTo(W, lockY); ctx.stroke(); + ctx.fillStyle = T.ash; ctx.font = '500 10px IBM Plex Mono, monospace'; ctx.textAlign = 'right'; ctx.textBaseline = 'bottom'; ctx.fillText('locked', W - 10, lockY - 4); } + blocks.forEach(function (e) { + var y = yOf(e); if (y < -20) return; + var age = (t - e.born) / 1000, w = e.word; + var col = w === 'proven' ? T.bone : w === 'included' || w === 'locked' ? T.ember : w === 'excluded' ? T.ash : T.molten; + var r = w === 'excluded' ? 2.2 : w === 'proven' ? 3.6 : 3; + var a = e.final ? 0.45 : 1; + if (age < 1.2) { var gl = 1 - age / 1.2; var rg = ctx.createRadialGradient(e.x, y, 0, e.x, y, 18); rg.addColorStop(0, F.rgba(T.molten, 0.5 * gl)); rg.addColorStop(1, F.rgba(T.molten, 0)); ctx.fillStyle = rg; ctx.beginPath(); ctx.arc(e.x, y, 18, 0, Math.PI * 2); ctx.fill(); } + var flicker = e.final ? 0 : Math.sin(t / 420 + e.x) * 0.6; + ctx.globalAlpha = a; ctx.fillStyle = col; ctx.beginPath(); ctx.arc(e.x + flicker, y, r, 0, Math.PI * 2); ctx.fill(); + if (w === 'locked') { ctx.strokeStyle = F.rgba(T.ember, 0.9); ctx.lineWidth = 1.5; ctx.beginPath(); ctx.arc(e.x, y, r + 4, 0, Math.PI * 2); ctx.stroke(); } + // a thin trail: the ember's rise + ctx.strokeStyle = F.rgba(col, 0.12); ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(e.x, y + r); ctx.lineTo(e.x, Math.min(H - 16, y + 14)); ctx.stroke(); + ctx.globalAlpha = 1; + }); + } + var L = F.loop(draw, canvas); L.kick(); + return { push: push, redraw: L.kick }; + } + root.IgneumForge = { mount: mount }; +})(window); diff --git a/site/scenes/lattice.js b/site/scenes/lattice.js new file mode 100644 index 000000000..1ff35cea3 --- /dev/null +++ b/site/scenes/lattice.js @@ -0,0 +1,77 @@ +/* Scene B, Lattice. A slow isometric DAG: time runs left to right, each miner lane sits one step deeper, so parents stand + behind their children. The selected chain is a lit spine; every other edge is a thin thread. Checkpoints are rings that + close around the spine where they lock. The camera drifts at chain speed. */ +(function (root) { + 'use strict'; + var F = root.IgneumFeed; + function mount(canvas, opts) { + opts = opts || {}; + var ctx = canvas.getContext('2d'), size = F.sizer(canvas, ctx), dims = size(), T = F.theme(); + var blocks = [], byHash = {}, lanes = {}, laneN = 0, cps = [], windowS = opts.window || 120, rank = {}; + var DEPTH = 8; // up to DEPTH lanes deep; the isometric step scales with the canvas (about 4.5% of its height per lane) + // the step scales with the canvas; the whole shear never takes more than a third of the width, so a narrow card keeps its time axis + function stepY() { return Math.max(7, Math.min(dims.H * 0.045, (dims.W * 0.33) / (DEPTH * 1.4))); } function stepX() { return stepY() * 1.4; } + root.addEventListener('resize', function () { dims = size(); L.kick(); }); + function lane(id) { if (!(id in lanes)) lanes[id] = laneN++; return lanes[id]; } + function vnow() { return Date.now() - 2500; } + function push(d) { + var now = performance.now(); + d.blocks.forEach(function (b) { var e = byHash[b.hash]; if (e) { e.src = b; e.word = F.word(b); return; } e = { hash: b.hash, src: b, word: F.word(b), lane: lane(b.miner || '?'), born: now }; byHash[b.hash] = e; blocks.push(e); }); + var cut = vnow() - windowS * 1000 - 20000; + blocks = blocks.filter(function (e) { if (e.src.ts < cut) { delete byHash[e.hash]; return false; } return true; }); + blocks.sort(function (a, b) { return a.src.ts - b.src.ts; }); + // lanes ranked: the miners of the selected chain nearest the front, then by blocks in the window + var score = {}; blocks.forEach(function (e) { var m = e.src.miner || '?'; score[m] = (score[m] || 0) + 1 + (e.src.chain ? 3 : 0); }); + var ids = Object.keys(score).sort(function (a, b) { return score[b] - score[a] || (a < b ? -1 : 1); }); rank = {}; ids.forEach(function (id, i) { rank[id] = i; }); + cps = (d.finality && d.finality.checkpoints) || []; + L.kick(); + } + function project(e) { + // the selected chain is the front lane; the other blocks sit one step deeper per miner rank, the many small miners sharing the back + var W = dims.W, H = dims.H, r = rank[e.src.miner || '?'] || 0, z = e.src.chain ? 0 : (1 + (r % (DEPTH - 1))) / DEPTH; + var SX = stepX(), SY = stepY(); + var x = 40 + (W - 80 - DEPTH * SX) * (1 - (vnow() - e.src.ts) / (windowS * 1000)) + z * DEPTH * SX; + var y = H * 0.74 - z * DEPTH * SY; + return { x: x, y: y, z: z }; + } + function draw(t) { + var W = dims.W, H = dims.H; T = F.theme(); + ctx.clearRect(0, 0, W, H); + // the ground plane: three faint isometric rails + ctx.strokeStyle = F.rgba(T.line, 0.9); ctx.lineWidth = 1; + for (var k = 0; k <= DEPTH; k += 2) { var yy = H * 0.74 - k * stepY(), xx = k * stepX(); ctx.beginPath(); ctx.moveTo(xx, yy); ctx.lineTo(W, yy); ctx.stroke(); } + var pos = {}; blocks.forEach(function (e) { pos[e.hash] = project(e); }); + // threads, back to front + var ordered = blocks.slice().sort(function (a, b) { return pos[b.hash].z - pos[a.hash].z; }); + ordered.forEach(function (e) { + var p = pos[e.hash]; if (p.x < -20) return; + (e.src.parents || []).forEach(function (h) { var q = byHash[h]; if (!q) return; var pq = pos[h]; var spine = e.src.chain && q.src.chain; + ctx.strokeStyle = spine ? F.rgba(T.ember, 0.9) : F.rgba(T.ash, e.word === 'excluded' ? 0.1 : 0.2); ctx.lineWidth = spine ? 2.2 : 1; + ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(pq.x, pq.y); ctx.stroke(); + if (spine) { ctx.strokeStyle = F.rgba(T.ember, 0.16); ctx.lineWidth = 8; ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(pq.x, pq.y); ctx.stroke(); } }); + }); + // checkpoint rings around the spine + cps.forEach(function (c) { + var ref = null, best = Infinity; blocks.forEach(function (e) { if (!e.src.chain || e.src.blue_score === null) return; var dd = Math.abs(e.src.blue_score - c.blue_score); if (dd < best) { best = dd; ref = e; } }); + if (!ref || best > 3) return; var p = pos[ref.hash]; if (p.x < 0 || p.x > W) return; + var locked = c.state === 'locked', age = (performance.now() - ref.born) / 1000, close = locked ? Math.min(1, age / 1.5) : 0.35; + ctx.strokeStyle = F.rgba(T.ember, locked ? 0.85 : 0.35); ctx.lineWidth = locked ? 1.8 : 1; ctx.setLineDash(locked ? [] : [3, 5]); + ctx.beginPath(); ctx.ellipse(p.x, p.y, 22 - 8 * close, 9 - 3 * close, 0, 0, Math.PI * 2); ctx.stroke(); ctx.setLineDash([]); + if (locked && !opts.compact) { ctx.fillStyle = T.ash; ctx.font = '500 10px IBM Plex Mono, monospace'; ctx.textAlign = 'center'; ctx.textBaseline = 'alphabetic'; ctx.fillText(Math.round((c.fraction_total || 0) * 100) + '%', p.x, p.y - 16); } + }); + // blocks: small isometric tiles, lit by word + ordered.forEach(function (e) { + var p = pos[e.hash]; if (p.x < -20 || p.x > W + 20) return; var w = e.word, age = (t - e.born) / 1000; + var col = w === 'proven' ? T.bone : (w === 'included' || w === 'locked') ? T.ember : w === 'excluded' ? T.ash : T.molten; + var s = e.src.chain ? 6 : 4.5, a = w === 'excluded' ? 0.45 : 1 - p.z * 0.35; + if (age < 1.4) { var gl = 1 - age / 1.4; var rg = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, 20); rg.addColorStop(0, F.rgba(T.ember, 0.45 * gl)); rg.addColorStop(1, F.rgba(T.ember, 0)); ctx.fillStyle = rg; ctx.beginPath(); ctx.arc(p.x, p.y, 20, 0, Math.PI * 2); ctx.fill(); } + ctx.globalAlpha = a; ctx.fillStyle = w === 'pending' ? T.row : col; ctx.strokeStyle = col; ctx.lineWidth = 1.2; + ctx.beginPath(); ctx.moveTo(p.x, p.y - s); ctx.lineTo(p.x + s * 1.3, p.y); ctx.lineTo(p.x, p.y + s); ctx.lineTo(p.x - s * 1.3, p.y); ctx.closePath(); ctx.fill(); ctx.stroke(); + ctx.globalAlpha = 1; + }); + } + var L = F.loop(draw, canvas); L.kick(); + return { push: push, redraw: L.kick }; + } + root.IgneumLattice = { mount: mount }; +})(window); diff --git a/site/scenes/pulse.js b/site/scenes/pulse.js new file mode 100644 index 000000000..06b10faff --- /dev/null +++ b/site/scenes/pulse.js @@ -0,0 +1,60 @@ +/* Scene C, Pulse. A radial view: the tip at the centre, time outward in rings, each miner a ray. A block is a bead on its + miner's ray at the radius of its age; a proven bead fills; a locked checkpoint is a ring that hardens from dashed to + solid at the radius where it locked. Beads drift outward as time passes. */ +(function (root) { + 'use strict'; + var F = root.IgneumFeed; + function mount(canvas, opts) { + opts = opts || {}; + var ctx = canvas.getContext('2d'), size = F.sizer(canvas, ctx), dims = size(), T = F.theme(); + var blocks = [], byHash = {}, rays = {}, rayN = 0, cps = [], windowS = opts.window || 120; + root.addEventListener('resize', function () { dims = size(); L.kick(); }); + function vnow() { return Date.now() - 2500; } + function ray(id) { if (!(id in rays)) rays[id] = rayN++; return rays[id]; } + function push(d) { + var now = performance.now(); + d.blocks.forEach(function (b) { var e = byHash[b.hash]; if (e) { e.src = b; e.word = F.word(b); return; } e = { hash: b.hash, src: b, word: F.word(b), ray: ray(b.miner || '?'), born: now }; byHash[b.hash] = e; blocks.push(e); }); + var cut = vnow() - windowS * 1000 - 20000; + blocks = blocks.filter(function (e) { if (e.src.ts < cut) { delete byHash[e.hash]; return false; } return true; }); + cps = (d.finality && d.finality.checkpoints) || []; + L.kick(); + } + function polar(e) { var R = Math.min(dims.W, dims.H) / 2 - 14, cx = dims.W / 2, cy = dims.H / 2; var r = 10 + (R - 10) * ((vnow() - e.src.ts) / (windowS * 1000)); var ang = ((e.ray * 0.618034) % 1) * Math.PI * 2 - Math.PI / 2; return { x: cx + Math.cos(ang) * r, y: cy + Math.sin(ang) * r, r: r, ang: ang }; } + function draw(t) { + var W = dims.W, H = dims.H; T = F.theme(); var cx = W / 2, cy = H / 2, R = Math.min(W, H) / 2 - 14; + ctx.clearRect(0, 0, W, H); + // time rings every 30 s + ctx.strokeStyle = F.rgba(T.line, 0.9); ctx.lineWidth = 1; + for (var s = 30; s < windowS; s += 30) { var rr = 10 + (R - 10) * (s / windowS); ctx.beginPath(); ctx.arc(cx, cy, rr, 0, Math.PI * 2); ctx.stroke(); } + // the tip + var pulse = 0.5 + 0.5 * Math.sin(t / 900); var tg = ctx.createRadialGradient(cx, cy, 0, cx, cy, 26); tg.addColorStop(0, F.rgba(T.ember, 0.35 + 0.2 * pulse)); tg.addColorStop(1, F.rgba(T.ember, 0)); ctx.fillStyle = tg; ctx.beginPath(); ctx.arc(cx, cy, 26, 0, Math.PI * 2); ctx.fill(); + ctx.fillStyle = T.ember; ctx.beginPath(); ctx.arc(cx, cy, 3.5, 0, Math.PI * 2); ctx.fill(); + // checkpoint rings, hardening when locked + cps.forEach(function (c) { + var ref = null, best = Infinity; blocks.forEach(function (e) { if (e.src.blue_score === null) return; var dd = Math.abs(e.src.blue_score - c.blue_score); if (dd < best) { best = dd; ref = e; } }); + if (!ref || best > 3) return; var p = polar(ref); if (p.r > R) return; var locked = c.state === 'locked', age = (performance.now() - ref.born) / 1000, hard = locked ? Math.min(1, age / 2) : 0; + ctx.strokeStyle = F.rgba(T.ember, locked ? 0.35 + 0.5 * hard : 0.3); ctx.lineWidth = locked ? 1 + hard : 1; ctx.setLineDash(locked && hard > 0.9 ? [] : [3, 6]); + ctx.beginPath(); ctx.arc(cx, cy, p.r, 0, Math.PI * 2); ctx.stroke(); ctx.setLineDash([]); + }); + // the selected chain as a soft spiral thread through its beads + var chain = blocks.filter(function (e) { return e.src.chain; }).sort(function (a, b) { return a.src.ts - b.src.ts; }); + // the selected chain as short arcs between consecutive chain beads (the arc follows the ring between the two radii, never a chord through the centre) + if (chain.length > 1) { ctx.strokeStyle = F.rgba(T.ember, 0.28); ctx.lineWidth = 1; for (var i = 1; i < chain.length; i++) { var p0 = polar(chain[i - 1]), p1 = polar(chain[i]); if (p0.r > R || p1.r > R) continue; var a0 = p0.ang, a1 = p1.ang, da = ((a1 - a0 + Math.PI * 3) % (Math.PI * 2)) - Math.PI; var steps = 10; ctx.beginPath(); for (var k = 0; k <= steps; k++) { var f = k / steps, rr = p0.r + (p1.r - p0.r) * f, aa = a0 + da * f; var x = cx + Math.cos(aa) * rr, y = cy + Math.sin(aa) * rr; if (k) ctx.lineTo(x, y); else ctx.moveTo(x, y); } ctx.stroke(); } } + // beads + blocks.forEach(function (e) { + var p = polar(e); if (p.r > R + 6) return; var w = e.word, age = (t - e.born) / 1000; + var col = w === 'proven' ? T.bone : (w === 'included' || w === 'locked') ? T.ember : w === 'excluded' ? T.ash : T.molten; + var rad = e.src.chain ? 4 : 3; + if (age < 1.2) { var gl = 1 - age / 1.2; var rg = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, 16); rg.addColorStop(0, F.rgba(T.ember, 0.5 * gl)); rg.addColorStop(1, F.rgba(T.ember, 0)); ctx.fillStyle = rg; ctx.beginPath(); ctx.arc(p.x, p.y, 16, 0, Math.PI * 2); ctx.fill(); } + ctx.globalAlpha = w === 'excluded' ? 0.45 : 1; + ctx.beginPath(); ctx.arc(p.x, p.y, rad, 0, Math.PI * 2); + if (w === 'proven' || w === 'included' || w === 'locked') { ctx.fillStyle = col; ctx.fill(); } else { ctx.fillStyle = T.row; ctx.fill(); ctx.strokeStyle = col; ctx.lineWidth = 1.2; ctx.stroke(); } + if (w === 'locked') { ctx.strokeStyle = F.rgba(T.ember, 0.9); ctx.lineWidth = 1.5; ctx.beginPath(); ctx.arc(p.x, p.y, rad + 4, 0, Math.PI * 2); ctx.stroke(); } + ctx.globalAlpha = 1; + }); + } + var L = F.loop(draw, canvas); L.kick(); + return { push: push, redraw: L.kick }; + } + root.IgneumPulse = { mount: mount }; +})(window); diff --git a/site/scrub.mjs b/site/scrub.mjs index 64acd3161..45890e9ed 100644 --- a/site/scrub.mjs +++ b/site/scrub.mjs @@ -8,7 +8,11 @@ import { fileURLToPath } from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); const utc = (h, m, s) => `${String((Number(h) + 23) % 24).padStart(2, '0')}:${m}${s || ''} UTC`; const RULES = [ - // machines: model names only + // machines: model names only (6 October 2026, site audit: the two Windows machines are described, never numbered) + [/\bPC 1's\b/g, "the three-card Windows rig's"], + [/\bPC 1\b/g, 'the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT)'], + [/\bPC 2's\b/g, "the RTX 5090 Windows rig's"], + [/\bPC 2\b/g, 'the RTX 5090 Windows rig'], [/the PC node at 192\.168\.[0-9.]+/g, 'the RTX 5090 node on the LAN'], [/\bthe PC node\b/g, 'the RTX 5090 node'], [/\bWindows PC\b/g, 'an RTX 5090 on Windows'], @@ -33,6 +37,12 @@ const RULES = [ [/dl\.igneum\.network[^ )`]*/g, 'the downloads host'], [/,? ?log intake id \d+/g, ''], [/\bintake id \d+\b/g, 'intake'], + // the site audit's page-leak shapes (6 October 2026): process ids, listen addresses, config paths, the node's listen flag + [/\bpid \d+\b/g, 'pid '], + [/0\.0\.0\.0:\d+/g, ''], + [/--rpclisten=\S*/g, 'the RPC listen flag'], + [/~\/\.config\/[A-Za-z0-9_./-]*/g, ''], + [/~\/\.config/g, ''], [/~\/Desktop\//g, '`'], [/``/g, '`'], [/~\/\.cargo\/bin\/cargo/g, 'cargo'], [/\/Users\/[A-Za-z0-9_.-]+/g, '~'], diff --git a/site/site.css b/site/site.css new file mode 100644 index 000000000..3500f2c5e --- /dev/null +++ b/site/site.css @@ -0,0 +1,230 @@ +/* Igneum site: one design system for every page (docs/plans/site-ui-3.md, 6 October 2026). + Tokens, type, the shared components (nav, footer, card, tile, table, button, pill, note, callout, code) and the + state words. Each page keeps a short block of its own after this file. Fonts are declared in partials/head.html. */ + +/* ---------- 1. tokens ---------- */ +:root{ + --obsidian:#0C0C0E;--graphite:#16161A;--row:#111114;--line:#2A2A30;--line-2:#3A3A42; + --ember:#F2541B;--ember-hi:#FF6A2B;--ember-text:#F2541B;--molten:#FFB35C;--molten-text:#FFB35C; + --bone:#F4F1EC;--ink-2:#C9C7C2;--ash:#9A9A9E;--ember-ink:#0C0C0E;--ok:#FFB35C; + --scrim:rgba(12,12,14,.72);--top-bg:rgba(12,12,14,.86);--shadow:rgba(0,0,0,.6);--hover:rgba(255,255,255,.04); + --ember-12:rgba(242,84,27,.12);--ember-40:rgba(242,84,27,.4);--molten-10:rgba(255,179,92,.1); + /* the chrome tokens older page blocks still read */ + --ground:var(--obsidian);--surface:var(--graphite);--surface-2:var(--row);--ink:var(--bone);--quiet:var(--ash); + --ui-bg:var(--top-bg);--ui-menu:var(--obsidian);--ui-ink:var(--bone);--ui-ink-2:var(--ink-2);--ui-ash:var(--ash);--ui-line:var(--line);--ui-line-2:var(--line-2); + --ui-accent:var(--ember);--ui-accent-ink:var(--ember-ink);--ui-hot:var(--molten);--ui-hover:var(--ember-hi);--ui-tint:var(--ember-12); + --code:var(--row);--code-ink:var(--ink-2); + /* type */ + --f-sans:'IBM Plex Sans','Plex Sans Fallback',system-ui,-apple-system,sans-serif; + --f-display:'Unbounded','Unbounded Fallback',sans-serif; + --f-mono:'IBM Plex Mono','Plex Mono Fallback',ui-monospace,Menlo,monospace; + --t-xs:11px;--t-sm:12px;--t-base:15px;--t-md:17px;--t-lg:19px;--t-h3:20px; + --t-h2:clamp(26px,3.2vw,36px);--t-h1:clamp(32px,5vw,56px);--t-hero:clamp(40px,7vw,76px);--t-num:clamp(26px,3vw,40px); + /* space, radius */ + --s-1:4px;--s-2:8px;--s-3:12px;--s-4:16px;--s-5:24px;--s-6:32px; + --gutter:32px;--sec:96px;--max:1120px;--nav-h:64px; + --r-card:16px;--r-row:12px;--r-btn:10px;--r-pill:999px; + color-scheme:dark; +} +@media (prefers-color-scheme:light){:root:not([data-theme="dark"]){ + --obsidian:#F4F1EC;--graphite:#FFFFFF;--row:#FAF8F5;--line:#E2DED8;--line-2:#CFCAC2; + --ember:#D0420D;--ember-hi:#E04A14;--ember-text:#B8390C;--molten:#B8731F;--molten-text:#8F5810; + --bone:#16161A;--ink-2:#3C3C42;--ash:#6B6B70;--ember-ink:#FFFFFF;--ok:#B8731F; + --scrim:rgba(244,241,236,.72);--top-bg:rgba(244,241,236,.88);--shadow:rgba(0,0,0,.18);--hover:rgba(0,0,0,.04); + --ember-12:rgba(224,74,20,.1);--ember-40:rgba(224,74,20,.4);--molten-10:rgba(184,115,31,.1); + color-scheme:light; +}} +:root[data-theme="light"]{ + --obsidian:#F4F1EC;--graphite:#FFFFFF;--row:#FAF8F5;--line:#E2DED8;--line-2:#CFCAC2; + --ember:#D0420D;--ember-hi:#E04A14;--ember-text:#B8390C;--molten:#B8731F;--molten-text:#8F5810; + --bone:#16161A;--ink-2:#3C3C42;--ash:#6B6B70;--ember-ink:#FFFFFF;--ok:#B8731F; + --scrim:rgba(244,241,236,.72);--top-bg:rgba(244,241,236,.88);--shadow:rgba(0,0,0,.18);--hover:rgba(0,0,0,.04); + --ember-12:rgba(224,74,20,.1);--ember-40:rgba(224,74,20,.4);--molten-10:rgba(184,115,31,.1); + color-scheme:light; +} +@media (max-width:1000px){:root{--gutter:24px}} +@media (max-width:720px){:root{--gutter:16px;--sec:64px}} + +/* ---------- 2. base ---------- */ +*{box-sizing:border-box} +html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:calc(var(--nav-h) + 16px)} +@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}} +body{margin:0;background:var(--obsidian);color:var(--bone);font:400 var(--t-md)/1.6 var(--f-sans);-webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;overflow-x:hidden} +h1,h2,h3,h4{font-family:var(--f-display);color:var(--bone);margin:0;text-wrap:balance;letter-spacing:-.01em} +h1{font-size:var(--t-h1);font-weight:900;line-height:1.05} +h2{font-size:var(--t-h2);font-weight:700;line-height:1.1} +h3{font-size:var(--t-h3);font-weight:700;line-height:1.25} +p,li,dd,figcaption,td{text-wrap:pretty} +p{margin:0 0 1em} +a{color:var(--ember-text);text-decoration:none} +a:hover{text-decoration:underline;text-underline-offset:3px} +a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visible,input:focus-visible{outline:2px solid var(--ember);outline-offset:3px;border-radius:6px} +::selection{background:var(--ember-40)} +img,canvas,svg,video{max-width:100%;display:block} +code,kbd,.mono{font-family:var(--f-mono)} +hr{border:0;border-top:1px solid var(--line);margin:var(--s-6) 0} +.skip{position:absolute;left:12px;top:-80px;z-index:50;background:var(--ember);color:var(--ember-ink);padding:10px 14px;border-radius:var(--r-btn);font:600 15px/1.2 var(--f-sans);text-decoration:none} +.skip:focus{top:12px} +.wrap{max-width:var(--max);margin:0 auto;padding:0 var(--gutter)} +.sec{padding:var(--sec) 0} +.sec+.sec{padding-top:0} +.sec-head{max-width:68ch;margin-bottom:var(--s-6)} +.sec-head p{color:var(--ink-2);font-size:var(--t-lg);line-height:1.5;margin:var(--s-3) 0 0} +.lead{font-size:var(--t-lg);line-height:1.55;color:var(--ink-2);max-width:62ch} +.eyebrow{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ash);margin-bottom:var(--s-3)} +.eyebrow.ember{color:var(--ember-text)} +.measure{max-width:68ch} +.muted{color:var(--ash)} +.right{text-align:right} +.visually-hidden{position:absolute!important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap} + +/* ---------- 3. nav ---------- */ +.nav{position:sticky;top:0;z-index:40;background:var(--top-bg);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-bottom:1px solid var(--line)} +.nav .wrap{display:flex;align-items:center;gap:var(--s-5);height:var(--nav-h)} +.brand{display:inline-flex;align-items:center;gap:10px;color:var(--bone);text-decoration:none} +.brand:hover{text-decoration:none} +.brand .mark{width:28px;height:28px;display:grid;place-items:center;border-radius:8px;background:var(--graphite);border:1px solid var(--line)} +.brand .word{font:900 20px/1 var(--f-display);letter-spacing:.06em} +.nav .links{display:flex;align-items:center;gap:var(--s-4);margin-left:auto} +.nav .links a{color:var(--ink-2);font-size:var(--t-base);font-weight:500;padding:8px 2px;border-bottom:2px solid transparent} +.nav .links a:hover{color:var(--bone);text-decoration:none} +.nav .links a[aria-current="page"]{color:var(--bone);border-bottom-color:var(--ember)} +.nav .cta{margin-left:var(--s-3)} +.burger{display:none;margin-left:auto;width:44px;height:44px;border-radius:var(--r-btn);border:1px solid var(--line);background:var(--graphite);color:var(--bone);cursor:pointer;align-items:center;justify-content:center} +.burger .bars{display:block;width:18px;height:2px;background:currentColor;position:relative} +.burger .bars::before,.burger .bars::after{content:"";position:absolute;left:0;width:18px;height:2px;background:currentColor} +.burger .bars::before{top:-6px}.burger .bars::after{top:6px} +.nav-sheet{display:none} +@media (max-width:900px){ + .nav .links{display:none} + .nav .cta{display:none} + .burger{display:inline-flex} + .nav.open .nav-sheet{display:block;position:fixed;inset:var(--nav-h) 0 0 0;background:var(--obsidian);z-index:39;overflow:auto;padding:var(--s-5) var(--gutter)} + .nav-sheet a{display:block;padding:14px 0;border-bottom:1px solid var(--line);color:var(--bone);font-size:var(--t-lg);font-weight:500} + .nav-sheet a[aria-current="page"]{color:var(--ember-text)} + .nav-sheet .btn{margin-top:var(--s-5);width:100%} +} + +/* ---------- 4. footer ---------- */ +.foot{border-top:1px solid var(--line);padding:var(--s-6) 0 var(--s-5);margin-top:var(--sec);color:var(--ash);font-size:var(--t-base)} +.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:var(--s-6)} +.foot-brand .brand{margin-bottom:var(--s-3)} +.foot-brand p{color:var(--ash);margin:0} +.foot-col .eyebrow{margin-bottom:var(--s-3)} +.foot-col a{display:block;color:var(--ink-2);padding:5px 0} +.foot-col a:hover{color:var(--bone)} +.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--s-3);border-top:1px solid var(--line);margin-top:var(--s-6);padding-top:var(--s-4);font-size:var(--t-sm)} +.foot-imprint{max-width:60ch;line-height:1.5} +.theme{display:inline-flex;border:1px solid var(--line);border-radius:var(--r-pill);overflow:hidden} +.theme button{background:transparent;border:0;color:var(--ash);font:500 var(--t-sm)/1 var(--f-mono);padding:8px 12px;cursor:pointer} +.theme button[aria-pressed="true"]{background:var(--graphite);color:var(--bone)} +@media (max-width:900px){.foot-grid{grid-template-columns:1fr 1fr}} +@media (max-width:500px){.foot-grid{grid-template-columns:1fr}} + +/* ---------- 5. components ---------- */ +.card{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5)} +.card h3{margin-bottom:var(--s-2)} +.card p:last-child{margin-bottom:0} +.grid{display:grid;gap:var(--s-4)} +.grid.c2{grid-template-columns:repeat(2,minmax(0,1fr))} +.grid.c3{grid-template-columns:repeat(3,minmax(0,1fr))} +.grid.c4{grid-template-columns:repeat(4,minmax(0,1fr))} +@media (max-width:900px){.grid.c3,.grid.c4{grid-template-columns:repeat(2,minmax(0,1fr))}} +@media (max-width:560px){.grid.c2,.grid.c3,.grid.c4{grid-template-columns:minmax(0,1fr)}} +/* a grid track never grows past the viewport for a long line inside it (the 390 px overflow class, 6 Oct 2026) */ +.grid>*,.tiles>*,.card,.two>*,.split>*,.split2>*,.hero-grid>*,.download>*,.layout>*,.pillars>*,.phases>*,.group>*,.feats>*,.fee>*,.steps>*,.states>*,.ol>*,.cells>*,.strip>*{min-width:0} +pre{max-width:100%} +@media (max-width:720px){main table{display:block;overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}.tbl table{display:table}} +.tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--s-3)} +@media (max-width:700px){.tiles{grid-template-columns:repeat(2,minmax(0,1fr))}} +.tile{background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:var(--s-4) var(--s-4) var(--s-3);min-width:0} +.tile .v{font:700 var(--t-num)/1 var(--f-display);color:var(--bone);letter-spacing:-.02em;overflow-wrap:anywhere} +.tile .v.state{font:500 var(--t-base)/1.3 var(--f-mono);color:var(--ash);padding:6px 0} +.tile .k{font:400 var(--t-sm)/1.4 var(--f-mono);color:var(--ash);margin-top:var(--s-2)} +.tile.hot .v{color:var(--ember-text)} +.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:10px 20px;border-radius:var(--r-btn);border:1px solid var(--line);background:transparent;color:var(--bone);font:600 var(--t-base)/1.2 var(--f-sans);text-decoration:none;cursor:pointer;white-space:nowrap} +.btn:hover{text-decoration:none;border-color:var(--line-2);background:var(--hover)} +.btn.primary{background:var(--ember);border-color:var(--ember);color:var(--ember-ink);font:700 15px/1.2 var(--f-display);letter-spacing:.01em} +.btn.primary:hover{background:var(--ember-hi);border-color:var(--ember-hi)} +.btn.small{min-height:36px;padding:6px 14px;font-size:14px} +.btn[aria-disabled="true"],.btn:disabled{opacity:.5;cursor:default} +@media (max-width:720px){.cta .btn{width:100%}} +.cta{display:flex;flex-wrap:wrap;gap:var(--s-3)} +.pill{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:var(--r-pill);padding:5px 12px;font:500 var(--t-sm)/1.4 var(--f-mono);color:var(--ink-2);background:var(--row)} +.dot{width:8px;height:8px;border-radius:50%;background:var(--molten);display:inline-block;flex:none} +.dot.live{animation:pulse 2s ease-in-out infinite} +.dot.off{background:var(--ash);animation:none} +.dot.bad{background:var(--ember);animation:none} +@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}} +@media (prefers-reduced-motion:reduce){.dot.live{animation:none}} +.note{color:var(--ash);font-size:var(--t-base);line-height:1.55;max-width:80ch;margin:var(--s-4) 0 0} +.callout{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:var(--s-4) var(--s-5);margin:var(--s-5) 0;color:var(--ink-2)} +.callout p:last-child{margin:0} +pre,.code{background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:var(--s-4);font:400 14px/1.6 var(--f-mono);color:var(--ink-2);overflow:auto;margin:0} +code{font-size:.92em;background:var(--row);border:1px solid var(--line);border-radius:6px;padding:1px 6px;color:var(--ink-2)} +pre code{background:none;border:0;padding:0} +.tbl{overflow-x:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--line);border-radius:var(--r-row);background:var(--graphite);min-width:0;max-width:100%} +table{border-collapse:collapse;width:100%;font-size:var(--t-base);line-height:1.45} +th,td{text-align:left;padding:10px 14px;vertical-align:top} +th{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);border-bottom:1px solid var(--line);white-space:nowrap} +td{border-top:1px solid var(--line);color:var(--ink-2)} +tr:first-child td{border-top:0} +td.num,th.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap} +td.id{font-family:var(--f-mono);font-size:14px;overflow-wrap:anywhere} +@media (max-width:720px){th,td{padding:8px 10px}} +.kv{display:grid;grid-template-columns:minmax(120px,30%) 1fr;gap:0 var(--s-4)} +.kv>div{padding:10px 0;border-top:1px solid var(--line);color:var(--ink-2)} +.kv>div:nth-child(-n+2){border-top:0} +.kv .k{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash);padding-top:12px} +details{border-top:1px solid var(--line)} +details:last-of-type{border-bottom:1px solid var(--line)} +summary{cursor:pointer;padding:14px 0;color:var(--bone);font-weight:500;list-style:none;display:flex;justify-content:space-between;gap:var(--s-3)} +summary::-webkit-details-marker{display:none} +summary::after{content:"+";font-family:var(--f-mono);color:var(--ash)} +details[open] summary::after{content:"\2212"} +details>:not(summary){padding-bottom:var(--s-4);color:var(--ink-2)} +input,select,textarea{font:400 var(--t-md)/1.4 var(--f-sans);color:var(--bone);background:var(--row);border:1px solid var(--line);border-radius:var(--r-btn);padding:10px 12px;width:100%} +input:focus,select:focus,textarea:focus{border-color:var(--line-2)} +.field{display:grid;gap:6px;margin-bottom:var(--s-4)} +.field label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)} + +/* ---------- 6. states ---------- */ +.state{display:inline-flex;align-items:center;gap:8px;font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)} +.state.live{color:var(--molten-text)} +.state.bad{color:var(--ember-text)} +.empty{color:var(--ash);font-size:var(--t-base);padding:var(--s-5) 0} +.empty.err{color:var(--ember-text)} +.spinner{width:24px;height:24px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--ember);animation:spin 1s linear infinite} +@keyframes spin{to{transform:rotate(360deg)}} +@media (prefers-reduced-motion:reduce){.spinner{animation:none}} + +/* ---------- 7. scenes ---------- */ +.viz{padding:var(--s-4)} +.viz-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:10px var(--s-5);margin-bottom:var(--s-3)} +.viz-stats{display:flex;flex-wrap:wrap;gap:var(--s-3) var(--s-4);font:400 var(--t-sm)/1.4 var(--f-mono);color:var(--ash)} +.viz-stats b{color:var(--bone);font-weight:500} +.viz canvas{width:100%;height:340px;border-radius:var(--r-row);background:var(--row);border:1px solid var(--line)} +@media (max-width:600px){.viz canvas{height:240px}} +.legend{display:flex;flex-wrap:wrap;gap:var(--s-3) var(--s-4);margin-top:var(--s-4);font-size:14px;color:var(--ink-2)} +.legend[hidden]{display:none} +.legend span{display:inline-flex;align-items:center;gap:8px} +.sw{width:12px;height:12px;border-radius:3px;display:inline-block;flex:none} + +/* the engaged scene: a chip in the corner while the wheel zooms */ +.scene canvas.engaged{outline:2px solid var(--ember);outline-offset:-2px} +.chip-zoom{position:absolute;right:12px;top:12px;display:inline-flex;align-items:center;gap:8px;background:var(--graphite);border:1px solid var(--line-2);border-radius:var(--r-pill);padding:5px 12px;font:500 var(--t-sm)/1.4 var(--f-mono);color:var(--ink-2);pointer-events:none} +.chip-zoom[hidden]{display:none} + +/* ---------- 8. print ---------- */ +@media print{ + :root{--obsidian:#fff;--graphite:#fff;--row:#f3f3f3;--line:#bbb;--line-2:#999;--bone:#000;--ink-2:#111;--ash:#444;--ember:#B8390C;--ember-text:#B8390C;--molten-text:#8F5810} + .nav,.foot,.burger,.skip,.cta,.theme,.no-print{display:none!important} + body{font-size:11pt;line-height:1.45;background:#fff;color:#000} + .wrap{max-width:none;padding:0} + a{color:#000;text-decoration:underline} + a[href^="http"]::after{content:" (" attr(href) ")";font-size:9pt;color:#444} + .card,.tbl,.callout,pre{break-inside:avoid;border-color:#bbb} + h1,h2,h3{break-after:avoid} + tr{break-inside:avoid} + canvas{display:none} +} diff --git a/site/wallet.html b/site/wallet.html index 5d67e81a3..e8e0f0918 100644 --- a/site/wallet.html +++ b/site/wallet.html @@ -31,9 +31,10 @@ + + @@ -201,10 +130,9 @@ td.num{font-variant-numeric:tabular-nums;white-space:nowrap} @@ -393,7 +333,7 @@ td.num{font-variant-numeric:tabular-nums;white-space:nowrap}
      - IGNEUM + IGNEUM

      Mined by GPUs. Proven by fire.

      @@ -429,10 +369,23 @@ td.num{font-variant-numeric:tabular-nums;white-space:nowrap}
      Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · hello@igneum.network © 2026 Igneum. Nothing on this page is an offer to sell anything. + igneum.network
      + +
      1 · Race the compiler every hourFor each new program, five to ten kernel variants are compiled, benched for two seconds each, and the winner is kept for the hour.Measured on the Mac's Metal worker: the winning variant +17.3% on the genesis seed and +21.2% on the hourly seed over the base compile, under load from other work. The RTX 5090 race is prepared and not yet run. Log, 4 Oct 2026
      2 · Auto-tune that learns from the fleetApps report the race per card and program class, and every finished Ember Tune. The best settings come back down through the signed update manifest as defaults, so the miner gets faster and more efficient for everyone as the fleet grows.Shipped. The fleet is still small, so no fleet table yet; the priors table on /miners fills as machines report.
      3 · Hash per watt, not hashEmber Tune: two knobs per card (power limit, core clock), the memory clock held, the point with the best MH per watt within 1% of the top rate kept and pinned. Miners pay for electricity; that is the number they compare.Measured on PC 1, 6 Oct 2026: an RTX 5090 from 311.0 W to 226.8 W for 0.15% of its rate (0.411 to 0.563 MH/W); an RTX 4070 from 106.0 W to 75.6 W for none (0.271 to 0.381 MH/W). The chosen clocks are the ladder's floor, not the optimum. AMD through the app's own helper, no prompt; Apple silicon measures only. The table above.
      3 · Hash per watt, not hashEmber Tune: two knobs per card (power limit, core clock), the memory clock held, the point with the best MH per watt within 1% of the top rate kept and pinned. Miners pay for electricity; that is the number they compare.Measured on the Windows rig, 6 Oct 2026: an RTX 5090 from 311.0 W to 226.8 W for 0.15% of its rate (0.411 to 0.563 MH/W); an RTX 4070 from 106.0 W to 75.6 W for none (0.271 to 0.381 MH/W). The chosen clocks are the ladder's floor, not the optimum. AMD through the app's own helper, no prompt; Apple silicon measures only. The table above.
      4 · Template latencySolo against the local node, a new template within 50 ms of a new tip, because a late block on a BlockDAG goes red and earns nothing.Shipped in 0.3.6 (the miner-latency merge; the app is at 0.3.14). Approximate, from the 0.3.6 release plan and not yet in the engineering log: switched p50 46 to 52 ms on a three-node CPU run, 5 Oct 2026.
      5 · Never lose a secondZero-loss hourly program swaps, fault guards, automatic restart, a CPU re-check of every found hash, per-worker health.Shipped. Swap 0.01 ms on Metal and 0.00 ms on CUDA with 0 rejected blocks; recoveries in the table above. Log, 4 Oct 2026
      6 · Prove it in publicThe bench table per card, fed from the job channel. We claim fastest only when the table says so.Live at /miners, one row per card, generator version and miner version, each with its log entry.