From acd6f86cb237d0f03ff425a7c0bfb4e4f2c6a7c5 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:33:16 +0000 Subject: [PATCH] site: rebuilt after fud-a Co-Authored-By: Claude Fable 5.1 --- site/bench.html | 5 ++--- site/index.html | 2 +- site/journey.json | 16 ++++++++-------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/site/bench.html b/site/bench.html index 195d5d2e..a3e0ba23 100644 --- a/site/bench.html +++ b/site/bench.html @@ -496,7 +496,6 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
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

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/.

-

<<<<<<< HEAD

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.

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
@@ -507,7 +506,7 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:

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".

-

Commands: tools/lock/with-lock.sh run node tools/txgen/run.mjs --duration 1200 --rate 2 --wallets 16 --fund 2 --cap 40 --summary <file>; node tools/txgen/proving-watch.mjs watch --interval 30 --duration 1560 --out <jsonl>; node tools/txgen/proving-watch.mjs report --summary <summary.json> --pc2-log <collected app log>; node tools/prove-fixtures/complete-export.mjs seq.json out.json 72803,72854; igneum-prove-export out.json 72803 proving/fixtures/block-72803-skipped-copies.json. =======

+

Commands: tools/lock/with-lock.sh run node tools/txgen/run.mjs --duration 1200 --rate 2 --wallets 16 --fund 2 --cap 40 --summary <file>; node tools/txgen/proving-watch.mjs watch --interval 30 --duration 1560 --out <jsonl>; node tools/txgen/proving-watch.mjs report --summary <summary.json> --pc2-log <collected app log>; node tools/prove-fixtures/complete-export.mjs seq.json out.json 72803,72854; igneum-prove-export out.json 72803 proving/fixtures/block-72803-skipped-copies.json.

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):

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

M1, M16, P14, F16: arithmetic and documents, no run. M1: the version 2 program space from the generator's draws (slot subset 48.4 bits, operation entropy 3.26 bits, about 770 bits of operations and registers per program, about 1,550 with rotation, bit and mask fields, capped by the 256-bit seed). M16: docs/analysis/m16-recompute-attacker-2026-10-05.md. P14: next_base_fee in igneum/exec/src/executor.rs:501 is the one controller; spec 05 section 5.1 now says so. F16: the two options priced from sim/results_v2.md H and M5 and the cloud F21 numbers, in the ledger entry.

C4, the overlay against GHOSTDAG, measured (tools/finality-attacks/c4.mjs, the live node line target-036 2b6d23ef, fast time, 3 nodes, 100-ms proxied links, ports 29800+; "weight against work": side B with four keys and 70% of the weight table, side A with two keys and 30%; at the cut the rates swap, A at 0.6 and B at 0.4 blocks/s for 150 s, so A builds the heavier chain while only B can certify; heal window 200 s). The first run went out with the override unapplied (the harness library reads it at import; fixed the same hour) and is kept as the rule v2 control:

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/. >>>>>>> fud-a

+

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/.

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

diff --git a/site/index.html b/site/index.html index 825637e7..f57ffafe 100644 --- a/site/index.html +++ b/site/index.html @@ -659,7 +659,7 @@ pre{margin:0;font-family:var(--f-mono);font-size:13px;line-height:1.6;color:var( - +