Merge origin/master (974805b) into release-0.3.9: fud-a round 6, the entity imprint, the conflict-marker check; docs/bench-log.md both entries, the site taken from master and rebuilt (519 links, 0 broken)
This commit is contained in:
commit
8b4b1e500a
28 changed files with 869 additions and 86 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -61,6 +61,8 @@ jobs:
|
|||
run: node tools/ci/link-check.mjs
|
||||
- name: identity grep of the public export list
|
||||
run: bash tools/ci/identity-check.sh
|
||||
- name: no conflict markers in tracked files
|
||||
run: bash tools/ci/no-conflict-markers.sh
|
||||
- name: copied sources are re-stamped before a build
|
||||
run: bash tools/ci/copied-sources-check.sh
|
||||
- name: pinned guest programs match their manifest and are built only by pin-guests.sh
|
||||
|
|
|
|||
|
|
@ -14,12 +14,13 @@ Mark description for the device, when a form asks: "A stylised flame formed of t
|
|||
|
||||
## Applicant
|
||||
|
||||
The new UAE steward decided on 3 October 2026, the ADGM DLT Foundation being set up for the name, the domains, the
|
||||
signing key and the client fee income. NOT [other-business]: a [other-business] filing would tie Igneum to VIVA and to its owner
|
||||
through public registers, which the standing rule forbids. The foundation's registered office is the applicant
|
||||
address, with a trademark attorney as the address for service, so no personal address appears anywhere. If the
|
||||
foundation is not incorporated the week you want to file, the attorney can file in the attorney firm's name as nominee
|
||||
and assign on incorporation; ask for that rather than filing under any existing company.
|
||||
Igneum Labs LTD, Licensee Address: Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial
|
||||
Centre (decided 5 October 2026; it replaces the ADGM DLT Foundation named on 4 October). NOT [other-business]: a [other-business]
|
||||
filing would tie Igneum to VIVA and to its owner through public registers, which the standing rule forbids. The
|
||||
registered address above is the applicant address, with a trademark attorney as the address for service, so no
|
||||
personal address appears anywhere. If the company's registration is not complete the week you want to file, the
|
||||
attorney can file in the attorney firm's name as nominee and assign on registration; ask for that rather than filing
|
||||
under any existing company.
|
||||
|
||||
## Classes and specifications (Nice classification, 12th edition wording)
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ UK registration UK00918212492 IGNIUM in classes 9, 36 and 42 (the memo of 3 Octo
|
|||
|
||||
## Order of work
|
||||
|
||||
1. Attorney engaged, with [other-business]'s details and the address for service.
|
||||
1. Attorney engaged, with Igneum Labs LTD's details and the address for service.
|
||||
2. Word mark IGNEUM filed in the UK, EU and US the same week (US on an intent-to-use basis).
|
||||
3. Device mark filed in the UK and EU; US device filing after the word mark is accepted.
|
||||
4. Non-use revocation against IGNIUM if the dates allow.
|
||||
|
|
|
|||
115
docs/analysis/m16-recompute-attacker-2026-10-05.md
Normal file
115
docs/analysis/m16-recompute-attacker-2026-10-05.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# M16: the recompute attacker with the 256 MiB cache on a die, a cost model
|
||||
|
||||
5 October 2026 (evening), FUD ledger sweep round 6. Ledger M16, review R3.5, the chip designer's attack 3.
|
||||
|
||||
The claim: "put 256 MiB of SRAM on a die and the dataset is never needed: 128 items per hash at about 1,170 integer
|
||||
operations and 8 near-free reads each; integer operations per dollar is where silicon beats a GPU."
|
||||
|
||||
This file prices that device from the rules in the specification and the rates measured so far. Nothing here is a
|
||||
measurement of a chip. Every figure says where it comes from; "approximate" marks a figure from memory.
|
||||
|
||||
## 1. What the honest miner pays per hash
|
||||
|
||||
| Quantity | Value | Source |
|
||||
|---|---|---|
|
||||
| Loads per hash | 128 (16 load slots x 8 iterations), every accepted program | `igneum-pow/src/generator.rs` (`LOAD_SLOTS`, `ITERATIONS`), spec 01 section 1.4.2 |
|
||||
| Distinct addresses per hash | 120.05 to 128, median 128.00, over 20,000 accepted programs | 20,000-program census, `docs/bench-log.md` "generator version 2"; `docs/analysis/weak-program-census-2026-10-03.md` |
|
||||
| Bytes per load | 4 (one dataset word) | spec 01 section 1.8.5 |
|
||||
| Dataset | 1 GiB (2^28 words), built once a day from the 256 MiB cache | spec 01 section 1.8.5; CLAUDE.md |
|
||||
| Honest rate, RTX 5090, 1 GiB dataset | 228.95 Mhash/s, 23.8 G random loads/s, 95.2 GB/s useful | `docs/bench-log.md`, "3 October 2026, RTX 5090, memory-hard dataset" |
|
||||
| Honest rate, RTX 5090, 64 MiB dataset (fits the 96 MiB L2) | 1,352 Mhash/s, 5.8x the 1 GiB rate | `docs/bench-log.md`, RTX 5090 dataset sweep (cited in ledger M1) |
|
||||
| Dataset build, RTX 5090 | 13.4 ms for 1 GiB (1,253 M items/s); cache fill 0.67 ms | the same entry |
|
||||
| Projected honest rate for version 2 programs, RTX 5090 | 141 Mhash/s (approximate: 18.0 G distinct loads/s at 128 distinct loads per hash; not yet run) | `docs/bench-log.md`, weak-program census, "Hash-rate spread" |
|
||||
|
||||
The honest hash is 128 dependent random 4-byte reads over a buffer larger than any on-chip cache. The ALU work of
|
||||
the program (64 instructions x 8 iterations per lane) is not what bounds it: the 5.8x step between the 64 MiB and
|
||||
1 GiB datasets on the same card is the memory system, not the arithmetic.
|
||||
|
||||
## 2. What the recompute attacker pays per hash
|
||||
|
||||
The attacker holds the 256 MiB cache (on a die, the premise) and derives each dataset word on demand instead of
|
||||
reading it.
|
||||
|
||||
| Quantity | Value | Source |
|
||||
|---|---|---|
|
||||
| Items per hash | 128 (one dataset item of 16 words per load; two loads in one item share it, so at most 128 and in the census's accepted population about 128) | spec 01 section 1.8.5, `dataset[w] = item(w >> 4)[w AND 15]` |
|
||||
| Mixer applications per item | 9 (`ITEM_ROUNDS = 8` dependent cache reads, nine mixer applications) | spec 01 sections 1.8.4 and 1.8.5 |
|
||||
| Operations per mixer application | about 130 integer operations (16 xor-add-multiply steps and 8 ChaCha quarter rounds on a 16-word state) | spec 01 section 1.8.4 |
|
||||
| Operations per item | about 1,170 | 9 x 130 |
|
||||
| Cache reads per item | 8 dependent 64-byte lines (each address depends on every earlier read) | spec 01 section 1.8.5 |
|
||||
| Operations per hash | about 150,000 (128 x 1,170) | arithmetic |
|
||||
| Cache bytes per hash | 65,536 (128 x 8 x 64) in 1,024 dependent reads | arithmetic |
|
||||
|
||||
Measured on Apple silicon (the only inline kernel run so far): the inline kernel does 9.48 Mhash/s on the M5 Max at
|
||||
both a 256 MiB and a 1 GiB dataset, against 94.8 honest at 256 MiB and 45.2 at 1 GiB (`proto-metal/MEMHARD.md`
|
||||
section 2.2: 10x and 4.8x slower). The same inline kernel under heavy load on 3 October ran 17x slower than honest at
|
||||
a 256 MiB dataset (`docs/bench-log.md`, "R3.26 / M15", M16 note). The Mac's 256 MiB cache sits in DRAM, so its
|
||||
inline kernel is bound by the 1,024 dependent cache-line reads per hash and does not price a die; it only shows
|
||||
the kernel exists and is bit-exact.
|
||||
|
||||
## 3. The die, priced in the GPU's own units
|
||||
|
||||
To match ONE RTX 5090 at its honest 1 GiB rate the attacker's chip must deliver, per second:
|
||||
|
||||
| Need | Value | Arithmetic |
|
||||
|---|---|---|
|
||||
| Integer operations | 34 T op/s | 228.95 M hash/s x 150,000 op/hash |
|
||||
| Cache-line reads | 234 G reads/s, 15 TB/s of SRAM bandwidth | 228.95 M x 1,024 reads x 64 B |
|
||||
| SRAM | 256 MiB, with the next day's cache under construction beside it | spec 01 (the cache is per day) |
|
||||
|
||||
What the GPU itself has (approximate, from memory, for scale): the RTX 5090's integer throughput is about 50 T
|
||||
op/s (21,760 ALUs at about 2.4 GHz, one 32-bit operation each per clock), the figure the ledger entry already
|
||||
carries; on-die SRAM at 256 MiB costs about 100 to 300 mm^2 on a current node (the low end from a 0.02 um^2 bit
|
||||
cell with array overhead, the high end from wafer-scale parts at about 1 MB per mm^2), against a 750 mm^2
|
||||
class GPU die; 15 TB/s of on-die SRAM bandwidth is within what wafer-scale parts quote and is not the bound.
|
||||
|
||||
So, at equal silicon and equal integer throughput, the recompute attacker reaches 50 T / 150,000 = about 0.33
|
||||
Ghash/s:
|
||||
|
||||
| Against | Honest 5090 rate | Attacker gain at equal integer budget |
|
||||
|---|---|---|
|
||||
| Closed-form and version 1 programs as measured | 229 Mhash/s | 1.5x |
|
||||
| Version 2 programs as projected (distinct-load bound) | 141 Mhash/s | 2.4x (the figure in the ledger entry) |
|
||||
|
||||
Before any chip-versus-GPU efficiency factor. A fixed-function pipeline with no instruction scheduling and no
|
||||
warp divergence is usually credited with 2x to 5x over a GPU on integer work (approximate, from memory; the
|
||||
honest target in the ledger is "under 2x"). Taking 3x: 4.5x to 7x over a 5090 at equal die area, minus the area
|
||||
the SRAM takes (13% to 40% of the die), so about 3x to 6x. That is the exposure as the parameters stand, and it is
|
||||
arithmetic, not a measurement.
|
||||
|
||||
## 4. The lever, and why it costs the honest miner nothing
|
||||
|
||||
The attacker's cost is linear in operations per item. The honest miner pays the mixer once per day in the
|
||||
dataset build (2^26 items x 1,170 op = 78 G op, 13.4 ms on the 5090 as measured) and never per hash. The
|
||||
verifier pays it per load it checks (spec 01 section 1.11: the CPU verifier derives the distinct items of a warp
|
||||
from the cache, 0.41 to 1.2 ms per warp with the cache on one M5 Max core, `docs/bench-log.md` 3 October).
|
||||
|
||||
| Mixer cost multiplier m | Operations per hash | Attacker rate at 50 T op/s | Gain against 229 Mhash/s (equal silicon, no efficiency factor) | Gain with a 3x fixed-function factor | Honest daily dataset build, 5090 | CPU verify per warp (scaled from 0.41 to 1.2 ms) |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 (today, 1,170 op/item) | 150,000 | 0.33 Ghash/s | 1.5x | 4.4x | 13.4 ms | 0.4 to 1.2 ms |
|
||||
| 2 | 300,000 | 0.17 Ghash/s | 0.73x | 2.2x | 27 ms | 0.8 to 2.4 ms |
|
||||
| 4 | 600,000 | 0.083 Ghash/s | 0.36x | 1.1x | 54 ms | 1.6 to 4.8 ms |
|
||||
| 8 | 1,200,000 | 0.042 Ghash/s | 0.18x | 0.55x | 107 ms | 3.3 to 9.6 ms |
|
||||
| 16 | 2,400,000 | 0.021 Ghash/s | 0.09x | 0.27x | 214 ms | 6.6 to 19 ms |
|
||||
|
||||
Reading. The mixer cost is the one parameter that moves the recompute attacker and leaves the honest hash rate
|
||||
untouched; it is bounded by the 10 ms CPU verification gate (ledger M9, spec 1.16), which at today's verify time
|
||||
allows about 8x before the slow core of the gate (a 2019-class laptop core, unmeasured, O-1.14) is at risk. The
|
||||
cache size is the other lever and is linear in SRAM area, which is the cheaper side for the attacker: 256 MiB to
|
||||
1 GiB moves the die from about 100 to 300 mm^2 to 400 to 1,200 mm^2, which is a multi-die part. Both are
|
||||
prototype values of spec 1.16, fixed at gate 1.
|
||||
|
||||
## 5. What this does not settle
|
||||
|
||||
1. The inline kernel on NVIDIA at a 64 MiB cache inside the 5090's 96 MiB L2 (the on-die SRAM emulation the
|
||||
ledger entry names) has not run; it is a PC job. It would put a measured point under the "50 T op/s" row: the
|
||||
rate a real integer engine reaches on the actual mixer with the cache in SRAM-class memory.
|
||||
2. The time-memory curve (O-1.6: store a fraction f of the dataset, recompute the rest) is not drawn; the model
|
||||
above is the f = 0 endpoint. A partial-store attacker with HBM instead of SRAM is a different device and may be
|
||||
the cheaper one.
|
||||
3. The mixer has had no cryptanalysis (spec 1.8.4, `MEMHARD.md` section 3); a shortcut inside the mixer would cut
|
||||
the 1,170 directly.
|
||||
4. Monero's seven years do not price this device (ledger C13).
|
||||
|
||||
Decision at gate 1 (owner: the project lead): the cache size rule "exceeds what one die can hold, and grows", and the mixer
|
||||
cost multiplier, against the CPU verify gate.
|
||||
|
|
@ -1450,3 +1450,77 @@ The adopted fee table (spec 05 section 5.11) reaches the devnet by `fees_v1_acti
|
|||
| The new pin | `proving/igneum-prove/pin-guests.sh` | shard 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 (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 Mac 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 07:33 BST (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`):
|
||||
|
||||
| Line | PC 1 | PC 2 | Mac | Sam's Mac | US laptop | Reads on |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `Finality: state blob of layout 1 read and converted` | 1 | 1 | 1 | 1 | 1 | F23 (persisted state migrated, no locks lost) |
|
||||
| certificates refused "names N voters" | 0 | 0 | 0 | 0 | 0 | F23 |
|
||||
| CONFLICTING, EQUIVOCATION | 0, 0 | 0, 0 | 0, 0 | 0, 0 | 0, 0 | F23, F24 |
|
||||
| `re-determined` (checkpoints 2970 and 2971 at 10:56 BST on three machines at once; the rest at first start) | 7 | 8 | 4 | 0 | 1 | F24 |
|
||||
| LOCKED | 1,198 | 1,204 | 1,197 | 683 | 961 | all |
|
||||
| `Consensus params digest` at start | f10a4eab... | f10a4eab... | f10a4eab... | f10a4eab... | f10a4eab... | X18, G12 |
|
||||
| `consensus params digest mismatch` (08:15 to 08:35 BST, the hand node restarted early with another proving height) | 115 | 46 | 56 | 0 | 0 | X18 |
|
||||
| `PoW cache built` (each at a node start; none at the epoch rolls of 14:29 and 15:29 UTC) | 5 | 5 | 8 | 1 | 5 | M30 |
|
||||
|
||||
M31 and M20 have no live line yet: no simnet or testnet node has been started since the cut, and the Mac 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):
|
||||
|
||||
| Machine | Compiler | Boundaries | Swapped with no pause | Compiled inline | Prepare total min / median / max | Notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| PC 1, RTX 5090 | NVRTC 12.8 | 10 | 10 | 0 | 656 / 684 / 1,074 ms (nvrtc 151 to 180 ms) | |
|
||||
| PC 1, Radeon integrated | OpenCL | 10 | 8 | 2 | 55.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 5090 | NVRTC 12.8 | 12 | 12 | 0 | 580 / 613 / 1,022 ms | |
|
||||
| PC 2, Radeon integrated | OpenCL | 12 | 12 | 0 | 6.9 / 9.4 / 11.7 s | |
|
||||
| US laptop, Intel UHD | OpenCL | 7 | 7 | 0 | 7.3 / 7.9 / 11.7 s (build 3.0 to 6.4 s) | |
|
||||
| Mac M5 Max | Metal | 8 | 8 | 0 | 34.0 / 34.9 / 37.8 s (program 0 to 444 ms; the rest is the hourly race) | |
|
||||
| Sam's Mac M4 Max | Metal | 1 | 1 | 0 | 40.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):
|
||||
|
||||
| Run | Variants timed | Winner | Base MH/s | Gain | Spread across the 17 | Compile for 17 | Timing |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 1 | 17 of 17 (none discarded, self-test PASS) | base, 31 registers, 24 blocks per SM at 1 warp per block | 139.746 | +0.00% | 137.75 (`ldcs`, -1.4%) to 139.75 | 300 ms | 112.2 s |
|
||||
| 2 | 17 of 17 | base | 139.654 | +0.00% | 137.70 to 139.69 | 232 ms | 112.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):
|
||||
|
||||
| Load | Viewport | Genuine, cold | Genuine, warm | Tampered cases (5 of 7 rejected inside 40 ms, the signature cases 36 to 71 ms) |
|
||||
|---|---|---|---|---|
|
||||
| 1 | mobile | 139.1 ms | 68.3 ms | all 7 rejected with the expected reason |
|
||||
| 2 | mobile | 150.2 ms | 58.4 ms | same |
|
||||
| 3 | mobile | 155.3 ms | 64.8 ms | same |
|
||||
| 4 | desktop | 151.0 ms | 63.3 ms | same |
|
||||
|
||||
What is measured: one BLS12-381 aggregate signature over 16 summed G1 keys plus 21 BLAKE2b header hashes in pure JavaScript. What is not: a phone (this is the laptop's CPU whatever the viewport says) and the wrapped block proof (no wrapper exists; the light verifier of the compressed SP1 proof needs 1.3 to 2.1 s of setup on this Mac, bench-log "the program id split").
|
||||
|
||||
**M21, block sizes on the live devnet** (Mac node wRPC, the last 60 chain blocks at DAA 112,433, bytes summed from the RPC fields, approximate serialisation): p50 723 B, p90 1,022 B, max 6,908 B (a block carrying a certificate), 1 transaction per block, coinbase payload p50 395 B and max 6,580 B. k from the fork's `calculate_ghostdag_k` (delta 0.01, x = 2 D at 1 block/s), ported to Python and checked against the sweep's table (D 5 s gives 18):
|
||||
|
||||
| D (s) | 0.343 (cloud p50) | 0.497 (p90) | 0.666 (p99) | 0.8 (p99 plus 3 hops of a 500 KB body at 100 Mbit/s) | 1.0 | 2.0 | 2.313 (cloud max) | 5.0 (Kaspa) | 10.0 |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| k | 3 | 4 | 5 | 6 | 6 | 9 | 10 | 18 | 31 |
|
||||
|
||||
**X5, the vote-key window** (Mac node `getFinalityWeights` at DAA 112,395): 22 keys, 21 voters above dust, total 7,196 of 7,200 blue blocks; top-1 8.3%, top-3 20.3%, top-5 31.9%, top-10 60.3%; 5 machines on the console, so 4.2 keys per machine. **P9** (`igneum_getProvingStatus`, 16:00 UTC): 352 shards paid, pool 19 entries, 0 failed, 0 pending, 154 verified, 8 assignees, exclusive window 10 DAA, record window 600, `S_p` 7,500,000, dust 5, window 7,200.
|
||||
|
||||
**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:
|
||||
|
||||
| Run | Rule | New locks during the split A / B | First lock A / B (s) | Blue score A / B at the heal | Sinks after the heal | Final chain | Conflicting certificates | Disagreeing locked indices |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| control | v2 (the live devnet's rule), `min_daa` 120 | 4 / 3 | 133 / 9 | 335 / 296 | apart (n0 on its own) | none (a finality fork, F21) | 1 on n0 | 1 |
|
||||
| off | no certificates (`min_daa` never) | 0 / 0 | none / none | 330 / 301 | one sink on all three | A's (the heavier) | 0 | 0; B's nodes re-determined 2 indices onto A's chain; n0 reconnected 36 s after the heal |
|
||||
| on, split 150 s | v3 from checkpoint DAA 0 | 0 / 2 | none / 39 | 326 / 313 | apart | none | 3 on n0 | 2 (n0 reconnected 66 s after the heal, A's chain past the 120-DAA table by then) |
|
||||
| on, split 90 s | v3 | 0 / 2 | none / 3 | 278 / 265 | apart | none | 3 on n0 | 2 (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, 17:27:04 to 17:29:54 BST). 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/`.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
Four rules for reading the table:
|
||||
|
||||
1. Nothing on this chain has been reproduced externally or reviewed independently. Every row's last column says "none yet". The repository is private until January 2027 (`site/journey.json`), so the first three labels are the ceiling today.
|
||||
1. Nothing on this chain has been reproduced externally or reviewed independently. Every row's last column says "none yet". The repository is private until the public testnet (decision of 5 October 2026), so the first three labels are the ceiling today.
|
||||
2. A status applies to the exact version in the row. An audit of one version never covers a newer one; when the version changes, the status falls back to "tested by the team" until the new version is reproduced or reviewed again.
|
||||
3. "Tested by the team" on one machine is one machine. The rows say which. Discrete AMD, Intel and a 2019-class CPU core have not run anything.
|
||||
4. The 12-node cloud network of 4 October 2026 (`infra/cloud-devnet`, Hetzner VMs in five locations) is the project's own. Rows that cite it are tested by the team, not reproduced externally.
|
||||
|
|
@ -94,6 +94,6 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml`
|
|||
|---|---|---|
|
||||
| designed | implemented | Code in this repository with test vectors that pass |
|
||||
| implemented | tested by the team | A bench-log entry with the machine, the date, the command and the number |
|
||||
| tested by the team | reproduced externally | The repository public (January 2027), the command published, and a third party's run with the same result, linked from the row |
|
||||
| tested by the team | reproduced externally | The repository public (at the public testnet), the command published, and a third party's run with the same result, linked from the row |
|
||||
| reproduced externally | reviewed independently | A named reviewer's published finding on that version. Funding for review is `docs/plans/funding.md` |
|
||||
| any | the row's status falls back | A new version of the code or rule the row names |
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Internal working list. Written 3 October 2026 against `docs/fud-ledger.md` version 0.1, `docs/spec/06-open-items.md`, `docs/bench-log.md`, and the public text in `site/index.html` (HP), `site/litepaper.html` (LP) and `site/journey.json` (J) as checked this evening. The ledger itself is not changed by this file. Entries are referenced by ledger id; overclaims by item number.
|
||||
|
||||
Decisions of 3 October 2026 applied throughout: (a) no development fund, priority fee 80% to miners and provers and 20% to the called app, external jobs 90% to provers and 10% burned; (b) the ledger is internal; (c) the project is established offshore and the founder's location is never mentioned; (d) deSEC nameservers now, a non-US registrar in December 2026; (e) the dedicated identities exist (GitHub organisation igneum-network with one anonymous owner, Vercel team igneum, Google Workspace on igneum.network).
|
||||
Decisions of 3 October 2026 applied throughout: (a) no development fund, priority fee 80% to miners and provers and 20% to the called app, external jobs 90% to provers and 10% burned; (b) the ledger is internal (superseded 5 October 2026: the ledger is published with the repository at the public testnet); (c) the project is established offshore and the founder's location is never mentioned; (d) deSEC nameservers now, a non-US registrar in December 2026; (e) the dedicated identities exist (GitHub organisation igneum-network with one anonymous owner, Vercel team igneum, Google Workspace on igneum.network).
|
||||
|
||||
## 1. Summary
|
||||
|
||||
|
|
@ -12,14 +12,14 @@ Decisions of 3 October 2026 applied throughout: (a) no development fund, priorit
|
|||
4. Answered: 16 entries. All 16 still carry a wording fix, an experiment or a counsel check.
|
||||
5. Overclaims: 78 items. 10 already fixed (5, 6, 9, 22, 23, 27, 38, 40, 47, 71), 3 partly fixed (11, 31, 75), 65 still present or still missing. Item 23 is fixed but stale. Item 73 must not be applied as written.
|
||||
6. The 3 October decisions close E4 outright, narrow G4, G8 and L3, and change E3, E5, G3 and G5 (section 4). The dev fund removal forces a rewrite of 11 places in the site, spec and design files (row 7).
|
||||
7. EXPOSES: six items. CLAUDE.md (full name, other companies, registrar, database region, personal GitHub handle), the cryptographer agent file, the commit handle igneum-labs, the +0100 timezone on every commit, the earlier ledger text "The founder is in the UK" still in git history, and the ledger itself in the tree. All are fixed in section 5.
|
||||
7. EXPOSES: six items. CLAUDE.md (full name, other companies, registrar, database region, personal GitHub handle), the cryptographer agent file, the commit handle igneum-labs, the local-time offset on every commit, the earlier ledger text "The founder is in the UK" still in git history, and the ledger itself in the tree. All are fixed in section 5.
|
||||
8. Measured since the ledger was written: the 256 MB cache dataset is built and bit-exact on Apple, NVIDIA (CUDA and OpenCL) and an AMD integrated chip; the shortcut is 4.8x slower than honest on Apple; CPU verify is 0.41 to 1.2 ms per warp with the cache; the VDF grinding simulation ran. Items 16, 20, 21, 23, 56 and 78 need these facts, not the ledger's replacements.
|
||||
9. By timing: 44 rows now (site text, decisions, accounts; two of them continue into December and mainnet), 12 before the repository goes public (citations, counsel, gate 1 measurements, the phase 2 benchmark), 16 before public testnet (gate 2 and 3 work, policies), 1 before mainnet, 1 with nothing further (F6).
|
||||
10. Five most urgent: section 5 steps 1 to 4 (the tree and history must be clean before any public push); rows 1 to 5 (dead links, the miner button, no contact route, listings, Day one); row 7 (dev fund text everywhere); row 9 (the founder is pseudonymous now, the text and the ledger disagree); rows 43 to 46 (trademark and counsel).
|
||||
|
||||
## 2. Every open or conceded entry
|
||||
|
||||
Who: the project lead (decision or account), Claude (text, spec, code, simulation), counsel, measurement (an experiment that produces a number). When: now, before public repo (January 2027 with the benchmark), before testnet (August 2027), before mainnet (November 2027).
|
||||
Who: the project lead (decision or account), Claude (text, spec, code, simulation), counsel, measurement (an experiment that produces a number). When: now, before public repo (opens at the public testnet, August 2027), before testnet (August 2027), before mainnet (November 2027).
|
||||
|
||||
| # | Ledger | Issue | Fix | Who | When | EXPOSES |
|
||||
|---|---|---|---|---|---|---|
|
||||
|
|
@ -31,7 +31,7 @@ Who: the project lead (decision or account), Claude (text, spec, code, simulatio
|
|||
| 6 | L2 (with E2) | Inducement wording: "so the people who show up early get the most" (LP 183), chart caption "Half of the 4 billion cap is mined in the first two years" (LP 184), HP "Half of all IGN is mined in the first two years" | Items 54 and 76: schedule facts, no "so" clause. Counsel opinion is row 46 | Claude | now | no |
|
||||
| 7 | E4, E5, G5, G8, O-5.4 | Dev fund text everywhere after decision (a): LP Economics (65/15/15/5 paragraph, "Development, paid by outsiders" section), LP Governance (fund bullet, second-client bullet), LP firsts row ("a development fund paid by outsiders"), HP Economics ("Development is paid from fees..."), spec 05 sections 5.2, 5.4, 5.5 and the self-dealing arithmetic, spec README row 5, spec 00 row 5, spec 06 items O-5.4 and O-5.7, docs/design/execution-layer.md lines 143, 210 and 217, the design document (CLAUDE.md already carries the new split) | Rewrite to: base fee burned in full; priority fee 80% miner and provers, 20% called app; external jobs 90% prover, 10% burn; no fund. the project lead confirms the 15% priority-fee burn is gone on purpose (section 4) | Claude, the project lead confirms | now | no |
|
||||
| 8 | E5 | HP "Not one coin to a founder, a fund or a stake" while the official client carries a 1% dev fee to the founder's company; LP spreads the dev fee, the pool and the proving business over three sections | Item 62 on HP. One LP heading that holds the 1% dev fee, the pool, the proving business, and that these now fund development since there is no fund | Claude | now | EXPOSES: "the founder's company" must be the offshore entity once it exists, never a company the project lead already owns |
|
||||
| 9 | G3 | The ledger's answer says "The founder's name is on every commit". Decisions (c) and (e) make the founder pseudonymous | Do not apply item 73 as written. LP "Who are you?" gets: "The founder is pseudonymous until the team page at public testnet. No cryptographer is hired yet." the project lead re-confirms whether the team page at public testnet names anyone | the project lead decides, Claude writes | now | EXPOSES: the ledger answer and CLAUDE.md name the founder; see section 5 |
|
||||
| 9 | G3 | The ledger's answer says "The founder's name is on every commit". Decisions (c) and (e) make the founder pseudonymous | Do not apply item 73 as written. LP "Who are you?" gets: "The founder is pseudonymous until the team page at public testnet. No cryptographer is hired yet." Decided 5 October 2026: no team page for now; the litepaper says the team is pseudonymous and names no team page | the project lead decides, Claude writes | now | EXPOSES: the ledger answer and CLAUDE.md name the founder; see section 5 |
|
||||
| 10 | F5 | "whole network's hashrate" misread | Item 32 | Claude | now | no |
|
||||
| 11 | F10, F4, G8 | Pool concentration unstated; LP heading "Speed and finality, powered by miners alone" | Items 33 and 43. Heading becomes "Speed and finality, a miner-weighted overlay on proof of work". Name pool concentration as the governance risk | Claude | now | no |
|
||||
| 12 | C3, M3, C8, C11 | Kaspa misstated; firsts table; LP 68 "taken over by chips, as Kaspa was" still reads as capture; Conflux missing from the problem section | Apply items 4, 7, 8, 10, 11 and 29. Items 5, 6, 9 and 47 are done | Claude | now | no |
|
||||
|
|
@ -163,6 +163,32 @@ Added after `docs/review/external-2026-10-03.md`. Rows continue the numbering of
|
|||
| 102 | X17 | Client shows gross earnings only; no mining and proving split, no failed jobs, no isolation design | O-8.2 display rules (client and phone-app 4.1, written 3 October 2026 night); O-8.3 isolation design before the first external job; update control already spec 8.2 item 4 | Claude (design); miner client (code) | before testnet | no |
|
||||
| 103 | M22 | Bounty has no metric, judge, eligible hardware or fund; 2x is not the economic line | Scoring rules (per-program distribution of hash/s and hash/J, capital per unit of hash rate, longevity, shortcut classes) published with the benchmark; funder, judge and reward are the project lead's; public claim limited to "competitive against the best independently proposed design across tested workloads" | Claude (rules), the project lead (fund) | before public repo | EXPOSES: the payer is the entity (row 50) |
|
||||
|
||||
### 2.6 Sweep (5 October 2026, evening), round 6: the experiment and status items
|
||||
|
||||
Appended by the consensus engineer and cryptographer agent (worktree `igneum-wt-fud-a`); the wording items of the same evening are the other agent's section. Rows below name the earlier row they touch; nothing above is rewritten. Evidence in `docs/bench-log.md`, "5 October 2026 (evening), FUD ledger sweep round 6".
|
||||
|
||||
| Row touched | Ledger | What changed (5 October 2026, evening) | Who next | When |
|
||||
|---|---|---|---|---|
|
||||
| 106 | G12, X18 | Done and rolled out (0.3.5, 07:33 BST; every node prints the digest, the digest refused the early-restarted hand node for 20 min at 08:15 BST). Left: the digest-less allowance on devnet and simnet, `rollout-v2.sh` two-field write | consensus engineer | before testnet |
|
||||
| 107 | F23, F24 | Done and rolled out (0.3.5): 0 "names N voters" refusals and 0 CONFLICTING on five machines in 10 h; checkpoints 2970 and 2971 re-determined on three machines at 10:56 BST with no hole | none | done |
|
||||
| 108 | M26, M27, X21 | Done and rolled out (0.3.5): the 0.3.4 prepare storm (4,299 refusals in 2 h on PC 1) ended at the 0.3.5 start, 0 `prepare-failed` since; cards read `mismatched=0 faults=0`. Left: the edited-kernel red-card test on a PC | miner lead | when convenient |
|
||||
| 117 | M20 | Done and rolled out (0.3.5, `m20-pruning`, 4 tests). Left: the live test, a fresh node syncing once the pruning point leaves genesis (still genesis at DAA 113,289 at 16:00 UTC) | consensus engineer | tonight or tomorrow, when the point moves |
|
||||
| 2.5 (M30, "the flood memory growth") | M30 | Done and rolled out (0.3.5): cache builds equal node restarts (5 / 5 / 8 in 10 h), none at the epoch rolls | none | done |
|
||||
| (F25) | F25 | Done and rolled out (0.3.5 merge 7abce72); both harness libraries ran tonight | none | done |
|
||||
| (F21, F22) | F21, F22 | Shipped in every node since 0.3.4; the switch `finality_v3_activation_daa` is absent from the live override file. Rollout = N3 of `docs/plans/finality-v3-rollout-devnet.md` | the project lead (N3), then the operator steps | now |
|
||||
| 50 | M1 | Program space counted (about 2^1550 shapes under a 2^256 seed; the per-program spread is 1.10x under version 2). The claim stays a target; the experiment stays the bounty and benchmark | the project lead (M22 terms), Claude (benchmark) | before public repo |
|
||||
| 60 | M11 | Measured on five machines, four compilers, three vendors over 10 to 12 boundaries each: NVRTC 0.6 to 1.1 s, OpenCL 7 to 12 s (iGPU 55 to 124 s beside builds), Metal under 0.5 s plus the race; 5090 race +0.00%, base twice. Left: multi-card rig, ROCm (hardware) | measurement (O-1.16) | before testnet |
|
||||
| 55 | M16 | Cost model written (`docs/analysis/m16-recompute-attacker-2026-10-05.md`): 1.5x to 2.4x at equal integer budget, 3x to 6x with a fixed-function factor, the mixer-cost lever. Left: the 64 MiB-cache inline kernel on the 5090 (PC job), O-1.6 | measurement; the project lead at gate 1 | before public repo |
|
||||
| 121 | M21 | Block sizes measured (p50 723 B, max 6.9 KB); k 5 at the measured p99, 6 with 500 KB bodies, 18 at 5 s. Left: O-2.2 with proof-bearing bodies | consensus engineer | before testnet |
|
||||
| 57 | P3 | The certificate half measured in a phone-sized tab (139 to 155 ms cold, 58 to 68 ms warm, on the laptop's CPU; no phone); the wrapper is unbuilt | measurement (phase 2) | before public repo |
|
||||
| 69 | P9 | Parameter table written from the live numbers (8 assignees, window 10 DAA s today, 25 s proposed, no shard bond, 120-s job claim timeout, `S_p` 30,000 at v1). Left: O-5.1 and O-5.6 values on the phase 4 devnet | the project lead (values), measurement | before testnet |
|
||||
| (P14) | P14 | Fixed in spec 05 section 5.1: one controller, the EIP-1559 step of `next_base_fee`. Left: design 4.1's "smoothed" phrase; R1 band, R8 | execution engineer | when convenient |
|
||||
| (F16) | F16 | Two options priced, B recommended (never withdraw, as 3.11.4). Left: replace the 3.5 paragraph, `finality_conflict` in the node, the forced double-certificate test | the project lead (gate 3), consensus engineer | before testnet |
|
||||
| 73 | X5 | Measurement defined: N_ind = distinct (ASN, machine fingerprint, pool attestation) classes among keys above dust; today N_ind by fingerprint is 5 for 21 keys. Left: the observer's ASN and fingerprint columns, the pool statement format | Claude (observer), the project lead (definition) | before testnet |
|
||||
| 65 | C4 | The overlay measured against bare GHOSTDAG on the same binary (`tools/finality-attacks/c4.mjs`): see the ledger entry and the bench-log table | cryptographer | before testnet |
|
||||
| 43, 44, 46, 58 | L1 to L5 | Untouched; decision owner line added (the project lead, with counsel) | the project lead, counsel | as rowed |
|
||||
| 9 | G3 | Untouched; decision owner line added (the project lead) | the project lead | now |
|
||||
|
||||
## 3. Overclaims still in public text today
|
||||
|
||||
Checked against the files this evening. "present" means the quoted text is still live. "missing" means the item is an addition that has not been made. "fixed" means the replacement is in. Line numbers are from the stripped page text, not the HTML.
|
||||
|
|
@ -264,7 +290,7 @@ Added after `docs/review/round-4-2026-10-04.md`. Rows continue the numbering of
|
|||
| 111 | M29 | LP 424 describes earnings in currency, a hardware wallet and proving the app does not have | Rewrite to 0.3.3; earnings, currency and the hardware wallet become a roadmap sentence | Claude | now | no |
|
||||
| 112 | F21 | LP 511 says a third of the blocks is needed to split finality in a partition | The round-4 section 1 (b) sentence | Claude | now | no |
|
||||
| 113 | X24, X25, X26, X27 | Token in the URL path and printed; agent self-installs at every start; permanent feed with the dl token in bodies; free-text `from` and no clean rotation | Header token in every client, HSTS, masked prints; arm only on `reboot_continue`; retention and a cap; sender binding; documented rotation (3 h) | relay owner | now | no |
|
||||
| 114 | G14 | The intake key (8 commits), the dl token (1), the review files, 51 files with the first name, `+0100` stamps | Section 5 step 4's rewrite list extended; `TZ=UTC` now | the project lead, Claude | before public repo | EXPOSES: yes, the whole row |
|
||||
| 114 | G14 | The intake key (8 commits), the dl token (1), the review files, 51 files with the first name, local-time stamps | Section 5 step 4's rewrite list extended; `TZ=UTC` now | the project lead, Claude | before public repo | EXPOSES: yes, the whole row |
|
||||
| 115 | X19, X20, M25, M28, X22, X28, X29, E17 | The minors of round 4 (node knobs and silences, cold-sync cost, miner day length, kernel commitment, restart paths, relay hygiene, host and file modes, unlogged economics inputs) | As each ledger entry says; the stray token-named file and the 0644 modes today | consensus engineer, miner-community-lead, relay owner, Claude | when convenient | no |
|
||||
| 116 | X30 | Bench page private strings; /api/live addresses, key hashes, payout addresses; the mobile menu | Fixed 4 October 2026: `ac89a37`, `6b644a6`, `2d8f09c`, `621f5cc` | Claude | done | no |
|
||||
|
||||
|
|
@ -314,23 +340,25 @@ Changed, not closed:
|
|||
- G5 (second client): "funded from the development fund as its first priority" has no funder. Row 47.
|
||||
- G3 (who are you): the anonymous founder is now the design, not a flaw to rebut. The ledger's "The founder's name is on every commit" is void. Row 9. The team-page-at-testnet decision needs re-confirming.
|
||||
- L1 and L2 (counsel): "offshore, parked" and "jurisdiction not yet named" become "offshore, being established", which is a jurisdiction counsel can be briefed in. Not closed until the opinion exists.
|
||||
- The ledger header ("Published alongside the litepaper") and its submission paragraph are now wrong under (b). The ledger is not changed by this file; the project lead edits those two lines when he next touches it.
|
||||
- The ledger header ("Published alongside the litepaper") and its submission paragraph are now wrong under (b). Both lines were rewritten on 5 October 2026 under the later decision: published with the repository at the public testnet, submissions to hello@igneum.network or the repository issues.
|
||||
- Decision (e) makes CLAUDE.md stale: it still says the Vercel project lives in the [other-business] team (moved per commit 61aa946) and lists two organisation owners. Section 5 step 2.
|
||||
|
||||
Text the decisions force, beyond the overclaims list: row 7 lists every file. The design document is the eleventh place and the only one outside the repository.
|
||||
|
||||
## 5. Before the repository goes public, in order
|
||||
|
||||
Nothing below is optional. The history, not just the working tree, carries the names: CLAUDE.md with the full name is in every commit, the ledger's earlier L2 text ("The founder is in the UK") is in the commits before 14ef6b3, and site/ledger.html (636 lines, the full ledger rendered) is in the commits before the same one. The commit author and committer on every commit is igneum-labs, and every commit carries a +0100 offset, which is UK or Irish summer time in early October. A file edit fixes none of that.
|
||||
The repository goes public at the public testnet (decision of 5 October 2026). The ledger and this file are published with it.
|
||||
|
||||
1. Move the ledger out of the tree. `docs/fud-ledger.md` is internal (decision b) and it maps the providers (GoDaddy, Vercel), names `.claude/agents/`, and says the founder's name is on every commit. Move it to a private location outside the repository (or a private repo) and add `docs/fud-ledger.md` to `.gitignore`. Keep this file (`docs/fud-fixes.md`) with it: it names the same things. The spec and the open-items file cite ledger ids (M7, F1, P8 and so on); those ids survive without the file and need no change.
|
||||
Nothing below is optional. The history, not just the working tree, carries the names: CLAUDE.md with the full name is in every commit, the ledger's earlier L2 text ("The founder is in the UK") is in the commits before 14ef6b3, and site/ledger.html (636 lines, the full ledger rendered) is in the commits before the same one. The commit author and committer on every commit is igneum-labs, and every commit carries a local-time offset one hour ahead of UTC, which is UK or Irish summer time in early October. A file edit fixes none of that.
|
||||
|
||||
1. Keep the ledger in the tree and publish it with the repository (decision of 5 October 2026, which replaces decision b). `docs/fud-ledger.md` and this file (`docs/fud-fixes.md`) are on the public export list of `tools/ci/identity-check.sh`; every hit the check finds in them is reworded before the first public push, and no entry is removed. The ledger still maps the providers (GoDaddy, Vercel) and names `.claude/agents/`; the private export rules cover the founder's name, and the rest is reworded in place. The spec and the open-items file cite ledger ids (M7, F1, P8 and so on); those ids do not change.
|
||||
2. Rewrite CLAUDE.md as a public file. Remove: line 4 ("the project lead's project"); every "the project lead" (lines 22, 34, 39, 41, 46, 48, 52; "the project lead's copy law" becomes "the copy law"); line 42 (the second owner [second-owner-login], "the project lead, the igneum.network Google login", the sentence about 40 commits carrying his name); line 43 ([other-business] team; it is the igneum team now); line 44 (Neon id and London region); lines 46 to 49 (registrar, "Full Protection", the purchase quotes; after December the registrar changes anyway); lines 51 to 53 (the browser-profile section names every other business: [other-business], QUANTUM, [other-business], [other-business], [other-business], [other-business]); the claude.ai artifact and doc links in "Source of truth" (they identify the tooling account). Move the operational notes (accounts, registrar, database id, browser profile, deploy scope) to a file outside the repository, for example `~/.config/igneum/NOTES.md`.
|
||||
3. Scrub `.claude/agents/cryptographer.md` line 32 ("unless the project lead overrides" becomes "unless the project lead overrides"). The other three agent files are clean. Decide whether `.claude/agents/` stays public at all; if it does, it is the G2 disclosure and consistent with row 29.
|
||||
4. Rewrite the history once, before the first public push. Nothing is public and nobody has cloned, so the cheapest safe route is to squash to one root commit ("Igneum: public tree") authored by a neutral handle at a UTC timestamp. If the history is kept instead, run git filter-repo to: drop `docs/fud-ledger.md`, `docs/fud-fixes.md` and `site/ledger.html` from every commit; replace CLAUDE.md and the agent file in every commit with the scrubbed versions; rewrite every author and committer to the neutral handle; rewrite every date to +0000. Either way: rename the GitHub account igneum-labs to a handle without a name (the noreply address keeps its numeric id, so the rename is one setting), confirm [second-owner-login] is no longer an organisation owner (decision e says one anonymous owner), and set `TZ=UTC` in whatever script commits from now on so no new +0100 appears.
|
||||
4. Rewrite the history once, before the first public push. Nothing is public and nobody has cloned, so the cheapest safe route is to squash to one root commit ("Igneum: public tree") authored by a neutral handle at a UTC timestamp. If the history is kept instead, run git filter-repo to: drop `site/ledger.html` from every commit; replace CLAUDE.md, the agent file, `docs/fud-ledger.md` and `docs/fud-fixes.md` in every commit with the scrubbed versions; rewrite every author and committer to the neutral handle; rewrite every date to +0000. Either way: rename the GitHub account igneum-labs to a handle without a name (the noreply address keeps its numeric id, so the rename is one setting), confirm [second-owner-login] is no longer an organisation owner (decision e says one anonymous owner), and set `TZ=UTC` in whatever script commits from now on so no local-time offset appears again.
|
||||
5. Check the organisation and the account profiles: no location, no personal avatar, no personal email, 2FA on, the organisation's public members list empty. The Vercel team igneum and the Workspace are not visible from the repository; nothing to do there beyond step 2.
|
||||
6. Add a LICENSE and a root README. Neither exists (`git ls-files` shows no root README or LICENSE). A public repository without a licence invites the first issue to be about the licence. the project lead picks the licence.
|
||||
7. Re-run the sweep from this evening on the final tree: `git ls-files | xargs grep -nIE "[user]|[removed]|london|[other-business]|[other-business]|[other-business]|quantum|godaddy|soft-voice|/Users/"` must return nothing, and `git log --format='%an %ae %cn %ce %ad'` must show one neutral identity and +0000 only. Secrets: the history grep for connection strings and tokens returned zero hits today; repeat it after the rewrite.
|
||||
7. Re-run the sweep from this evening on the final tree: `git ls-files | xargs grep -nIE -f igneum-public/tools/identity.local` (the private identity list, case-insensitive) must return nothing, and `git log --format='%an %ae %cn %ce %ad'` must show one neutral identity and +0000 only. Secrets: the history grep for connection strings and tokens returned zero hits today; repeat it after the rewrite.
|
||||
8. Fix the public text first (rows 1 to 41). The ledger's X1 answer is that the honest route is to open the repository with the bench logs, the simulator and the test report. Opening it with "no chip can ever" still on the homepage hands the first critic the ledger's own list.
|
||||
9. Put the GitHub links back on HP and the /bench page (row 1) on the day the repository opens, with the January 2027 benchmark.
|
||||
9. Put the GitHub links back on HP and the /bench page (row 1) on the day the repository opens, at the public testnet.
|
||||
|
||||
What is already clean: `docs/bench-log.md` and the /bench page name machines, not people (commit 1769eda); the live site returns 404 for everything under `docs/` and 307 for `/ledger`; `site/.env.local`, `site/.vercel/` and `vendor/` are ignored; no tracked file carries a home-directory path; no connection string or token appears anywhere in the history.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Igneum FUD ledger
|
||||
|
||||
Version 0.1, 3 October 2026. A living document. Published alongside the litepaper.
|
||||
Version 0.1, 3 October 2026. A living document. Published with the repository at the public testnet (decision of 5 October 2026).
|
||||
|
||||
## What this is
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ Statuses used:
|
|||
| Conceded | The critic is right. "Stated" means the litepaper already says so; "not yet stated" means the litepaper must change, and the fix is in the overclaims list at the end |
|
||||
| Closed by rule, Decided, Closed by removal | A rule now in `docs/spec/`, a decision by the project lead, or a removal answers it as of the date given, and the spec section is named. The status it replaced is kept on the line |
|
||||
|
||||
Submitting a criticism: open an issue on the repository once it is public (January 2027, with the benchmark), or use the contact route on igneum.network. Anything that is not already in this ledger, or that shows an entry here is wrong, gets added with credit if wanted.
|
||||
Submitting a criticism: email hello@igneum.network (Igneum Labs LTD, Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre), or open an issue on the repository once it is public, at the public testnet. Anything that is not already in this ledger, or that shows an entry here is wrong, gets added with credit if wanted.
|
||||
|
||||
Evidence locations referenced below: `docs/bench-log.md`, `proto-metal/TESTS.md`, `sim/results.md`, `sim/finality_sim.py`, `proto-cuda/`, the design document section "Finality rule, version 2, after the second hostile review" (called "design doc, Finality v2" here), its "Security model" table, and its "What the hostile review changed" table.
|
||||
|
||||
|
|
@ -29,7 +29,9 @@ Evidence locations referenced below: `docs/bench-log.md`, `proto-metal/TESTS.md`
|
|||
### M1. The program space is tiny
|
||||
"Eleven integer ops, 64 instructions, 8 iterations, a splitmix register init. That is not RandomX. RandomX leans on a superscalar out-of-order CPU with floating point and branches. Yours is a sea of 32-bit ALUs and a memory bus. A chip for that is a weekend."
|
||||
|
||||
Status: Open, experiment scheduled. Sweep (5 October 2026): nothing runnable; the bounty, the public benchmark and a chip design are M22's decisions and hardware. The nearest number stays M16's arithmetic.
|
||||
Status: Open, program space counted, the claim stands as a target (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): nothing runnable; the bounty, the public benchmark and a chip design are M22's decisions and hardware. The nearest number stays M16's arithmetic.
|
||||
|
||||
Sweep (5 October 2026, evening): the program space, swept as arithmetic from the version 2 generator (`igneum-pow/src/generator.rs`: 16 load slots as a uniform 16-subset of instructions 1 to 63, then nine draws per instruction, 592 draws per program; 10 non-load operations with weights 12/10/8/8/8/7/6/6/6/4; 8 registers; a 31-way rotation, a 32-way bit and a 5-way mask per instruction; two 32-bit immediates). Counting choices: the slot subset is 48.4 bits; the operation draw carries 3.26 bits of entropy (of log2 10 = 3.32); operations and registers alone give about 770 bits per program; with the rotation, bit and mask fields about 1,550 bits; with the immediates about 5,650 bits, all capped by the 256-bit seed, so the space a chip has to serve is 2^256 distinct programs drawn from a structure of about 2^1550 shapes, and the critic is right that it is a small instruction set: 12 operations, 8 registers, no floating point, no branches, by design (vendor-identical rounding). What the sweep adds to the ledger's answer is the number that matters for a fixed-function design, the spread a chip must absorb: under generator version 2 every accepted program does 120 to 128 distinct loads per hash (median 128.00, 20,000-program census), so the per-program hash-rate spread on a memory-bound device is the 1.10x residual the census measured, not the 2.7x of version 1; the chip's advantage therefore cannot come from the program (it is one fixed memory-bound shape) and must come from the memory system or from the recompute route, which is M16's cost model (`docs/analysis/m16-recompute-attacker-2026-10-05.md`: 1.5x to 2.4x at equal integer budget before any fixed-function factor, 3x to 6x with one, and the mixer-cost lever that cuts it below 1x). The experiment that closes M1 is unchanged: the bounty and the public benchmark (M22, decision owner the project lead).
|
||||
|
||||
Answer: Correct that the arithmetic is simple on purpose. Integer only, because floating point rounds differently per vendor and would split the chain (design doc, hostile review table, row 2). The defence is not the ALU work. It is random 4-byte reads over a dataset larger than any on-chip cache: the RTX 5090 runs the same program 5.8x faster when the dataset fits in its 96 MiB L2 (1,352 Mhash/s at 64 MiB against 229 at 1 GiB, bench-log, RTX 5090 sweep). A chip has to buy the same gigabytes of memory and loses the same latency. The honest target for a chip's gain is under 2x and it is a target, not a measurement. The experiment that tests it is the standing bounty for any chip design beating a GPU by more than 2x, live with the public benchmark in January 2027 (design doc, decisions table, row 1). Until a bounty has gone unclaimed for years the claim is a target.
|
||||
|
||||
|
|
@ -129,7 +131,9 @@ Evidence: `docs/bench-log.md`, RTX 5090 sections. Fix: overclaims list, item 14.
|
|||
### M11. Hourly JIT on real rigs
|
||||
"50 ms compile is a Mac number. On a HiveOS rig the miner has to ship NVRTC or a ROCm compiler, compile for eight cards of mixed generation, and do it every hour without crashing. Every miner that tried runtime codegen had a bad year."
|
||||
|
||||
Status: Open, experiment scheduled. Sweep (5 October 2026): partly measured. One RTX 5090 compiled the hourly program at runtime (nvcc in the background) on the live devnet in 1,285 ms with no pause and 0 rejected (bench-log, "first hourly program swap"). A multi-card mixed rig and ROCm remain unmeasured (hardware, O-1.16).
|
||||
Status: Answered with evidence on the fleet that exists, Open for a multi-card rig and ROCm (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): partly measured. One RTX 5090 compiled the hourly program at runtime (nvcc in the background) on the live devnet in 1,285 ms with no pause and 0 rejected (bench-log, "first hourly program swap"). A multi-card mixed rig and ROCm remain unmeasured (hardware, O-1.16).
|
||||
|
||||
Sweep (5 October 2026, evening): hourly runtime codegen measured on five machines, four compilers and three vendors over the live devnet's boundaries of 5 October 2026 (miner logs through the intake, DAA 82,800 to 111,600, from each machine's 0.3.5 start; `docs/bench-log.md`, "FUD ledger sweep round 6", M11). NVRTC on the two RTX 5090s: prepare 580 to 1,074 ms in all (nvrtc 147 to 180 ms, cache, dataset, 96-lane self-test), 22 of 22 boundaries swapped with no pause, 0 rejected. OpenCL on the two integrated Radeons: prepare 6.9 to 11.7 s on PC 2 and 55 to 124 s on PC 1 (its 1 GiB dataset build on the iGPU runs beside today's WSL build jobs), the two late boundaries on PC 1 (82,800 and 93,600, the prepare sent 156 to 160 DAA before the boundary instead of 449) compiled inline, the rest swapped. OpenCL on the Intel UHD laptop: prepare 7.3 to 11.7 s (build 3.0 to 6.4 s), 7 of 7 swapped with no pause. Metal on the two Macs: program 0 to 444 ms, prepare 34 to 40 s because the hourly race runs inside it, 9 of 9 swapped with no pause. The failure the critic predicts did happen, on the 0.3.4 miner: a wrong prepared pack at DAA 61,200 made both PCs' NVIDIA workers refuse the prepare every 0.7 s for two hours (4,299 and 4,233 `prepare-failed` lines) and cross two boundaries by inline compile; the 0.3.5 miner's rate limit ended it (M27). The variant race on the 5090 (the job of `docs/plans/miner-perf.md`, run on PC 1 at 15:52 UTC with the miners stopped): 17 NVRTC variants, 3 rounds, twice; base won both runs at 139.75 and 139.65 MH/s, gain +0.00%, every variant within -1.5% (`ldcs`) and +0.05% of base, compile 232 to 300 ms for the 17, 112 s of timing per run; the Mac fleet records agree that base wins on the M5 Max with the GPU to itself (10 records, g256 at -4.2%, against +17% under 4 October's contention). The race is therefore switched off as a default worth nothing on this program class: 40 s an hour of paused mining on the Macs for a base winner. Still unmeasured: a multi-card mixed-generation rig and ROCm (hardware, O-1.16).
|
||||
|
||||
Answer: Correct that the compile figures (18 to 52 ms) are Metal on one Mac. The 5090 run used an offline nvcc build. Runtime compile with NVRTC and with ROCm on a multi-card rig is unmeasured. KAWPOW miners do ship runtime kernel generation on both vendors, so the problem is known to be solvable (approximate, from memory). Measured in phase 2 with the miner client prototype.
|
||||
|
||||
|
|
@ -309,7 +313,9 @@ Evidence: design doc "Unit economics of a proof"; litepaper "What Igneum does no
|
|||
### P3. A phone verifies in milliseconds is a SNARK-wrapper claim
|
||||
"Hash-based STARK proofs are hundreds of kilobytes and take real work to verify. Milliseconds on a phone means a Groth16 or Plonk wrapper, and wrapping SP1 proofs needs a big machine for minutes."
|
||||
|
||||
Status: Open, experiment scheduled. Sweep (5 October 2026): hardware item (the wrapper on consumer hardware); not runnable here.
|
||||
Status: Open, the certificate half measured in a phone-sized tab, the wrapper half unmeasured and unbuilt (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): hardware item (the wrapper on consumer hardware); not runnable here.
|
||||
|
||||
Sweep (5 October 2026, evening): what the homepage verifier measures is a BLS certificate, not a SNARK: `site/verify/core.js` recomputes 21 header hashes (BLAKE2b), checks the voter list's canonical order, sums the 16 signers' G1 keys and checks one BLS12-381 aggregate signature, in pure JavaScript (`@noble/curves` 2.4.0). Measured tonight on `https://igneum.network/verify/test.html` against the live checkpoint 3668 (16 of 21 signers, 72.3% of weight): in the built-in browser pane's mobile emulation (375 x 812, an Android user agent, three loads) the genuine certificate verified in 139.1, 150.2 and 155.3 ms cold and 68.3, 58.4 and 64.8 ms warm; the same page at desktop size on the same machine 151 and 63.3 ms. Emulation changes the viewport and the user agent and nothing else: the CPU is this M5 Max under a load average above 100 (two builds and the C4 harness running), so the mobile and desktop numbers are the same number, and the 15 to 66 ms of `docs/plans/morning-2026-10-04.md` is the same laptop idle. What is NOT measured: any phone (a 2024 phone core is 2x to 4x slower than this laptop core on scalar JavaScript, approximate, so 150 to 600 ms cold for the certificate alone); and the thing the critic names, the wrapped block proof. No wrapper exists: the light verifier of the pinned SP1 compressed proof takes 1.3 to 2.1 s of setup plus 2 to 108 ms per verify on this Mac (bench-log 5 October, "the program id split"), is a 58 MB native binary, and a Groth16 or Plonk wrap of it is unbuilt (phase 2 benchmark). The litepaper's phone claim stays "wrapped for light clients" until the wrapper is measured on a phone.
|
||||
|
||||
Answer: Correct. The light-client proof is the aggregated block proof wrapped once into a small curve-based proof, and wrapping is the aggregator's job. The cost and latency of that wrapper on consumer hardware is unmeasured and belongs in the phase 2 benchmark alongside the shard time. Until measured, the litepaper should say "wrapped for light clients".
|
||||
|
||||
|
|
@ -369,7 +375,22 @@ Evidence: design doc "Proving speed on consumer GPUs" risk item and Finality v2
|
|||
### P9. Shard griefing
|
||||
"Claim a shard with a small bond and never prove it. Repeat. Finality waits on you."
|
||||
|
||||
Status: Answered by design, parameters open. Sweep (5 October 2026): the parameters (O-5.6) are phase 4 devnet work; the economy simulator's lever study found the claim timeout a market parameter and recommends starting the devnet at 120 s (`docs/analysis/economy-2026-10-04.md` section 6).
|
||||
Status: Answered by design, parameter table written from the live numbers (5 October 2026, evening sweep). Was: Answered by design, parameters open. Sweep (5 October 2026): the parameters (O-5.6) are phase 4 devnet work; the economy simulator's lever study found the claim timeout a market parameter and recommends starting the devnet at 120 s (`docs/analysis/economy-2026-10-04.md` section 6).
|
||||
|
||||
Sweep (5 October 2026, evening): shards carry no bond (spec 7.2, P13), so shard griefing is a prover sitting on an exclusive window; the only bond is the external job's. The table, from the live devnet at 16:00 UTC (`igneum_getProvingStatus` on the Mac node: 352 shards paid, pool 19 entries, 0 failed, 0 pending, 154 verified; the task's figure of 215 paid was the morning's) and the measured shard times:
|
||||
|
||||
| Parameter | Live devnet value (5 October 2026) | Proposed for the testnet | Why |
|
||||
|---|---|---|---|
|
||||
| Assignees per shard | 8 (`ASSIGNEES_PER_SHARD`, `consensus/core/src/proving.rs`) | 8 | 21 eligible keys today, so a shard's draw covers 38% of the fleet; at 1,000 keys 0.8%. Eight keeps one slow or absent assignee from costing more than one window |
|
||||
| Exclusive window | 10 DAA s (`EXCLUSIVE_WINDOW_DAA`) | 25 s | The economy study's rule (the 90th percentile of the fleet's shard time plus one program swap, rounded up to 5 s): the 5090 proves a full 7.5 M pgas shard in 9.1 s core, 10.9 s compressed, and the swap is under 1.1 s (M11), so 10 s is at the 5090's median and loses the window for every slower card; 25 s covers a 12 GB card at the 20-s target |
|
||||
| After the window | open to anyone, first verified record paid | unchanged | A griefing assignee costs the network one window and nothing else; there is no claim to hold |
|
||||
| Shard budget `S_p` | 7,500,000 pgas (prototype) | 30,000 pgas (calibrated v1, `B_p / 4`) | Adopted 5 October 2026, spec 05 section 5.11 |
|
||||
| Record window | 600 DAA s (`recordWindow` 0x258) | 600 | A record older than this is not paid; bounds the pool and the by-number history |
|
||||
| Dust for eligibility | 5 blue blocks in the window (devnet), 100 (mainnet) | 100 | W3 of spec 03; a key below dust is never drawn |
|
||||
| External job bond | none implemented (phase 4) | `maxPgas x f_p x 1.5` escrow with a 3,600-block expiry and full refund (design 4.6) | O-5.6 keeps the number; the premium 1.5 is a parameter open |
|
||||
| Claim timeout, external jobs | none implemented | 120 s | The economy simulator's lever study (`docs/analysis/economy-2026-10-04.md` section 6): a market parameter, 120 s keeps jobs on 24 GB cards |
|
||||
|
||||
Execution and the 30-s lock never wait for a proof (unchanged); the cost of a griefed shard is proof latency, one window per absent assignee at most. Decision owner for the testnet values: the project lead (O-5.1, O-5.6).
|
||||
|
||||
Answer: The bond is slashed and the shard reopens; the proving fee rises until someone proves it (security model table, "Prover cartel withholding proofs"). The open parameters are the bond size, the timeout, and whether an un-proven block delays only the proof (it does; execution and the 30-second lock do not wait for the proof). Set in phase 4.
|
||||
|
||||
|
|
@ -496,6 +517,8 @@ Sweep (5 October 2026, evening): stated. `site/litepaper.html`, cover meta line
|
|||
"Anonymous founder, GoDaddy domains, a Vercel site, a litepaper dated the same day as five 'milestones'. This is a template."
|
||||
|
||||
Status: Conceded, team page deferred by decision.
|
||||
Decision owner (5 October 2026, evening sweep): the project lead (the team page at public testnet, fud-fixes row 9).
|
||||
Status: Conceded, team page deferred by decision. Decided 5 October 2026: no team page for now; the litepaper says the team is pseudonymous and names no team page.
|
||||
|
||||
Answer: The founder's name is on every commit. The litepaper defers the team page to public testnet by decision, with disclosed mining addresses at genesis. There are no coins to sell and no sale planned, so there is nothing to run away with before block one. The five log entries dated 3 October 2026 are day one of the project and should be presented as that.
|
||||
|
||||
|
|
@ -590,12 +613,14 @@ Sweep (5 October 2026, evening): stated. `site/litepaper.html`, The problem: "Ch
|
|||
### C4. vs Kaspa: a finality overlay changes GHOSTDAG's guarantees
|
||||
"GHOSTDAG's safety comes from blue work. A certificate that overrides blue work and a pruning point that never passes the latest lock are changes to the security model, not features on top."
|
||||
|
||||
Status: Open, experiment scheduled. Sweep (5 October 2026): the overlay has now run on a real DAG (cloud devnet, 4 October): with the module on, two partitions produced 0 conflicting locks, the 15.8% side locked nothing, the 84.2% side locked every interval, and the minority reorganised 423 to 496 blocks at the heal and adopted the majority's certificates within 15 s; the same day's F21 finding (a long honest partition locks alone from day 10 at 50/50) is the one real change to GHOSTDAG's guarantees found so far, and rule v3 answers it. The module-off comparison and the trace-driven adversary of O-3.8 are still owed.
|
||||
Status: Measured on the live node line, and the overlay does NOT do what the spec says at a heal: a NEW SERIOUS FINDING (5 October 2026, evening sweep; owner: cryptographer and consensus engineer, decision owner the project lead). Was: Open, experiment scheduled. Sweep (5 October 2026): the overlay has now run on a real DAG (cloud devnet, 4 October): with the module on, two partitions produced 0 conflicting locks, the 15.8% side locked nothing, the 84.2% side locked every interval, and the minority reorganised 423 to 496 blocks at the heal and adopted the majority's certificates within 15 s; the same day's F21 finding (a long honest partition locks alone from day 10 at 50/50) is the one real change to GHOSTDAG's guarantees found so far, and rule v3 answers it. The module-off comparison and the trace-driven adversary of O-3.8 are still owed.
|
||||
|
||||
Answer: True. Among candidate tips (those passing through every certified checkpoint) GHOSTDAG selects by blue work under the 3,600-second merge-depth bound; a certified checkpoint removes other tips from candidacy. That is a change, and its interaction with pruning, with red blocks in the attacker's weight and with latency is exactly what the gate 3 devnet measures. The module is separable so GHOSTDAG alone remains the fallback.
|
||||
|
||||
Evidence: design doc Finality v2, Fork choice items 1 to 4; `sim/results.md` final section.
|
||||
|
||||
Sweep (5 October 2026, evening): the module-on against module-off comparison of O-3.8, run on the fast-time harness with the live node line (`tools/finality-attacks/c4.mjs`, fork 2b6d23ef, 3 nodes, 100-ms proxied links; raw tables in `docs/bench-log.md`, "FUD ledger sweep round 6", C4). The scenario separates weight from work: side B (n1, n2, four keys) holds 70% of the weight table and side A (n0, two keys) 30% when the link is cut; from the cut A mines at 0.6 blocks/s and B at 0.4, so A's chain is the heavier one by blue work while only B can certify under rule v3 (A holds 30% of the frozen table). Module off (`min_daa` never, so no certificate can form, fork choice bare GHOSTDAG): after a 150-s split the three nodes converged on A's heavier chain within 36 s of the heal, B's nodes re-determined their two split-time checkpoints onto it (F24), 0 conflicts. Module on (rule v3 from checkpoint DAA 0), 90-s split, n0 back on the link 6 s after the heal, A's chain at about 58 DAA of its own time, well inside the 120-DAA frozen table: during the split A locked nothing and B locked indices 7 and 8 on its own blocks, as designed; after the heal n0 did not switch. Its log: B's certificates for 8 and 9 arrived and were "kept pending until the chain decides (no lock at this index)" (the F24 path), n0's chain never changed because GHOSTDAG prefers its heavier tip and nothing in the node turns a verified certificate over an off-chain block into a fork-choice constraint, and one window after n0's last lock (index 7 at DAA 209, so from DAA 329) the frozen table no longer applied on A's chain ("no frozen table (no lock on this chain inside the window)"), A's two keys were 100% of A's own window table (B's post-cut blocks are red there and earn nothing), and n0 locked 10, 11 and 12 alone; B's certificates for 10 and 11 then logged CONFLICTING on n0, and B's nodes kept their certified chain. End state: sinks apart, 2 locked indices disagreeing across the nodes, a finality fork from a 96-s honest partition with no attacker and the frozen table intact at the heal; the same shape with a 150-s split (the table expired at the heal) and under rule v2 (the control: 1 conflict, sinks apart). So the answer to the critic is sharper than conceded: the overlay is specified to override blue work (spec 3.5, "GHOSTDAG among tips through all certified checkpoints") but the shipped node applies a certificate only to a block on its own chain, holds the rest pending a reorg that GHOSTDAG alone never produces, and after one window the heavier side certifies its own chain. Two honest views never reconcile. What closes it: a verified certificate over a block the node does not have on its selected chain must verify against the weight table at THAT block (its signers' weight there) and, when valid, constrain fork choice to tips through it, forcing the reorg (a certificate-driven reorg, bounded by the finality depth), with the node's own unlocked records re-determined on the new chain (F24); until then the exchange guidance of 3.9 (a node partitioned for more than a minute treats its locks as proof of work until it has seen the network's certificates agree with its own) is the only protection, and the 3.11.7 row for this case ("a certificate over a chain the node is not on") is missing. On the live devnet the window is 7,200 DAA (two hours) and the cliff is two hours after a side's last lock; a miner who joins with more hashrate than the weight table credits is the realistic work-majority side. The trace-driven adversary of O-3.8 is still owed. Spec rows: 3.5, 3.11.4, 3.11.7; node: `processes/finality.rs` (`ingest_certificate`'s pending branch, `fork_choice_lock`). Decision owner: the project lead (gate 3; a rule change to the node's fork choice).
|
||||
|
||||
### C5. vs Ethereum: you compare inclusion to finality
|
||||
"'Included in about one second, against twelve on Ethereum.' Inclusion in a DAG is not confirmation. Ethereum's twelve seconds is a slot, its finality is about thirteen minutes, and you compare your two-minute lock to that as if a two-minute lock by a pool committee were the same thing."
|
||||
|
||||
|
|
@ -686,6 +711,7 @@ Evidence: CLAUDE.md rules (privacy rejected). Fix: overclaims list, item 68.
|
|||
"A founder's company earns a dev fee, runs a pool and a proving business, seeds the DEX, pays 'launch grants', and the roadmap ends in 'exchange listings after'. Expectation of profit from the efforts of others, in writing."
|
||||
|
||||
Status: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable.
|
||||
Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here.
|
||||
|
||||
Answer: There is no sale, no premine, no allocation and no promise of return, and nothing in consensus is controlled by the team and no protocol fee reaches it (the development fund was removed on 3 October 2026), which is the structure that regulators have treated most favourably (approximate: compare the SEC's own framework on sufficiently decentralised networks and MiCA's exemption for tokens created automatically as a reward for maintaining a distributed ledger, approximate quotation). The weak points a lawyer will circle are the ones quoted: founder-run pool and proving business, founder-seeded DEX, launch grants, and the phrase "exchange listings after". None is in consensus; all are promotional. The litepaper must drop the listing sentence and counsel must review the founder-business paragraph before v0.2. The legal entity is "offshore, parked" in the design doc, which is not an answer.
|
||||
|
||||
|
|
@ -695,6 +721,7 @@ Evidence: design doc "Legal" paragraph. Fix: overclaims list, items 75 and 76.
|
|||
"Several jurisdictions now treat a cryptoasset promotion to their consumers as regulated: the UK since October 2023 needs an authorised approver, the EU under MiCA has its own marketing rules, the US has the Howey test. 'The people who show up early get the most' on a domain you own is a promotion wherever the reader sits."
|
||||
|
||||
Status: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable.
|
||||
Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here.
|
||||
|
||||
Answer: A litepaper describing how to mine a coin that does not exist is arguably not an invitation to engage in investment activity, and the regime has carve-outs for information that is not an inducement (approximate; this needs an opinion from counsel in the jurisdiction the project is established in, which is offshore and not yet named). Sentences that read as inducements to acquire ("show up early get the most", "half of all supply in the first two years") should be rewritten as schedule facts before v0.2. Country-code domains such as igneum.co.uk redirect to igneum.network and carry no separate content.
|
||||
|
||||
|
|
@ -704,6 +731,7 @@ Evidence: none. Fix: overclaims list, item 77.
|
|||
"Fifteen domains at a US registrar on US nameservers behind a US host. One court order and igneum.network is a parking page."
|
||||
|
||||
Status: Conceded, mitigation scheduled. Sweep (5 October 2026): a deSEC token now sits in `~/.config/igneum` (mode 600), so the nameserver move of fud-fixes row 44 has started; the registrar move waits for December.
|
||||
Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here.
|
||||
|
||||
Answer: True. GoDaddy and Vercel are both US companies and have both complied with takedowns. Mitigations: an ENS or equivalent name and an IPFS mirror of the site and litepaper, the site's content hash published in the repository and in the genesis block, at least one non-US registrar for a second TLD, and the chain itself never depending on any domain (seed nodes are addresses in the client, not DNS only). Phase 5.
|
||||
|
||||
|
|
@ -713,6 +741,7 @@ Evidence: CLAUDE.md "Domains". Mitigation: not yet.
|
|||
"'Testnet miners are paid real money for real proofs from phase five.' That is a business paying contractors in crypto across borders with no entity."
|
||||
|
||||
Status: Open. Sweep (5 October 2026): counsel and entity; nothing runnable.
|
||||
Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here.
|
||||
|
||||
Answer: Correct that it needs an entity, terms and tax treatment before it happens. The payments come from the customer rollup on its own chain, not from Igneum, but the arrangement is organised by the project. Counsel before phase 5.
|
||||
|
||||
|
|
@ -722,6 +751,7 @@ Evidence: design doc "The first six months".
|
|||
"Igneum. Have you checked EUIPO, USPTO and the UK IPO? There is no evidence you did."
|
||||
|
||||
Status: Open. Sweep (5 October 2026): a person's search, recorded outside the repository; nothing runnable.
|
||||
Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here.
|
||||
|
||||
Answer: No clearance search is recorded in the repository. One is required before the name is used commercially, in all three registers and in Nice classes 9, 36 and 42, approximate. Until then the name is provisional and the litepaper should not claim otherwise.
|
||||
|
||||
|
|
@ -785,7 +815,9 @@ Evidence: litepaper "Roadmap"; design doc "Team".
|
|||
### X5. 1,000 independent miners is a Sybil number
|
||||
"Your testnet gate is 1,000 independent miners for 30 days. One person with a script is 1,000 miners."
|
||||
|
||||
Status: Conceded, measurement to define.
|
||||
Status: Conceded, measurement defined from the vote-key window and today's numbers (5 October 2026, evening sweep); decision owner the project lead (O-X.1). Was: Conceded, measurement to define.
|
||||
|
||||
Sweep (5 October 2026, evening): the definition, measurable from chain data plus two attestations, and today's reading. Unit: a vote key with at least the dust count of blue blocks in the 30-day weight window (W3), which is the smallest thing the chain can count. Independence: two keys are independent when they differ in all three of (a) the autonomous system of the address their blocks' nodes announce (seed and peer tables, the observer's address field), (b) the machine fingerprint the miner app sends with its log uploads (`machine_id`, already in every STATUS line's run id), and (c) the pool attestation, a signed statement by a pool operator listing the keys it runs (absent for solo keys). N_ind = the number of distinct (ASN, fingerprint, pool) classes among eligible keys; the gate of `site/journey.json` phase 5 reads "N_ind >= 1,000 over the same 30 days with top-10 share of window weight under 50%". Today's reading from the live window (Mac node, `getFinalityWeights` at DAA 112,395): 22 keys, 21 voters above dust (dust 5 on the devnet), total weight 7,196 of 7,200 blue blocks; top-1 share 8.3%, top-3 20.3%, top-5 31.9%, top-10 60.3%; the console counts 5 machines and 21 identities in 10 minutes, so the fleet runs 4.2 keys per machine (the launcher's one key per worker, F17's client default) and N_ind by fingerprint alone is 5, by ASN at most 3 (two home networks and one US household, approximate). That is the Sybil ratio the critic means, measured: 21 "miners" are 5 machines. The hashing concentration of X14 (top-1 12.8%, top-3 34.5% over 8,090 blocks on 4 October) and tonight's weight shares agree within the window's drift. What the observer must add (O-X.1): the ASN per announcing address, the fingerprint per key (the app already has both), and the pool statement format.
|
||||
|
||||
Answer: Correct. "Independent" needs a definition that can be measured: distinct ASNs, distinct hardware fingerprints from the benchmark, or signed attestations from pool operators. Defined in phase 4, before the gate is tested.
|
||||
|
||||
|
|
@ -1133,7 +1165,9 @@ Evidence: the files and lines above. Fix: review's first of five. Review id R3.2
|
|||
### M16. The 256 MiB cache fits on a die, so the recompute attacker is compute bound
|
||||
"Your 4.8x-slower shortcut ran with the cache in DRAM behind a chip that cannot hold it. Put 256 MiB of SRAM on a die and the dataset is never needed: 128 items per hash at about 1,170 integer operations and 8 near-free reads each. That is 150,000 operations per hash, and integer operations per dollar is where silicon beats a GPU."
|
||||
|
||||
Status: Open, experiment scheduled. Sweep (5 October 2026): not runnable on this Mac; the on-die emulation needs the RTX 5090 (an inline kernel at a 64 MiB cache inside its 96 MiB L2). The only newer number is the loaded-Mac reconfirmation of 3 October (inline 17x slower at a 256 MiB cache, bench-log "R3.26 / M15", M16 note), which does not price a die. Hardware item.
|
||||
Status: Open, cost model written, the on-die emulation still a PC job (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): not runnable on this Mac; the on-die emulation needs the RTX 5090 (an inline kernel at a 64 MiB cache inside its 96 MiB L2). The only newer number is the loaded-Mac reconfirmation of 3 October (inline 17x slower at a 256 MiB cache, bench-log "R3.26 / M15", M16 note), which does not price a die. Hardware item.
|
||||
|
||||
Sweep (5 October 2026, evening): `docs/analysis/m16-recompute-attacker-2026-10-05.md` prices the device from the specification and the measured rates. Per hash the attacker recomputes 128 items at 9 mixer applications of about 130 operations and 8 dependent 64-byte cache reads each: about 150,000 integer operations and 1,024 dependent SRAM reads (65 KB). To match one RTX 5090 at its measured 229 Mhash/s the chip needs 34 T integer op/s and 15 TB/s of SRAM bandwidth beside 256 MiB of SRAM (100 to 300 mm^2 on a current node, approximate). At the 5090's own integer budget (about 50 T op/s, approximate) that is 0.33 Ghash/s: 1.5x the measured closed-form rate, 2.4x the 141 Mhash/s projected for version 2 programs, before any fixed-function factor; with a 3x factor (approximate) 3x to 6x at equal die area. The lever: the mixer cost is paid by the honest miner once a day (13.4 ms per 1 GiB on the 5090, measured) and by the attacker per hash, so doubling it halves the attacker's rate at zero honest cost, 4x puts the equal-silicon gain at 0.36x and the factored gain near 1x, bounded by the CPU verify gate (0.41 to 1.2 ms per warp today, 10 ms the gate, so about 8x of headroom on the M5 Max core). What is still unmeasured: the inline kernel on the 5090 with a 64 MiB cache inside its L2 (the SRAM emulation, a PC job), the time-memory curve of O-1.6, and any cryptanalysis of the mixer. Decision at gate 1 (owner the project lead): cache size and mixer cost against the verify gate.
|
||||
|
||||
Answer: Correct as arithmetic, unmeasured as a device. From spec 1.8.4 and 1.8.5 an item costs 9 mixer applications of about 130 operations and 8 cache reads; under the proposed 16-load rule a hash derives 128 items. A 5090-class integer budget (about 50 T operations a second, approximate) gives about 0.33 Ghash/s against the honest 141 Mhash/s projection, about 2.4x at equal silicon before any chip-versus-GPU efficiency, and a 256 MiB SRAM is about 250 to 300 mm^2 on a current node (approximate, from wafer-scale parts). The cache size was set to beat a GPU's L2 (spec 1.16), not a die. The lever is the cache size and the mixer cost, both prototype values at gate 1. Monero's precedent does not price this (C13). An FPGA does not reach it (review, chip designer, attack 3).
|
||||
|
||||
|
|
@ -1171,7 +1205,7 @@ Evidence: `docs/analysis/weak-program-census-2026-10-03.md` sections 7 and 9. Re
|
|||
### M20. Pruning proofs are checked with the kHeavyHash stub
|
||||
"Wait thirty hours, start a fresh node, and watch it reject the honest pruning proof: `validate.rs:192` runs kHeavyHash on headers mined under the lottery, which pass with probability 2^-28. And if you loosen that, I forge levels with an ASIC that already exists."
|
||||
|
||||
Status: Open, acknowledged, fix named. Sweep (5 October 2026): still the stub on `devnet-v4` (`consensus/src/processes/pruning_proof/validate.rs:192` calls `calc_block_level_check_pow`; `apply.rs:74, 200` and `mod.rs:207` call `calc_block_level`). The test, a fresh node syncing a chain past its pruning depth, needs a network older than that depth; a fresh node against the live devnet is outside this sweep's rules, so it was not run. When it bites: the devnet's pruning depth is `PRUNING_DURATION` 108,000 DAA (`consensus/core/src/config/constants.rs:94`; the derived lower bound is 63,398), and the pruning point first leaves genesis once a finality point sits a full pruning depth below the tip, DAA 108,000 to 151,200, which at 1.05 DAA/s from DAA 33,000 at 17:37 UTC on 4 October falls between about 14:00 UTC on 5 October and 01:00 UTC on 6 October (approximate). From then on a fresh node receives a pruning proof and the stub rejects the honest headers with probability about 1 - 2^-28 each. Fix row in `docs/fud-fixes.md` section 2.5.
|
||||
Status: Fixed in the node (rolled out 5 October 2026, 0.3.5: `m20-pruning` d35b00cf merged into fork 20139145 as its last merge, `cargo test -p kaspa-consensus --features igneum-pow -- pruning_proof` 4 passed at 03:15 UTC, `docs/plans/release-0.3.5.md` 1b and 3b: pruning proofs are checked with the Igneum lottery hash and the chain seeds; `pruning_proof/validate.rs`, the IBD proof flow and the p2p proof messages carry the seeds). Sweep (5 October 2026, evening): the live test is still owed and now possible: the Mac node's pruning point is still genesis at DAA 113,289 (`getBlockDagInfo` at 16:00 UTC, pruning point `edc4fa84...` with DAA score 0), so no node has yet served or checked a lottery-hashed pruning proof on the live devnet; the first fresh node to sync after the pruning point moves (expected between 14:00 UTC on 5 October and 01:00 UTC on 6 October by the entry's own arithmetic, approximate) is the measurement, and a fresh `igneumd` on this Mac against the live seed is read-only for the network and should be run then. Was: Open, acknowledged, fix named. Sweep (5 October 2026): still the stub on `devnet-v4` (`consensus/src/processes/pruning_proof/validate.rs:192` calls `calc_block_level_check_pow`; `apply.rs:74, 200` and `mod.rs:207` call `calc_block_level`). The test, a fresh node syncing a chain past its pruning depth, needs a network older than that depth; a fresh node against the live devnet is outside this sweep's rules, so it was not run. When it bites: the devnet's pruning depth is `PRUNING_DURATION` 108,000 DAA (`consensus/core/src/config/constants.rs:94`; the derived lower bound is 63,398), and the pruning point first leaves genesis once a finality point sits a full pruning depth below the tip, DAA 108,000 to 151,200, which at 1.05 DAA/s from DAA 33,000 at 17:37 UTC on 4 October falls between about 14:00 UTC on 5 October and 01:00 UTC on 6 October (approximate). From then on a fresh node receives a pruning proof and the stub rejects the honest headers with probability about 1 - 2^-28 each. Fix row in `docs/fud-fixes.md` section 2.5.
|
||||
|
||||
Answer: Correct. `consensus/src/processes/pruning_proof/validate.rs:192` calls `calc_block_level_check_pow`, which runs the stub, and `apply.rs` and `mod.rs` call `calc_block_level` the same way; `docs/fork-divergence.md` records that seeds must be threaded through pruning-proof validation before a pruning network. The devnet will pass its pruning depth (108,000 blocks, sooner after tonight's overshoot) and a fresh node will show it. Fix: derive the epoch and day for proof headers from the proof's own headers (fork map a4, O-2.5) and remove the stub from the proof path.
|
||||
|
||||
|
|
@ -1180,7 +1214,7 @@ Evidence: the files above. Test: sync a fresh node from the 30-hour devnet. Revi
|
|||
### M21. GHOSTDAG k is Kaspa's table value for Kaspa-sized bodies
|
||||
"k = 18 assumes a 5-second delay bound measured with Kaspa's blocks. Yours carry EVM transactions and recursive proof records."
|
||||
|
||||
Status: Open, extends O-2.2. Sweep (5 October 2026): k re-derived with the fork's own function (`vendor/rusty-kaspa/consensus/core/src/config/bps.rs`, `calculate_ghostdag_k`, delta 0.01) at 1 block/s: a delay bound of 2 s gives k 9, 5 s gives 18, 10 s gives 31, 20 s gives 55, 30 s gives 79. Measured propagation on the 12-node, 5-region cloud devnet of 4 October with today's bodies: p99 0.67 s, max 2.3 s, which the function maps to k 5 and k 10. So k = 18 carries about 7x headroom on today's bodies; the run with proof-bearing bodies (O-2.2) is still owed and decides whether that headroom survives.
|
||||
Status: Answered with evidence for today's bodies, Open for proof-bearing bodies (5 October 2026, evening sweep). Sweep (5 October 2026, evening): block sizes measured on the live devnet and k derived from them. The last 60 chain blocks at DAA 112,433 (Mac node, wRPC, sizes summed from the RPC fields, approximate serialisation): p50 723 bytes, p90 1,022, max 6,908 (a block carrying a certificate section), 1 transaction per block (the coinbase), coinbase payload p50 395 bytes, max 6,580; the proof records in the coinbase are 274 bytes each (unit test `largest_coinbase_fits_on_every_network`), the SP1 proof itself (1.27 MB per shard, bench-log 5 October) stays in the pool and never enters a block. Serialisation of the largest observed block on a 100 Mbit/s link is 0.6 ms per hop, so the delay bound is the propagation alone: with the fork's `calculate_ghostdag_k` (delta 0.01, x = 2 D at 1 block/s) the cloud devnet's p50 343 ms gives k 3, p90 497 ms k 4, p99 666 ms k 5, max 2.3 s k 10, and k = 18 corresponds to D = 5 s, 7.5x the measured p99. For mainnet-sized bodies: the fast-time profile's mass limits (500,000 compute mass at 1 mass per transaction byte) bound a body near 500 KB, 40 ms per hop at 100 Mbit/s and about 120 ms over the 3 hops of the cloud topology, which moves the p99 to about 0.8 s and k to 6, still 3x inside k = 18; a 5-s bound holds bodies up to about 50 MB per hop at that bandwidth. So k = 18 is Kaspa's value and it carries 3x to 7x of headroom on the measured network for any body the mass limits allow; the proof-bearing run of O-2.2 decides whether the red rate under real bodies stays near the model (bench-log "FUD ledger sweep round 6", M21). Was: Open, extends O-2.2. Sweep (5 October 2026): k re-derived with the fork's own function (`vendor/rusty-kaspa/consensus/core/src/config/bps.rs`, `calculate_ghostdag_k`, delta 0.01) at 1 block/s: a delay bound of 2 s gives k 9, 5 s gives 18, 10 s gives 31, 20 s gives 55, 30 s gives 79. Measured propagation on the 12-node, 5-region cloud devnet of 4 October with today's bodies: p99 0.67 s, max 2.3 s, which the function maps to k 5 and k 10. So k = 18 carries about 7x headroom on today's bodies; the run with proof-bearing bodies (O-2.2) is still owed and decides whether that headroom survives.
|
||||
|
||||
Answer: Correct. Spec 2.1 takes k, max parents and the mergeset limit from Kaspa's table at 1 BPS. O-2.2's two-miner devnet measures the parallel and red rate; it should run with proof-bearing bodies of the size section 5.4 of the execution design implies, and k should be re-derived from the measured delay.
|
||||
|
||||
|
|
@ -1207,7 +1241,19 @@ Evidence: the files above. Review id R3.2.
|
|||
### F16. A lock can become uncertified after a heal
|
||||
"Section 3.5: two certificates at one index, strike the equivocators, re-evaluate, and if neither or both still lock the index is uncertified. So the lock my node reported and I credited on is revocable."
|
||||
|
||||
Status: Open, decision at gate 3 (extends O-3.6). Sweep (5 October 2026): a decision item (O-3.17); nothing runnable.
|
||||
Status: Open, the two options priced, one recommended (5 October 2026, evening sweep); decision owner the project lead (gate 3, O-3.17). Was: Open, decision at gate 3 (extends O-3.6). Sweep (5 October 2026): a decision item (O-3.17); nothing runnable.
|
||||
|
||||
Sweep (5 October 2026, evening): the two options, with their measured cost.
|
||||
|
||||
| | Option A: re-evaluate (spec 3.5 as proposed) | Option B: never withdraw (spec 3.11.4 as written) |
|
||||
|---|---|---|
|
||||
| Rule | Two certificates at one index: strike every key that signed both, re-evaluate both against Q3; follow the one that still locks; if neither or both, the index is uncertified | A verified certificate is never deleted, downgraded or re-evaluated; the node keeps following the one it verified first, publishes the pair, sets `finality_active` false with reason `conflict`, and an operator resolves the split with a trusted certificate (F5) |
|
||||
| When the state arises | Only above the one-third bound: an equivocator holding 34% of total weight across a 50/50 split gives 2 to 54 conflicting locks in 150 to 360 min under v2 (`sim/results_v2.md` H at 2/3) and 21 to 69 from minute 14 to 78 under v3 (M5); 33% and below give 0 in every seed. Or an honest partition longer than a window (30 days on mainnet under v3; under v2 from day 10 at 50/50: the cloud devnet's 26 conflicting certificates and 23 disagreeing locked indices across three nodes, bench-log "finality floor 2/3"; tonight's C4 control run under v2: 1 conflicting certificate, sinks apart after the heal) | the same states |
|
||||
| What an exchange sees | Every one of those 2 to 69 indices was reported locked and is then uncertified: a lock is a confirmation count, which is the critic's point. In the honest-partition case there is no equivocator to strike, both still lock, and every index of the split (23 on the devnet) is withdrawn on both sides | No reported lock is ever withdrawn; the node stops reporting new locks from the first conflict until the operator acts (minute 2 to 77 in H, minute 14 to 78 in M5), the chain runs on proof of work meanwhile, and the exchange guidance of 3.9 treats it as proof of work |
|
||||
| Cost to the honest network | Recovery is automatic but every credit made on a withdrawn lock is exposed; the attacker who caused it keeps its deposit either way (F6) | A finality pause of operator length (hours) after an attack that costs the attacker ten days of a third of all hashrate in public (3.1) or a 30-day partition; the pause is the price of "locked" meaning irrevocable |
|
||||
| What the shipped node does today | not implemented | half: a second certificate at a locked index is kept and logged CONFLICTING (`processes/finality.rs`, F24 wording), the node keeps the first (`fork_choice_lock`), but it does not yet clear `finality_active` or expose `finality_conflict` (spec 3.11.7 row C4); no `finality_conflict` symbol exists in the fork |
|
||||
|
||||
Recommendation: Option B, which spec 3.11.4 already states and O-3.17 names; it is Kaspa's rule for a finality conflict (`vendor/rusty-kaspa/consensus/notify/src/notification.rs`, `FinalityConflict`), it is the only reading under which an exchange can credit on a lock, and its cost falls on a state that needs a 34% equivocator or a 30-day partition. What it needs: the 3.5 paragraph replaced by 3.11.4's text, `finality_conflict` and the `finality_active` clear in the node, and the forced-double-certificate devnet test of 3.11.7. Decision owner: the project lead (gate 3).
|
||||
|
||||
Answer: Correct as the proposal stands. For an exchange "locked" must be irrevocable or it is a confirmation count. The alternative is Kaspa's: a verified certificate is never re-evaluated; two certificates at one index are a chain split that halts `finality_active` until an operator intervenes, and the node never reports a lock it may withdraw. Equivocation costing history and not coins (F6) means the attacker who caused the split keeps the deposit either way. Decision at gate 3; the devnet partition-and-heal test of O-3.6 measures whichever rule is chosen.
|
||||
|
||||
|
|
@ -1263,7 +1309,9 @@ Evidence: spec 7.2. Review id R3.13.
|
|||
### P14. Two definitions of the proving base fee, and a quote that cannot know the ratio
|
||||
"Spec 5.1 adjusts `f_p` from the unproven backlog smoothed over the difficulty window; design 4.1 adjusts it EIP-1559 style toward `B_p / 2`. And `eth_gasPrice` has no calldata, so your fold returns an average and a modexp-heavy transaction reverts on the budget and pays for it."
|
||||
|
||||
Status: Open, decision named. Sweep (5 October 2026): decision item; spec 5.1 (backlog-smoothed) and design 4.1 (EIP-1559 toward B_p / 2) still differ.
|
||||
Status: Fixed in the spec (5 October 2026, evening sweep): one definition. Was: Open, decision named. Sweep (5 October 2026): decision item; spec 5.1 (backlog-smoothed) and design 4.1 (EIP-1559 toward B_p / 2) still differ.
|
||||
|
||||
Sweep (5 October 2026, evening): the fork has one controller and it is the EIP-1559 step. `next_base_fee(current, used, limit, floor, denominator)` in `igneum/exec/src/executor.rs:501` moves the fee toward `limit / 2` by `current x |used - target| / target / denominator`, never below the floor, and `service.rs:234-235, 310-311` applies it per chain block to both dimensions with the installed schedule's floor and denominator (8). Nothing reads the unproven backlog into `f_p`; the backlog rule of design 4.3 halves `B_p`, which raises `f_p` through the step. Nothing smooths over the difficulty window. Spec 05 section 5.1's proving row now says exactly that (this sweep's edit) and cites the function; section 5.11 already said "EIP-1559 toward half the limit, denominator 8, both dimensions". Design 4.1 still carries the words "smoothed over the difficulty window as the design document requires" and is now the odd one out: the smoothing was a design intention never implemented, and the litepaper is untouched. The quote half of the entry is unchanged: `eth_gasPrice` is a network-average fold and `eth_estimateGas` returns the limit that covers both charges (spec 7.1); R1's band measurement and R8 (the two fees against each other) remain the experiments.
|
||||
|
||||
Answer: Correct on both. Fix: one controller definition in both files; `eth_gasPrice` documented as a network-average fold with `eth_estimateGas` (which has the calldata) returning the limit that covers both charges; and the R1 band measurement (pgas / gas inside 0.1 to 10 for 95% of ethereum/tests) as the evidence that the average is usually close. R8 and R11 remain the experiments.
|
||||
|
||||
|
|
@ -1395,7 +1443,9 @@ Evidence: spec 4.3 (O-4.3), 3.3.1, 3.5, 3.7 item 2, 3.9. Experiment: O-3.16. Rev
|
|||
### F22. Certificates carry 8 to 10 of 12 votes on a healthy network, so locks sit a hair above the floor
|
||||
"Two of your cloud checkpoints locked at 66.8% against a 66.7% floor with every node connected. One slow aggregator and finality pauses."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, evening; branch `finality-fixes` of the node, behind `finality_v3_activation_daa`, `docs/plans/finality-v3-rollout-devnet.md`). Was: Open, found by the team (4 October 2026, 12-node cloud devnet, second partition run). Sweep (5 October 2026): nothing runnable without the devnet rollout; rule v3 is measured on the fast-time 3-node network (held certificates 6 of 6 at 11 of 11 indices, 0 conflicts, lock latency unchanged; bench-log "finality rule v3"). The rollout is an operator step.
|
||||
Status: Fixed in the node and shipped, rule not yet activated on the live devnet (5 October 2026, evening sweep). Was: Fix built, pending rollout (4 October 2026, evening; branch `finality-fixes` of the node, behind `finality_v3_activation_daa`, `docs/plans/finality-v3-rollout-devnet.md`). Was: Open, found by the team (4 October 2026, 12-node cloud devnet, second partition run).
|
||||
|
||||
Sweep (5 October 2026, evening): the code is on every node since 0.3.4 (the 0.3.4 fork was `finality-fixes` 6aa69a45, which carries the fold and the frozen table; 0.3.5 to 0.3.8 keep it, `docs/plans/release-0.3.5.md` 1b) but the switch is not thrown: the live override file read by the 0.3.6 digest check is `{"difficulty_v2_activation_daa": 33000, "proving_v0_activation_daa": 84100}` (`docs/plans/release-0.3.6.md` 8g) and the default is never on every network (`consensus/core/src/config/params.rs`, `finality_v3_activation_daa: u64::MAX` on devnet), so the live devnet runs rule v2 and today's locks still carry 67.0% to 71.9% of active weight (node logs, 5 October 2026: PC 2 `checkpoint 2612 LOCKED ... 67.0% of active`, PC 1 `3080 LOCKED ... 71.9%`). Rollout is the operator step N3 of the plan (publish the switch in the manifest override and every hand node's file at once, as the proving activation did). Decision owner: the project lead (N3). Sweep (5 October 2026): nothing runnable without the devnet rollout; rule v3 is measured on the fast-time 3-node network (held certificates 6 of 6 at 11 of 11 indices, 0 conflicts, lock latency unchanged; bench-log "finality rule v3"). The rollout is an operator step.
|
||||
|
||||
Answer: True as measured, and the cause is not a cut-off at all: the node builds the certificate the instant the votes it holds meet Q3, and carries that one. Measured on the cloud logs of the healthy stretch 11:45 to 14:00 UTC (212 indices, `infra/cloud-devnet/results/2026-10-04/f22-vote-timing.md`, script `tools/finality-attacks/vote-timing.py`): the first certificate was built median 1.24 s (p99 1.71 s) after the first node determined the checkpoint, with 7 to 10 of 12 signers (mean 8.27); by then 10.24 votes had been issued on average, so about two were in flight (the miner's 1-s poll, a 250-ms gossip pump per hop, inter-region RTT up to 289 ms) and about two were issued later; the last of the 12 votes was issued median 1.45 s, p90 2.36 s after the first determination. Holding for 1 s after the first build would have carried all 12 votes at 192 of 212 indices; the other 20 are one event, miners 01, 06 and 11 down together for 10 minutes across indices 377 to 396 (the afternoon `hop.sh` restarts), not relay lag. The fix (spec Q4, rule v3): the first certificate still forms at quorum, so lock latency is unchanged; once every voter has signed, or `certificate_fold` DAA seconds after the determination (3 on devnet, 6 on mainnet), a node rebuilds the certificate from every vote it has seen and gossips the heavier one, and every node replaces a held certificate with a verified heavier one over the same block. Presence needs nothing: under the block reading of Q2 a late vote already counts once any block carries it. Unit test `fold_round_carries_late_votes_and_heavier_certificates_replace` (node, `processes::finality`). Network figures: `docs/bench-log.md`, "finality rule v3".
|
||||
|
||||
|
|
@ -1578,7 +1628,7 @@ the project lead's decision of 4 October 2026: the total-weight floor of Q3 is 2
|
|||
- **F16** (a lock can become uncertified after a heal). Status: rule unchanged (spec 3.11.4: a verified certificate is never withdrawn, O-3.17 implements the conflict report). What the floor changes is how the state F16 describes arises: two certificates at one index now need equivocators holding at least one third of total weight in every scenario (two certificates need 4/3 of weight in signatures), not 13.3% across a partition that outlasts the presence decay (`sim/results_v2.md` H at 2/3: 0 conflicts and no lock on either side through a 33% equivocator, conflicts from minute 0 at 34%). Ten days of 100% hashrate in public, or the long-partition case of F21.
|
||||
- **F18** ("a silent minority cannot freeze finality" is false under the floor). Status: Fixed again (4 October 2026). The litepaper now says a lock needs two thirds of all 30-day weight and that finality pauses whenever less than two thirds is connected and signing. The pause threshold moved from about 42% of weight silent to one third: in the model, whose keys are in outage 2.2% of the time, 30% silent locks every checkpoint, 32% locks 88%, 33% locks 11% and 34% locks none for as long as it stays silent (`sim/results_v2.md` L1). Was: Fixed (56.7% sentence).
|
||||
- **F9** (half the hashrate leaves and finality stalls for ten days). Status: Conceded, stated (4 October 2026). Under the 2/3 floor the critic's number is back: 50% churn pauses finality for 10 days and 35% churn for 1.4 days, until the departed weight ages out of the window (`sim/results_v2.md` D's total column, which the 2/3 floor equals arithmetically, and L2). The chain runs on proof of work meanwhile, the node reports the pause, and the litepaper says so. This is the price of the one-third safety bound and was taken knowingly. Was: Answered by design (the active denominator recovered in two hours).
|
||||
- **F21** (new, from attack scenario 6A). "Your floor is a fraction of a table each side computes for itself. Cut the network in half and leave it cut: after a while each half's window is full of its own blocks, each half holds two thirds of its own table, and both lock without any attacker at all. Your simulation never saw it because it kept the weights global." Status: Fix built, pending rollout (4 October 2026, evening): rule v3, spec 3.3 Q5, the frozen weight table, on the node's `finality-fixes` branch behind `finality_v3_activation_daa` (`docs/plans/finality-v3-rollout-devnet.md`). The rule: a certificate also needs its signers to hold two thirds of the weight table at the last certified checkpoint on C_i's chain, at that table's weights, while that checkpoint is less than one window old. Both sides of a partition share that table and neither can fill it, so no side under two thirds locks until 30 days have passed without a certified checkpoint; at the heal locking resumes on one chain. Proved first in `sim/finality_v2.py` scenario M (`sim/results_v2.md`, "Rule v3"): 50/50, 60/40 and 55/45 splits never lock in 12 days (v2: days 10.2, 5.2, 7.9), both sides of a 31-day split lock alone at day 30.00 when the frozen table expires, the 70/30 majority locks at once under both rules, every pre-heal lock is kept and the first lock after the heal comes 0 minutes in, the 34% equivocator still conflicts (the one-third bound of 3.11.2 is untouched). The price, stated in 3.7 item 2: a set of one third or more that stops mining and signing at once pauses finality for 30 days (v2: 1.7 days at 35%, 10.1 at 50%); a gradual departure costs nothing because every certified checkpoint re-freezes the table. A view still cannot count blocks it has never seen, so a partition longer than a window forks as before; the fix moves the bound from a third of the window to the whole of it. Node: `processes::finality` (`frozen_table`, the Q5 test in `evaluate`), unit test `frozen_table_holds_a_side_without_the_other_keys_for_one_window`; network figures in `docs/bench-log.md`, "finality rule v3". Was: Conceded, stated (4 October 2026): spec 3.3.1, 3.7 item 9, 3.9 guidance; `sim/results_v2.md` L4 (view-local weights). Correct. A side with pre-split share s holds s + (1 - s) t / 30 of its own table on day t and two thirds of it from day 30 (2/3 - s) / (1 - s): day 10 at 50/50 (day 4 under the old floor), day 5 for the 60 side of 60/40 (at once under the old floor). On the devnet the old floor fell at 84 s of a young 1,439-DAA window (`docs/bench-log.md`, "finality v2 attack harness", S6A); at 2/3 the same cut on a full 1,800-DAA window held for the whole 150-s split and fell at 205 s against a predicted W / (3R) = 200 s (`docs/bench-log.md`, "finality floor 2/3", 6A and 6A long heal). What the devnet adds to the simulation: after the heal the other side's blocks are merged red, so each side's own share jumps rather than drifts, both sides of a 50/50 split certify their own checkpoints within 10 s of each other, and F1 then pins each node to its own certified chain: 26 conflicting certificates and 23 disagreeing locked indices across three nodes, no equivocation, a finality fork that the network heal did not undo and that only an operator's trusted certificate (F5, not implemented) can resolve. No rule removes it, because a view cannot count blocks it has never seen; the floor at two thirds moved the day from 4 to 10, and the exchange guidance treats a node partitioned for more than a day as proof of work until it has rejoined. A rule option for gate 3, not adopted: evaluate the floor against the table of the last locked checkpoint while no newer lock exists, which trades F9's 10-day recovery for a manual override.
|
||||
- **F21** (new, from attack scenario 6A). "Your floor is a fraction of a table each side computes for itself. Cut the network in half and leave it cut: after a while each half's window is full of its own blocks, each half holds two thirds of its own table, and both lock without any attacker at all. Your simulation never saw it because it kept the weights global." Status: Fixed in the node and shipped, rule not yet activated on the live devnet (5 October 2026, evening sweep: the code has shipped in every node since 0.3.4 and the switch `finality_v3_activation_daa` is absent from the live override file, default never; the F22 entry above carries the evidence; the overlay-against-GHOSTDAG run of C4 exercised rule v3 on the live node line on the fast-time harness tonight; decision owner for N3: the project lead). Was: Fix built, pending rollout (4 October 2026, evening): rule v3, spec 3.3 Q5, the frozen weight table, on the node's `finality-fixes` branch behind `finality_v3_activation_daa` (`docs/plans/finality-v3-rollout-devnet.md`). The rule: a certificate also needs its signers to hold two thirds of the weight table at the last certified checkpoint on C_i's chain, at that table's weights, while that checkpoint is less than one window old. Both sides of a partition share that table and neither can fill it, so no side under two thirds locks until 30 days have passed without a certified checkpoint; at the heal locking resumes on one chain. Proved first in `sim/finality_v2.py` scenario M (`sim/results_v2.md`, "Rule v3"): 50/50, 60/40 and 55/45 splits never lock in 12 days (v2: days 10.2, 5.2, 7.9), both sides of a 31-day split lock alone at day 30.00 when the frozen table expires, the 70/30 majority locks at once under both rules, every pre-heal lock is kept and the first lock after the heal comes 0 minutes in, the 34% equivocator still conflicts (the one-third bound of 3.11.2 is untouched). The price, stated in 3.7 item 2: a set of one third or more that stops mining and signing at once pauses finality for 30 days (v2: 1.7 days at 35%, 10.1 at 50%); a gradual departure costs nothing because every certified checkpoint re-freezes the table. A view still cannot count blocks it has never seen, so a partition longer than a window forks as before; the fix moves the bound from a third of the window to the whole of it. Node: `processes::finality` (`frozen_table`, the Q5 test in `evaluate`), unit test `frozen_table_holds_a_side_without_the_other_keys_for_one_window`; network figures in `docs/bench-log.md`, "finality rule v3". Was: Conceded, stated (4 October 2026): spec 3.3.1, 3.7 item 9, 3.9 guidance; `sim/results_v2.md` L4 (view-local weights). Correct. A side with pre-split share s holds s + (1 - s) t / 30 of its own table on day t and two thirds of it from day 30 (2/3 - s) / (1 - s): day 10 at 50/50 (day 4 under the old floor), day 5 for the 60 side of 60/40 (at once under the old floor). On the devnet the old floor fell at 84 s of a young 1,439-DAA window (`docs/bench-log.md`, "finality v2 attack harness", S6A); at 2/3 the same cut on a full 1,800-DAA window held for the whole 150-s split and fell at 205 s against a predicted W / (3R) = 200 s (`docs/bench-log.md`, "finality floor 2/3", 6A and 6A long heal). What the devnet adds to the simulation: after the heal the other side's blocks are merged red, so each side's own share jumps rather than drifts, both sides of a 50/50 split certify their own checkpoints within 10 s of each other, and F1 then pins each node to its own certified chain: 26 conflicting certificates and 23 disagreeing locked indices across three nodes, no equivocation, a finality fork that the network heal did not undo and that only an operator's trusted certificate (F5, not implemented) can resolve. No rule removes it, because a view cannot count blocks it has never seen; the floor at two thirds moved the day from 4 to 10, and the exchange guidance treats a node partitioned for more than a day as proof of work until it has rejoined. A rule option for gate 3, not adopted: evaluate the floor against the table of the last locked checkpoint while no newer lock exists, which trades F9's 10-day recovery for a manual override.
|
||||
|
||||
### M24. Your two-lane controller oscillates for an hour when a second miner joins mid-epoch
|
||||
"Watched your devnet this morning. The second 5090 came in at 10:12 and the difficulty never settled: 102M to 164M for forty minutes, 54 to 81 blocks a minute, three or four clamp steps stacked inside a second. Your fast lane and your slow lane disagree by a hair under the trigger and the rule flips between them every two minutes. One card joining is the mildest event a chain can see."
|
||||
|
|
@ -1655,7 +1705,7 @@ Evidence: `docs/design/execution-layer.md` 6, 5.6, 9.1 R12; spec 5.7; ledger P7;
|
|||
Review: `docs/review/round-4-2026-10-04.md`. Scope: devnet v4 through `a21ff239` (HEAD `3bfe346f`), the prebuilt workers, the Igneum Miner app 0.3.1 to 0.3.3, the relay, the Windows CI, the downloads host, the live site and the economics after the day's measurements. No secret value appears in any entry; comparisons were count-only.
|
||||
|
||||
### X23. One shipped key is an administrator channel to the founder's PCs
|
||||
"Your relay accepts either the URL token or the `x-igneum-key` header for everything, including queuing PowerShell that the PC agent runs as administrator. The key is the log-intake key, a literal in six tracked files and inside every Windows and prover package you have handed out. And the zip with both relay secrets sits on the downloads host behind the dl token, which is in your git history and in every installed app. One token, four hops, no privilege boundary."
|
||||
"Your relay accepts either the URL token or the `x-igneum-key` header for everything, including queuing PowerShell that the PC agent runs as administrator. The key is the log intake key, a literal in six tracked files and inside every Windows and prover package you have handed out. And the zip with both relay secrets sits on the downloads host behind the dl token, which is in your git history and in every installed app. One token, four hops, no privilege boundary."
|
||||
|
||||
Status: Open, fatal as an operational fact (4 October 2026). The agent was live and elevated on PC 1 at 13:41 UTC (`GET machines`, read-only). Sweep (5 October 2026): the relay token was rotated on 4 October (`~/.config/igneum/relay-token.old-2026-10-04` sits beside the new one); `POST task` with `kind: run` still needs only the token (`relay/api/relay.mjs:114-119`, no per-machine secret or signature), so the operational half stands. The 401 test needs the deployed relay and PC 1 (relay owner; rotation is the project lead's).
|
||||
|
||||
|
|
@ -1711,7 +1761,9 @@ Evidence: the files above.
|
|||
### G12. The PoW schedule comes from the environment on every network, including mainnet
|
||||
"Your mainnet gate refuses the override file. It does not refuse `IGNEUM_POW_EPOCH_BLOCKS`. A node without a file installs the schedule from the environment and `Params.pow_epoch_blocks` is never consulted."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, local worktree `vendor/igneum-node-fud`, no remote; main repo branch `fud-consensus`). Was: Open (4 October 2026).
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, local worktree `vendor/igneum-node-fud`, no remote; main repo branch `fud-consensus`). Was: Open (4 October 2026).
|
||||
|
||||
Sweep (5 October 2026, evening): measurement line: every node on the line prints `Consensus params digest: f10a4eab...` at start (node logs of PC 1, PC 2, the Mac, Sam's Mac and the US laptop, 5 October 2026, the digest with difficulty 33,000 and proving 84,100), and the environment variables have no reader left in the miner (`IGNEUM_POW_DAY_MS` moved into the template, M25 confirmed the day-mismatch rejection on 5 October). No mainnet node has been started; the mainnet refusal line is covered by the unit test `env_pow_schedule_is_devnet_and_simnet_only` only.
|
||||
|
||||
The fix: `PowSchedule::from_env()` is gone. `PowSchedule::from_env_for(network, base)` applies the three variables on devnet and simnet only and returns `None` elsewhere; the daemon calls `Params::apply_env_pow_schedule()` after the override file, prints "PoW schedule from the environment (...)" when applied and "Ignoring IGNEUM_POW_... on igneum-mainnet: the environment never sets a consensus parameter outside devnet and simnet" when not, then installs the network's schedule from `Params` on every network (`install_pow_schedule`), so `Params.pow_epoch_blocks` is what runs; the lazy fallback in `pow_schedule()` installs the devnet constants, never the environment. The miner takes all three schedule values from the template (`pow_epoch.day_ms` joined the two epoch fields in `PowEpochInfo`, the RPC model and the gRPC proto), so `IGNEUM_POW_DAY_MS` has no reader left in the miner (R4.1.9's day split is closed with it). The effective schedule is part of the params digest of X18, so a devnet node with the variable set cannot connect to one without it. Unit test `env_pow_schedule_is_devnet_and_simnet_only` (consensus-core, `config::params::tests`): the variable moves the devnet and simnet schedule and digest, leaves mainnet's and testnet's untouched, and the caller can tell "ignored" from "nothing set". Spec 2.8 and 8.7 state the rule.
|
||||
|
||||
|
|
@ -1729,7 +1781,7 @@ Answer: Correct. `.github/workflows/windows.yml` (step "payload inputs") checks
|
|||
Evidence: the files above. Experiment: alter one byte of a hosted `payload-inputs.zip` on a test folder and run the workflow; it must fail before the build.
|
||||
|
||||
### G14. Secrets and identity in the history of a repository with a public date
|
||||
"The intake key is in six files across eight commits, the dl token in one, the review and ledger files are tracked, 51 tracked files carry the founder's first name, and every commit today is stamped `+0100`. The 3 October sweep said zero hits."
|
||||
"The intake key is in six files across eight commits, the dl token in one, the review and ledger files are tracked, 51 tracked files carry the founder's first name, and every commit today is stamped with the local-time offset. The 3 October sweep said zero hits."
|
||||
|
||||
Status: Open (4 October 2026); extends `docs/fud-fixes.md` section 5.
|
||||
|
||||
|
|
@ -1740,7 +1792,9 @@ Evidence: `git ls-files | xargs grep -lF <value>` counts, `git log -S`. Experime
|
|||
### X18. Two nodes with two override files connect, and only some mismatches fork
|
||||
"Your handshake compares the network name and nothing else. A PoW or difficulty mismatch forks and bans; a `finality` mismatch is a WARN; `rollout-v2.sh` throws the finality block away when it writes the file; the app rewrites the packaged file on every start."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026).
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026).
|
||||
|
||||
Sweep (5 October 2026, evening): measurement line, live: the digest refused a real mismatch the morning it shipped. A hand node restarted early with another `proving_v0_activation_daa` was refused by every peer for 20 minutes (bench-log "live devnet: the first shards proven"); the node logs carry 115 `consensus params digest mismatch` lines on PC 1, 46 on PC 2 and 56 on the Mac between 08:15 and 08:35 BST on 5 October 2026 (`Refusing peer ...: consensus params digest mismatch, local f10a4eab... remote a6da35e8...`), none since. Still open from this entry: the digest-less allowance on devnet and simnet (to remove), `rollout-v2.sh` still writes the file as two fields (R4.1.12).
|
||||
|
||||
The fix: `Params::consensus_digest()` (BLAKE2b-256, domain `IgneumParamsDigest`, every consensus field in a fixed tagged order: genesis, difficulty, mass and lane limits, blockrate, crescendo, the ten finality fields, the PoW schedule, the three activation heights; not the dead `timestamp_deviation_tolerance`, not seeders or ports; spec 2.8 lists it). The version message carries it (`paramsDigest`, field 11); `initialize_connection` refuses a peer whose digest differs with `ProtocolError::ParamsDigestMismatch` and one WARN naming both digests before any flow is registered, so a finality-only mismatch, which used to connect and WARN "names N voters" after the fact, never connects. A peer with no digest (an older build) is refused on mainnet and testnet and let in with a WARN on devnet and simnet while the devnet rolls (an allowance to remove afterwards). The node prints its digest at start. Unit test `consensus_digest_covers_every_consensus_field_and_nothing_else`. Measured (`docs/bench-log.md`, "round-4 consensus items", digest run; `tools/finality-attacks/fud.mjs digest`, fast time, ports 29400+): a listener on the shared fast-time override and a dialler whose finality block differs by one DAA second of window: the dialler was refused at the handshake on both sides ("Refusing peer ...: consensus params digest mismatch, local 4bf7... remote 7a40..." on the listener, the reject message on the dialler), 0 peers after 25 s on both; a third node on the shared override connected in 1 s. Control on the finality-fixes build 6aa69a45: the mismatched dialler connected (1 peer, no line). `rollout-v2.sh` still rewrites the file as two fields and the app still rewrites the packaged file (R4.1.12): with the digest both now fail loudly at the handshake instead of forking; the merge fix for the script is not done tonight.
|
||||
|
||||
|
|
@ -1751,7 +1805,9 @@ Evidence: the files above. Experiment: two nodes on different files; the handsha
|
|||
### F23. The equivocation ban is node-local, so honest nodes refuse each other's certificates
|
||||
"Evidence detected from an RPC vote stamps the sink's DAA; evidence carried in a block stamps the carrier's DAA. Two honest nodes hold different `until` for the same key, their voter lists differ by one at every checkpoint between the two expiries, and `voter_count` refuses the other's certificate for good."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026); reproduced by the red team the same evening on the stock s1 scenario (n0 kept the ban until DAA 726 against 239 on n1 and n2, 9 and 3 to 4 certificates refused "names N voters").
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026); reproduced by the red team the same evening on the stock s1 scenario (n0 kept the ban until DAA 726 against 239 on n1 and n2, 9 and 3 to 4 certificates refused "names N voters").
|
||||
|
||||
Sweep (5 October 2026, evening): measurement line, live: the persisted finality state converted on the upgrade on every machine (`Finality: state blob of layout 1 read and converted (0 evidence records)` once on PC 1, PC 2, the Mac, Sam's Mac and the US laptop, 5 October 2026), no node lost its locks, and in the 10 hours to 15:45 UTC the node logs of the five app machines carry 0 certificates refused "names N voters", 0 CONFLICTING and 0 EQUIVOCATION lines against 5,243 LOCKED lines (intake query over every `nodelog-*` upload, split per line server-side). No equivocation has happened on the live devnet, so the ban path itself is exercised only by the fast-time run below (`fud.mjs ban`: voter lists agree on three nodes at every index, 0 refusals).
|
||||
|
||||
The fix: the node-local `stripped` map is gone. Evidence is kept as `EvidenceRecord` (the two votes, the carriers with their DAA scores) and the ban at a checkpoint C is a function of C's past (`bans_at`): the key is stripped at C when some carrier lies in C's past and `daa(C) < daa(lowest carrier in C's past) + ban`. Evidence detected over RPC or gossip strips nothing until a block carries it; the node puts it in its next templates. The weight table cache stays ban-free and `voters_at` applies the checkpoint's own bans, so a certificate built before the carrier existed verifies on a node that saw the evidence later, and a node that saw it over RPC counts the same voters as one that saw it in the block. Evidence records are bounded (4,096; dropped once the ban ended two windows below the sink or never carried within one ban of being seen; 16 carriers per record), the same for vote and certificate carriers. The persisted state is layout 2; a layout-1 blob is read and converted on start, so no devnet node loses its locks on the upgrade. Unit test `ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list` (three `TestConsensus` nodes on one chain: the voter list agrees on all three at every checkpoint, the key is a voter before the carrier and after the ban and nowhere in between, the third node verifies the first two's certificates at every locked index). Measured (`docs/bench-log.md`, "round-4 consensus items", ban run; `fud.mjs ban`, 480 s, six voters, one equivocation at index 9 by a voter on n0 over RPC, n2 cut off 45 s around it and healed, so it saw the evidence late from the carrier block): on the `fud-consensus` build every node names 5 voters at the same indices (10 to 12 in the final pass, 10 to 13 in the first), 0 certificates refused "names N voters", 0 conflicting certificates, 0 locked indices disagreeing, voter counts agree at every index with lines on two or more nodes, locks continue to index 14 or 15 on all three. Control on the finality-fixes build: n0 (the RPC detector) refused 2 certificates "names N voters, this node counts M", the rest agreed because each node built its own; the red team's stock s1 scenario the same evening gave 9 / 3 / 4 refusals. Spec 3.6 and the 3.10 row state the rule.
|
||||
|
||||
|
|
@ -1764,7 +1820,9 @@ Red-team run, 4 October 2026 (evening, the 0.3.4 finality-fixes build with rule
|
|||
### F24. A checkpoint determination is never revisited
|
||||
"After a reorg deeper than `checkpoint_depth`, the node's record for that index names a block off its chain. Every certificate the network forms for that index is refused as conflicting, with no equivocation anywhere, and the node voted for a block that is not on its chain."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026); extends F7 and C4.
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026); extends F7 and C4.
|
||||
|
||||
Sweep (5 October 2026, evening): measurement line, live: the re-determination fired on the real devnet and left no hole. Checkpoints 2970 and 2971 were re-determined at 10:56:44 to 10:56:45 BST on 5 October 2026 on PC 1, PC 2 and the Mac at once (`Finality: checkpoint 2971 re-determined: block bb4aa204...` on all three, 7 / 8 / 4 re-determined lines per machine over the day including the first-start ones at indices 704 to 722), with 0 CONFLICTING lines and 0 refusals anywhere in the 10 hours to 15:45 UTC, and the three nodes' later locks agree (the console's last lock #3646 at 15:46 UTC). Before this fix the same event would have logged CONFLICTING for every certificate at the moved index and left the index unlocked on the losing side.
|
||||
|
||||
The fix: after every virtual change, every unlocked checkpoint record whose block is no longer a chain ancestor of the sink is determined again on the new chain ("re-determined" log line); the certificate held over the old block is dropped, the fold clock restarts. A certificate over a block other than the node's determination at an unlocked index (or at an index not yet determined, up to 64 ahead) is no longer logged CONFLICTING and discarded: it is held pending (4 per index) and verified when a re-determination names its block; a block that cannot be the index's checkpoint on any chain (C1 as a function of the DAG: blue score under the target, or the selected parent's not) is refused outright. CONFLICTING now means what 3.11.4 says: a certificate against a LOCK. The certificate verification itself is unchanged; a locked index is never re-determined (fork choice keeps the chain through it). The node's own keys do not re-vote at a re-determined index (that would be equivocation); the lock there comes from the network's certificate, which is the point. Unit tests `reorg_past_an_unlocked_checkpoint_re_determines_it_and_verifies_the_pending_certificate` and `a_locked_checkpoint_pins_the_chain_and_a_certificate_against_it_conflicts`. Measured (`docs/bench-log.md`, "round-4 consensus items", reorg run; `fud.mjs reorg`, n0 with 30% of the weight cut off for 180 s while the 70% side kept locking, then healed): on the `fud-consensus` build n0 re-determined its own 1 to 2 split indices on the majority chain, verified the pending certificates at determination (2 in the final pass), logged 0 CONFLICTING and 0 refusals, and ended with every index the majority locked locked on the same block (0 disagreeing). Control on the finality-fixes build: n0 refused 3 certificates "is for X, this node's checkpoint is Y" and never locked indices 8 and 9 that the majority locked (the permanent hole of this entry), 0 disagreeing because the hole is not a lock. The final pass also found that a chain which becomes the sink at a lower blue score than the old one (more blue work per block after the split's difficulty drift) re-determined index 9 at a sink below its depth, to a block below the target: fixed the same night (an index the new chain has not reached is un-determined and determined again when it has; unit test `a_shallower_sink_un_determines_the_indices_it_cannot_reach`) and re-run (`reorg-final2`, fork 977db931): the majority locked nothing during the split this time (Poisson again), n0 re-determined its one split index, verified 1 pending certificate at determination, 0 CONFLICTING, 0 refused, 0 disagreeing, no record below its target, every index the majority locked locked on n0 too. The red team's own reproductions on the new build (`tools/finality-attacks/redteam/rtfin.mjs`, fin-attacks miner at 6 blocks/s): `f24c` (3/3 split, 16 s cut) PASS with 0 refusals, 0 CONFLICTING, 0 stuck indices, 0 disagreeing; `f24b` (4/2 split, 24 s cut) FAIL on both builds for a reason outside F24: at 6 blocks/s the DAA score advances 6 a second, so the 24-s cut is 144 DAA, longer than the 120-DAA weight window and the 60-DAA merge depth; the two chains cannot merge at the heal and each side's table holds only its own keys (n1's lone locks read "100.0% of total, 100.0% of the table frozen at lock 39"), which is the partition longer than a window that spec 3.7 item 9 states and F21 conceded, not a reorg. The scenario's "under merge depth" assumes 1 DAA a second. Spec 3.2 C1 and C4, and the 3.10 rows, state the rule.
|
||||
|
||||
|
|
@ -1777,7 +1835,7 @@ Red-team run, 5 October 2026, 00:56 (the 0.3.4 finality-fixes build, rule v3 on,
|
|||
### F25. The fast-time harnesses cannot start a node, and the timestamp probe tests the old rule
|
||||
"Both attack harnesses rebuild each node's override with `JSON.parse` and `JSON.stringify` of `infra/fast-time/override-60x.json`. That file now carries two `u64::MAX` sentinels (`difficulty_v2_activation_daa`, `proving_v0_activation_daa`); a JavaScript number cannot hold them, the round-trip writes `18446744073709552000`, and `igneumd` refuses the file as a floating point where a u64 is expected. Every `--fast-time` run of `tools/finality-attacks` and `tools/harness` fails at the first node. Scenario 2 of `tools/harness` still probes the 132 s future bound and reports FAIL against the 10 s rule the node has carried since the timestamp fix."
|
||||
|
||||
Status: Fixed in both harnesses (4 October 2026, night: `tools/finality-attacks/lib/net.mjs` kept the sentinels as BigInt through the merge since the v3 runner of the evening; `tools/harness/lib/net.mjs` got the same reviver on branch `fud-memory`, merged into `fud-consensus`); the stale timestamp criterion of scenario 2 is not touched. Was: Open (4 October 2026, red-team run). Tooling, low severity: no consensus effect, but every fast-time attack run is blind until it is fixed.
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: both harness libraries reached master with the `fud-consensus` merge 7abce72 of the 0.3.5 cut; the sweep of 5 October ran `run.mjs s4` and `s5 --fast-time`, `fud.mjs` and tonight's `c4.mjs` through them, every node started). Was: Fixed in both harnesses (4 October 2026, night: `tools/finality-attacks/lib/net.mjs` kept the sentinels as BigInt through the merge since the v3 runner of the evening; `tools/harness/lib/net.mjs` got the same reviver on branch `fud-memory`, merged into `fud-consensus`); the stale timestamp criterion of scenario 2 is not touched. Was: Open (4 October 2026, red-team run). Tooling, low severity: no consensus effect, but every fast-time attack run is blind until it is fixed.
|
||||
|
||||
Answer: Correct, measured. The red-team run's first scenario errored on it (`docs/review/redteam-2026-10-04.md`, "Tooling defect"); `tools/proving-v0/run.mjs` already edits the file as text for this reason. Scenario 2 live probe: past floor pmt+1, future flip between +130.00 and +130.01 s of the probe's own offsets, every stamp from +10 s rejected; the node is right, the criterion is stale. Smallest fix: in `tools/finality-attacks/lib/net.mjs` and `tools/harness/lib/net.mjs` `overrideParams`, drop the two sentinel fields before `stringify` (absent means never) or splice the extra fields into the file text; in `tools/harness/scenarios/s2-timestamp.mjs`, probe `max(pmt + 1, parent - 10 s)` and the +10 s bound. Also stale: `tools/exec-attacks/scenario3_pgas.mjs` waits for an over-budget transaction to be included and skipped with `BlockProvingBudget`; since F-exec-B the mempool refuses it with the metered pgas, so the check should accept `ProvingGasAboveBlockLimit` from the pool (`docs/review/redteam-2026-10-04.md` row 28). And `tools/finality-attacks` scenario 5 compares the burster's share of the weight window with its share of the whole run, which only agree when the run is shorter than the window (row 17).
|
||||
|
||||
|
|
@ -1813,10 +1871,10 @@ Evidence: the files above. Experiment: `igneum-miner` with `IGNEUM_POW_DAY_MS=14
|
|||
### M26. The interval fault guard freezes its baseline and loops
|
||||
"On a trip you skip the STATUS print, so the baseline it would have updated stays frozen, and you roll the counters back to it. Any healthy rate over ten times a slow first interval trips again every interval, forever, with no STATUS line and no `faults=` for the app to read."
|
||||
|
||||
Status: Fixed (4 October 2026, evening), fork commits `aea5ac6d`, `501363e0` and `945153ab` on `miner-reliability` (`igneum/miner/src/guard.rs`; the second fixes a fill loop that spun forever after a guard kill, found by the test network). Replaced: Open (4 October 2026).
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: `miner-reliability` 945153ab merged into fork 20139145, `docs/plans/release-0.3.5.md` 1b; the guard tests in the 0.3.5 `igneum-miner` suite, 12 passed). Was: Fixed (4 October 2026, evening), fork commits `aea5ac6d`, `501363e0` and `945153ab` on `miner-reliability` (`igneum/miner/src/guard.rs`; the second fixes a fill loop that spun forever after a guard kill, found by the test network). Replaced: Open (4 October 2026).
|
||||
|
||||
Fix: `IntervalGuard` builds its baseline from the healthy intervals of the current worker process (a moving average, two intervals before it can trip) and forgets it when the worker restarts; the STATUS line is printed on a trip, with `faults=`; `RestartPolicy` restarts a guard-killed worker after 2 s, doubling per trip inside ten minutes, and the third trip ends the miner with exit 43 so the app shows a faulted card instead of a loop. The 60 s no-line timeout no longer skips the guards and the STATUS line. Measured against a fake worker on a private test network: `docs/bench-log.md`, "4 October 2026, miner fault guards and the app watchdog measured against a fake worker".
|
||||
Status: Fix built (4 October 2026, branch `miner-reliability` of the node, `aea5ac6d`), pending merge and a run on a PC. `IntervalGuard`: the baseline is a moving average of the worker process's healthy intervals, forgotten on a restart; the STATUS line is printed on a trip with `faults=`. `RestartPolicy`: 2 s, doubling inside ten minutes, the third trip exits 43 so a supervisor can mark the card. Unit tests in `guard.rs` replay the slow-first-interval case and the back-off. The GPU stress run (`--status-secs 10` with a stress tool for 15 s) needs a PC (hardware). Was: Open (4 October 2026).
|
||||
Sweep (5 October 2026, evening): measurement line, live, from the five app machines' miner logs over the 20 hours to 15:30 UTC: on the 0.3.5 to 0.3.8 miners every PC fault line is of one kind and rare (PC 1: 2 `WORKER FAULT` lines in the 07:00 hour and 4 in the 10:00 hour, PC 2: none after 03:00 UTC), the `no job completed ... killing the worker, it restarts` guard fired 43 times on PC 1 and 40 on PC 2 in the whole window, every time with a restart and a STATUS line afterwards, and the console shows 0 faults and 0 restarts on every card at 15:46 UTC. The loop this entry describes (a trip every interval for ever) does not appear on any machine since the 0.3.5 start. Earlier line, kept for the record: Fix built (4 October 2026, branch `miner-reliability` of the node, `aea5ac6d`), pending merge and a run on a PC. `IntervalGuard`: the baseline is a moving average of the worker process's healthy intervals, forgotten on a restart; the STATUS line is printed on a trip with `faults=`. `RestartPolicy`: 2 s, doubling inside ten minutes, the third trip exits 43 so a supervisor can mark the card. Unit tests in `guard.rs` replay the slow-first-interval case and the back-off. The GPU stress run (`--status-secs 10` with a stress tool for 15 s) needs a PC (hardware). Was: Open (4 October 2026).
|
||||
|
||||
Answer: Correct. `igneum/miner/src/main.rs:1404-1418` with the update at `:1452-1454` skipped by `continue`; the restart has no cap and no growing back-off (`:1213-1216`). A slow first interval (a game on the GPU, a foreground self-heal build on a slow card) is enough. Fix: update the baseline on a trip, or compare to the previous interval; cap restarts with a growing back-off. Review id R4.2.1.
|
||||
|
||||
|
|
@ -1825,8 +1883,8 @@ Evidence: the file above. Experiment: `--status-secs 10` with a GPU stress tool
|
|||
### M27. A flapping node makes the worker rebuild once per template
|
||||
"A prepare goes out whenever the wanted pair differs from the prepared one. No count, no interval, no once-per-epoch. Each one writes a pack on the CPU with the job loop stalled and costs the worker a full build; `prepare-failed` resends on the next fill."
|
||||
|
||||
Status: Fixed (4 October 2026, evening), fork commit `aea5ac6d` on `miner-reliability` (`guard::PrepareLimiter`): one `prepare` per pair per epoch, one retry after `prepare-failed`, none within 30 s of the last; a held prepare is printed once (`PREPARE held ...`). Measured with a worker that refused every prepare across three epochs: `docs/bench-log.md`, the same entry as M26. Replaced: Open (4 October 2026).
|
||||
Status: Fix built (4 October 2026, branch `miner-reliability`, `aea5ac6d`), pending merge. `PrepareLimiter`: one prepare per pair per epoch, one retry after prepare-failed, none within 30 s of the last, a held prepare said once; a unit test replays a flapping node. The fast-time simnet with a flipping `next_epoch_seed` was not run (it needs a patched node and a GPU worker). Was: Open (4 October 2026).
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5, as M26). Was: Fixed (4 October 2026, evening), fork commit `aea5ac6d` on `miner-reliability` (`guard::PrepareLimiter`): one `prepare` per pair per epoch, one retry after `prepare-failed`, none within 30 s of the last; a held prepare is printed once (`PREPARE held ...`). Measured with a worker that refused every prepare across three epochs: `docs/bench-log.md`, the same entry as M26. Replaced: Open (4 October 2026).
|
||||
Sweep (5 October 2026, evening): measurement line, live, the exact failure this entry predicts happened on the 0.3.4 miners and stopped with 0.3.5. Between 01:24 and 02:59 UTC on 5 October 2026 both PCs' NVIDIA workers refused the prepared pack for epoch 1130e9ea... (`prepare-failed ...: the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT`) and the 0.3.4 miner re-sent the prepare every 0.7 s: 4,299 `prepare-failed` lines on PC 1 and 4,233 on PC 2 in two hours, with 3,609 and 3,494 `WORKER FAULT seed mismatch` lines, two boundaries (DAA 61,200 and 64,800) crossed by inline compile instead of a swap on both PCs. From the 0.3.5 start (07:15 UTC) to 15:30 UTC: 0 `prepare-failed` lines on any machine, 4 and 4 `WORKER FAULT` lines, and every boundary from DAA 68,400 to 111,600 swapped with no pause on both PCs (intake query over the `miner-*` uploads, `docs/bench-log.md`, "FUD ledger sweep round 6", M11). The flapping-node simnet was not run; the live storm stands in for it. Earlier line, kept for the record: Fix built (4 October 2026, branch `miner-reliability`, `aea5ac6d`), pending merge. `PrepareLimiter`: one prepare per pair per epoch, one retry after prepare-failed, none within 30 s of the last, a held prepare said once; a unit test replays a flapping node. The fast-time simnet with a flipping `next_epoch_seed` was not run (it needs a patched node and a GPU worker). Was: Open (4 October 2026).
|
||||
|
||||
Answer: Correct. `igneum/miner/src/main.rs:1113-1165, 1337-1339`; `worker.cpp:644-658`; `host.c:1208-1225`. Estimated loss 30 to 60 percent against a node that alternates seeds per template; a stale home node on a fork is the realistic trigger. Fix: at most one prepare per pair per epoch and none within 30 s of the last. Review id R4.2.2.
|
||||
|
||||
|
|
@ -1844,8 +1902,8 @@ Evidence: the files above. Experiment: a tampered pack with matching vectors mus
|
|||
### X21. A wrong program burns power with a green rate
|
||||
"The CPU re-check counts mismatches and does nothing: no threshold, no stop. The app reads `hash`, `now`, `template_age` and `synced` from STATUS and nothing else, so `mismatched=` and `WORKER FAULT` never reach the card."
|
||||
|
||||
Status: Fixed (4 October 2026, evening), fork commit `aea5ac6d` (`guard::MismatchGuard`: three consecutive CPU re-check mismatches kill the worker, `WORKER FAULT cpu re-check ...`) and app commit `f39e240` on `miner-reliability` (`app/igneum-app/src/watchdog.rs`: the app reads `mismatched=`, `faults=` and the `WORKER FAULT` lines, shows them on the card, and its own watchdog restarts a miner once for no status in 90 s or a zero rate for 60 s while synced, then marks the card faulted; a silent node is restarted in-process). Measured: `docs/bench-log.md`, the same entry as M26. Replaced: Open (4 October 2026).
|
||||
Status: Fix built (4 October 2026): `MismatchGuard` on branch `miner-reliability` (`aea5ac6d`) kills the worker after three consecutive CPU re-check mismatches (`WORKER FAULT cpu re-check`), and the app reads `mismatched=` and `WORKER FAULT` on branch `release-0.3.5` (`app/igneum-app/src/engine.rs`, 3 matches; 0 on master). Pending merge and release; the edited-kernel test needs a GPU worker (hardware). Was: Open (4 October 2026).
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: the miner half with `miner-reliability` in fork 20139145, the app half with app commit f7d2af7 of the 0.3.5 branch, `docs/plans/release-0.3.5.md` 1a). Was: Fixed (4 October 2026, evening), fork commit `aea5ac6d` (`guard::MismatchGuard`: three consecutive CPU re-check mismatches kill the worker, `WORKER FAULT cpu re-check ...`) and app commit `f39e240` on `miner-reliability` (`app/igneum-app/src/watchdog.rs`: the app reads `mismatched=`, `faults=` and the `WORKER FAULT` lines, shows them on the card, and its own watchdog restarts a miner once for no status in 90 s or a zero rate for 60 s while synced, then marks the card faulted; a silent node is restarted in-process). Measured: `docs/bench-log.md`, the same entry as M26. Replaced: Open (4 October 2026).
|
||||
Sweep (5 October 2026, evening): measurement line, live: every STATUS line of every card on the five machines carries `mismatched=0` and `faults=0` and the console reads the fields (Machines card at 15:46 UTC on 5 October 2026: `0 mismatched, 0 restarts` per card, `0 faults` per machine), so the path from the miner's counter to the card exists on the fleet; the edited-kernel test that would turn a card red was not run (it needs a hand-edited pack on a PC). Earlier line, kept for the record: Fix built (4 October 2026): `MismatchGuard` on branch `miner-reliability` (`aea5ac6d`) kills the worker after three consecutive CPU re-check mismatches (`WORKER FAULT cpu re-check`), and the app reads `mismatched=` and `WORKER FAULT` on branch `release-0.3.5` (`app/igneum-app/src/engine.rs`, 3 matches; 0 on master). Pending merge and release; the edited-kernel test needs a GPU worker (hardware). Was: Open (4 October 2026).
|
||||
|
||||
Answer: Correct. `igneum/miner/src/main.rs:1250-1261`; `app/igneum-app/src/engine.rs:~1762-1780` (zero matches for either string). The PowerShell launcher matches them (`igneum-common.ps1:843`), which is what README.txt and TEST.md describe. Fix: stop the worker after 3 consecutive mismatches and show it on the card; the app reads both fields. Review id R4.2.3.
|
||||
|
||||
|
|
@ -1890,7 +1948,9 @@ Evidence: the files above.
|
|||
### M30. A block or transaction flood grows the 0.3.4 node by hundreds of megabytes in a minute
|
||||
"On the 3 October ordering-layer node (no execution layer) the resource-exhaustion scenario grew RSS by 4, 11 and 14 MB and the 50x block flood by 30 MB. On the 0.3.4 build, same harness, same scenarios, same 60 s: template flood +6 MB, submit flood +269 MB, mempool flood +270 MB, block flood 302 to 1,082 MB on both nodes (567 MB at 10 s, 824 MB at 20 s). The harness calls it a pass because its bound is baseline + 512 MB; a peer that keeps going is not bounded by the harness."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, night; node branch `fud-memory`, merged into `fud-consensus`; main repo branch `fud-memory`, merged into `fud-consensus`). Was: Open (4 October 2026, red-team run). Serious: a single peer at 50 blocks/s or 500 transactions/s is the devnet's own fast-miner event, and a node that grows 13 MB/s under it runs out of memory in minutes on the 2 to 4 GB cloud nodes.
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-memory`, merged into `fud-consensus`; main repo branch `fud-memory`, merged into `fud-consensus`). Was: Open (4 October 2026, red-team run).
|
||||
|
||||
Sweep (5 October 2026, evening): measurement line, live: cache builds now equal node restarts, not epoch rolls. In the 10 hours to 15:45 UTC on 5 October 2026 the node logs show 5 `PoW cache built` lines on PC 1, 5 on PC 2, 8 on the Mac and 1 on Sam's Mac, each at a node start (the 0.3.5, 0.3.6, 0.3.7 and 0.3.8 restarts and the proving-activation restart), and none at the hourly boundaries: the swaps at DAA 108,000 (14:29 UTC) and 111,600 (15:29 UTC) built no cache on any machine (the last build on PC 1 is the 0.3.8 restart at 13:42 UTC). The 0.3.4 engine built one 256 MiB cache per hourly roll (about 270 MB an hour of growth on the app node). The 30 MB per 1,000 blocks of non-cache growth and the unbounded `ExecState.records` stay as stated. Serious: a single peer at 50 blocks/s or 500 transactions/s is the devnet's own fast-miner event, and a node that grows 13 MB/s under it runs out of memory in minutes on the 2 to 4 GB cloud nodes.
|
||||
|
||||
The cause, measured (not the one guessed below): every RSS step in both floods is one `PoW cache built` line, 256 MiB each. The lottery engine (`consensus/pow/src/igneum.rs`, `IgneumEngine`) keyed its resident entries by `(epoch seed, day)` and built a full 256 MiB cache per entry, `KEEP = 4`, although the cache depends on the day seed alone (`igneum_pow::Epoch::from_seed_bytes`: cache from the day bytes, program from the epoch seed). The floods ran on the 60x profile, where an epoch rolls every 60 DAA, so the 50x block flood rolled it every 10 to 20 s and paid a cache each time; the 3 October run was on the devnet profile (3,600-DAA epochs, no roll in 60 s), which is what differed, not the execution layer. The s6 figures were cumulative from one starting RSS: the mempool flood's "+270 MB" was the submit flood's growth carried forward (its own cost is 1 MB), and 197 chain blocks cost under 1 MB in `ExecState.records`. On the live devnet the same engine costs 256 MiB per hourly epoch roll up to `KEEP`, which is the steady-state growth the coordinator saw on the 0.3.4 app node (1,081 MB at 27 min, 2,258 MB at 4 h 14 min, about 270 MB an hour). The fix: caches keyed by day, `KEEP_DAYS = 3` (3 x 256 MiB resident, plus at most 2 in-flight builds), programs keyed by `(epoch seed, day)` at a few KB each (`KEEP = 8`, LRU); an epoch roll on the same day builds no cache; node and miner compute the identical hash through `EpochRef` (unit test `epoch_rolls_share_the_day_cache`). No consensus rule changed. Measured (`docs/bench-log.md`, "ledger M30", two-node fast-time floods, before on the shipping finality-fixes build, after on `fud-memory` 796f758d): s6 submit flood +263 / +257 MB with 1 cache build each, after +3 / +2 MB and 0 builds; s7 50x block flood 302 to 1,085 MB with 3 builds, after 302 to 318 MB and 0 builds; template and mempool floods unchanged at +6 and +1 MB. Steady state, measured on two nodes at 1 block/s with no flood for 1,500 blocks on the 60x profile (`tools/harness/scenarios/s8-steady.mjs`, bench-log "ledger M30", steady-state paragraph): the shipping build reached 1,342 MB by block 514 after 9 cache builds (one per epoch roll; five 256 MiB chunks, the fifth an evicted one the allocator keeps) and 1,371 MB at 1,529 blocks; the fixed build held 319 MB at 510 blocks with 1 build and 603 MB at 1,526 blocks with 2 (the fast-time day rolled once), so on the devnet profile it is 256 MiB flat, 512 MiB around midnight UTC, 768 MiB worst case. Both builds then climb 30 MB per 1,000 blocks (30.7 before, 30.2 after), which is not the PoW cache (72 MB of non-cache footprint at 1,526 blocks against 23 MB at 0; the reading, not a measurement, is the consensus database's buffers and rusty-kaspa's entry-sized caches filling); the live node's 36 MB per 1,000 blocks between epoch rolls fits it. The app node's 2,258 MB at 4 h 14 min exceeds what this node build can reach (about 1.7 GB at 15,000 blocks) and includes its GPU worker, which needs its own `vmmap -summary`. Still growing by design and not bounded tonight: `ExecState.records` (1 to 2 KB per chain block, approximate, 100 to 170 MB a day at 1 block/s; a window must cover the proving sortition window and the by-number RPC history), `SNAPSHOT_RING = 64` state clones scaling with state size, the finality key registry (grows with distinct vote keys; votes, certificates, locks and evidence are trimmed). The harness now reports per-load RSS deltas and cache-build counts and takes `IGNEUM_HARNESS_BASE_PORT` and `IGNEUM_HARNESS_TMP`.
|
||||
|
||||
|
|
@ -1901,7 +1961,9 @@ Evidence: `/tmp/igneum-redteam-ord/results/s6-exhaustion.json` and `s7-flood.jso
|
|||
### M31. The 0.3.4 node cannot produce a block template on mainnet, testnet or simnet parameters
|
||||
"`getBlockTemplate` on a `--simnet` node from the finality-fixes build answers every call with `Coinbase payload is above max length (204). Try to shorten the extra data.` and the network never makes a block. The coinbase of this build carries the vote-key reveal, the proof-record section and the finality section; only `DEVNET_PARAMS` was raised to `MAX_COINBASE_PAYLOAD_LEN_WITH_FINALITY` (16,384). `MAINNET_PARAMS`, `TESTNET_PARAMS` and `SIMNET_PARAMS` still carry Kaspa's 204 (`consensus/core/src/config/params.rs:705, 766, 828` against `:900`)."
|
||||
|
||||
Status: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`). Was: Open (4 October 2026, red-team run). Serious for anything that is not the devnet: a mainnet or testnet genesis on these parameters cannot be mined by a voting miner at all; harmless on the live devnet, whose parameters carry the raise.
|
||||
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`). Was: Open (4 October 2026, red-team run). Serious for anything that is not the devnet: a mainnet or testnet genesis on these parameters cannot be mined by a voting miner at all; harmless on the live devnet, whose parameters carry the raise.
|
||||
|
||||
Sweep (5 October 2026, evening): measurement line: the unit test `largest_coinbase_fits_on_every_network` passed in every 0.3.5 suite run (`cargo test -p kaspa-consensus-core`, 101 passed on the 0.3.6 fork tip a11455e7 on 5 October 2026, `docs/plans/release-0.3.6.md` 3b) and the testnet identity `igneum-testnet-1` adopted the same morning carries the raised limit with every switch at 0, so the first testnet genesis is mineable by a voting miner; no simnet network has been started since the cut, so the template line on simnet is covered by the test, not a run.
|
||||
|
||||
The fix: `max_coinbase_payload_len` is `MAX_COINBASE_PAYLOAD_LEN_WITH_FINALITY` (16,384) on mainnet, testnet and simnet as on devnet, and the template builder fits the finality section into what the payload has left (`finality::encode_section_within`, certificates first, then evidence, then votes; the RPC computes the budget from the fixed part, the script, the node version, the miner's extra data and the record section), so a coinbase can never exceed the limit on any network whatever the voter count. The worst case did not fit even on devnet before: 8 certificates over 8,192 voters, 8 pieces of evidence and 48 votes come to about 30 KB, so the per-item bounds alone were not a bound. Unit test `largest_coinbase_fits_on_every_network` (consensus-core): the fixed part, the version, a key reveal, a full record section (8 records of 274 bytes) and the cut finality section fit under every network's limit, the cut keeps every certificate and every piece of evidence and at least 8 votes, the uncut section would not fit, and a budget under one certificate yields an empty section. The exec-attacks network (`tools/exec-attacks/net.sh`, `--simnet`) can drop its override once this build ships; not re-run tonight.
|
||||
|
||||
|
|
@ -1960,7 +2022,7 @@ Evidence: the commits above. Experiment: `curl https://igneum.network/api/live`
|
|||
|
||||
- **Moved to Fixed or Rolled out, from evidence that already existed and had not reached the ledger:** M15 (cheap checks before the PoW engine, merged and live), M17 (hot swap, measured on the live devnet across three vendors), M19 (the census cells filled, 16 loads a Definition), M24 (rule v2 activated at DAA 33,000), P20 (the buffered save confirmed on the third run), X16 (the evidence page exists), G11 (the spec is public).
|
||||
- **Moved to Answered with evidence:** F1 (the first-month gate implemented, measured on 4 October and re-confirmed tonight on the finality-fixes build: the burster locks nothing alone; the launch month is arithmetic now), F7 (reorg depth p50 1, p99 3, max 5 on a 12-node, 5-region network), F19 (bought keys are worth their blocks; scenario K at both floors), E12 (the simulation half), E15 (the security-budget model: the floor is crossed in year 7, 11 or never by price, and no fee level moves it).
|
||||
- **Fix built on a branch, pending merge or rollout:** M26, M27, X21 (`miner-reliability` `aea5ac6d`, with the app half on `release-0.3.5`), F22 (rule v3, fast-time network), part of X22.
|
||||
- **Fix built on a branch, pending merge or rollout:** M26, M27, X21 (`miner-reliability` `aea5ac6d`, with the app half on `release-0.3.5`), F22 (rule v3, fast-time network), part of X22. Sweep (5 October 2026, evening): M26, M27, X21, F23, F24, G12, X18, M30, M31, F25 and M20 are now "Fixed (rolled out 5 October 2026, 0.3.5)" with their live measurement lines; F21 and F22 are shipped in every node since 0.3.4 and wait only for the switch N3 (decision owner the project lead).
|
||||
- **Open with new evidence and a fix row (fud-fixes section 2.5):** M20 (the stub is still in the pruning-proof path on `devnet-v4`; it goes live the moment the devnet passes its pruning depth), M21 (the k table from the fork's own function), M28, X20, P15, X29 (half fixed: file modes), X14 (hashing concentration measured), M25 (confirmed live in the sweep: a mismatched day length is rejected as `BlockInvalid` with no reason named, 0 of 4 against 7 of 7), M14 and F14 (no amplification in the chain model under rule v2 or Kaspa's rule, nor on the finality-fixes node under fast time, s5 ratio 0.864; the finality-with-DAA run still owed).
|
||||
- **Open, needs hardware, a person or the devnet:** M1, M11 (a rig), M16 (the 5090), M22, X19 (the node line; `faketime`), X23 to X28 (the relay owner and PC 1; the token is rotated, the run-task binding is not), E13, E14, E16, E17 (the draw lines), F16, F20 (the devnet test), C4 (module off), P3, P14, P16, P17, P21, P22, X13, X15, X17, G10, L1 to L5, L8, D5, D6.
|
||||
- **Nothing became worse.** Two things are closer than they look: M20 becomes a live failure for every fresh node once the devnet's pruning point leaves genesis, which at the devnet's 1.05 DAA/s (DAA 33,000 at 17:37 UTC on 4 October) is between DAA 108,000 (`PRUNING_DURATION`, about 14:00 UTC on 5 October) and DAA 151,200 (the first finality point a full pruning depth below the tip, about 01:00 UTC on 6 October), approximate; X23's operational half (a run task on the PCs needs only the relay token) is unchanged after the rotation.
|
||||
|
|
|
|||
248
docs/plans/release-0.3.9.md
Normal file
248
docs/plans/release-0.3.9.md
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
# Igneum Miner 0.3.9: the fee switch to the devnet, 5 October 2026
|
||||
|
||||
Release engineer, from 15:34 UTC, the project lead: "give it everything we have, ready for 7pm" (18:00 UTC). Worktree
|
||||
`/Users/joshm/Projects/igneum-wt-ship039`, branch `release-0.3.9` from master 23d11d5 (the 0.3.8 merge; nothing else
|
||||
on master). Every Mac build through `/Users/joshm/Projects/igneum/tools/lock/with-lock.sh build` at `nice -n 19` with
|
||||
`-j 4`. Times are UTC. `release-0.3.8.md` is the template for the cut and the proving rollout; `release-0.3.6.md`
|
||||
section 5 step 4 for the override publish.
|
||||
|
||||
## 1. What 0.3.9 carries
|
||||
|
||||
| Change | Where | State |
|
||||
|---|---|---|
|
||||
| The prover core mirrors both fee tables and the `fees_v1_activation_daa` switch (the shard input carries the schedule and the block's DAA score; one pinned guest meters before and after the switch as the node does) | `proving/igneum-prove/core/src/config.rs`, `pgas.rs`, `shard.rs`, `executor.rs`, the export and the host, branch `fee-switch` | (pending) |
|
||||
| A new pinned guest: new shard program id, new aggregator id | `proving/igneum-prove/elf/` | (pending) |
|
||||
| The runbook for the switch | `docs/plans/fee-switch-devnet.md` | (pending) |
|
||||
|
||||
Scope change at 16:16Z (coordinator, from the txgen agent's result: shards with content fail the native-execution veto
|
||||
unless `igneum_exportSegments` names the block index and body position per entry): 0.3.9 also carries the NODE change
|
||||
`txgen-export` a24ab01a (one file, `igneum/exec/src/rpc.rs`, 124 insertions, plus its unit test), from the separate
|
||||
clone `vendor/igneum-node-txgen`, fast-forwarded onto the fork's `release-0.3.6` in `vendor/igneum-node-036`
|
||||
(2b6d23ef -> a24ab01a, 16:23:58Z). The exporter side (`export blocks_of`, fixtures block-72803 and block-72854 with
|
||||
node-plan sidecars) is on master (txgen merge 49796b0, taken into this branch). The RPC change touches no consensus
|
||||
parameter, so the digest must stay f10a4eab... (checked with the 20-s scratch run below). The node is therefore
|
||||
rebuilt: Mac arm64 here under the lock, Windows exes by the Mac cross-build (never a PC-built Windows node),
|
||||
Linux by a PC 1 build job (for HiveOS; the seed keeps the glibc-2.36 cross-build of 2b6d23ef, the change is RPC only
|
||||
and the hand nodes and the seed export nothing), and the node's `kaspa-rpc-service` and `igneum-exec` suites on PC 2.
|
||||
|
||||
## 2. The branch
|
||||
|
||||
| Commit | What |
|
||||
|---|---|
|
||||
| 9f1c555 | `origin/master` merged in (local master was 7 commits behind: the fud-b wording merge, the site rebuild, rotation-3 executed; no app or packaging file, two lines in `tools/ship-app.mjs`); the ship tool's preflight refuses a tree behind origin/master |
|
||||
| 49796b0 | `origin/master` merged again at 16:23Z (txgen 49796b0, testnet-infra 83a0bcf, public-release 1eb94b0: the exporter's `blocks_of`, the node-plan fixtures, `build-job.mjs --node-tests`, `ship-app.mjs --public`, dl/public, the HiveOS package); no conflict, 0.3.9 still in all 6 |
|
||||
| f7a41a2 | Merge `fee-switch` (15bb6cd, landed 16:24Z). Conflicts: `proving/igneum-prove/export/src/main.rs` (only the two `use` lines: master's `ensure` kept, fee-switch's `FeeParams`, `FeeSchedule` taken, `SHARD_PROVING_GAS_BUDGET` gone), `docs/bench-log.md` (both entries), `docs/testnet/README.md` (both sentences), `site/index.html` and `site/journey.json` (master's, then `node site/build.mjs`: 13 pages, `link-check` 518 links, 0 broken) |
|
||||
| 2b6bf7f | `Igneum Miner 0.3.9: ...`, the six version files (`node tools/ship-app.mjs --check`: 0.3.9 in all 6) |
|
||||
| dfc0cfc | `packaging/windows/node-source.pin` = a24ab01a (written by `push-inputs.sh`, section 5b) |
|
||||
| 00c7b4f | `infra/devnet/restart-hand-nodes.sh` and `restart-seed.sh` take the fork tip's commit and the seed's cross-built binary by variable (section 5c); pushed 16:42Z, `windows.yml` dispatched again on it: run 37342911129 |
|
||||
| 1269db8 | `origin/master` 318a2de merged (coordinator 16:32Z: housekeeping, the signed jobs envelope `igneum-jobs.signed.json` on both sides, `test-publish-jobs.sh`, `ship-app.mjs` carries the envelope in FOLDER_FILES and `--public`); it rewrites four app sources (`jobs.rs`, `jobrun.rs`, `jobbuild.rs`, `bin/ota-sign.rs`), so the chained build that had started at 16:31Z was killed at its app step and restarted from this tree, and the app tests rerun. The fork's own `housekeeping` branch is NOT in 0.3.9 (0.3.10) |
|
||||
|
||||
## 3. Tests and checks, with the command
|
||||
|
||||
| Tip | Command | Result |
|
||||
|---|---|---|
|
||||
| 23d11d5 (before the merge) | `tools/ci/identity-check.sh` | 0 hits over 206 files, 15:36Z |
|
||||
| 23d11d5 | `tools/ci/copied-sources-check.sh` | every copying build script re-stamps its sources |
|
||||
| 23d11d5 | `tools/ci/pinned-guests-check.sh` | elf/ matches its manifest, no script builds a guest outside pin-guests.sh |
|
||||
| 23d11d5 | `node tools/ci/check-workflow-shell.mjs` | 12 run blocks in 2 workflows, 25 .ps1, 0 findings |
|
||||
| 23d11d5 | `node --test relay/test/parse.test.mjs relay/test/auth.test.mjs relay/test/wake.test.mjs` | 15 pass |
|
||||
| 23d11d5 | `node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs` | 10 pass |
|
||||
| 0.3.9 bump | `node tools/ship-app.mjs --check` | 0.3.9 in all 6 (bumped with the tool's own six patterns, 15:38Z) |
|
||||
| 2b6bf7f | `tools/ci/identity-check.sh`, `copied-sources-check.sh`, `pinned-guests-check.sh` (the NEW `elf/` matches its manifest), `check-workflow-shell.mjs`, the relay tests (15), the UI tests (10) | all as at 23d11d5, 16:28Z |
|
||||
| fork a24ab01a + app 2b6bf7f | PC 2 build job `build-20261005-162506` (`node tools/build-job.mjs run --target 1ccfe586 --targets linux --node-tests "kaspa-rpc-service igneum-exec" --app-tests "igneum-app"`) | started 16:25Z, done 16:27:55Z (139 s): Linux node built in 78 s (cache warm), `kaspa-rpc-service` and `igneum-exec` suites exit 0 in 36 s, `igneum-app` exit 0 in 5 s; its Linux igneumd 374fccad... (48,736,744, glibc 2.39: not for the seed) placed under `infra/cross/out/` of this worktree |
|
||||
| 1269db8 | `cargo test --release -p igneum-app` (under the build lock, this Mac; the final app tree, with the housekeeping merge) | ok: 76 (lib) + 27 (ota-sign) + 8 (prove-verify), 0 failed, 16:33 to 16:41Z |
|
||||
| 1269db8 | `cargo test --release` in `proving/igneum-prove` (the whole workspace, under the build lock, this Mac: 11 min wall, almost all of it compiling beside the chained build) | ok: core 8, export 3 + fixtures 2, host 9 (1 ignored), aggregator, pin and program 0, 0 failed, 16:32 to 16:43Z |
|
||||
| 1269db8 | `gh workflow run windows.yml --ref release-0.3.9` -> run 37341810898 | green 16:39:45Z (parse checks; engine, window host, payload, installer, smoke run; the inputs step against the a24ab01a inputs of 5b) |
|
||||
| 9f1c555 + bump | `cargo test --release -p igneum-app` (under the build lock, this Mac; the app crate is not touched by `fee-switch`, so this run stands for the final tree) | ok: 75 (lib) + 26 (ota-sign) + 8 (prove-verify), 0 failed, 15:49 to 15:54Z (target dir cloned by APFS from the 0.3.8 worktree) |
|
||||
|
||||
## 4. The state of the network before the cut (15:35Z)
|
||||
|
||||
| Node | Binary | Override file | Digest |
|
||||
|---|---|---|---|
|
||||
| Mac app node d937c69d, PC 1 ae432dc7, PC 2 1ccfe586 | app 0.3.8, node 2b6d23ef | the manifest's `{33000, 84100}` | (the live one) |
|
||||
| The observer and node 1 on this Mac (hand nodes) | `vendor/igneum-node/target-release/release/igneumd`, the 0.3.5 build 20139145: NO `fees_v1_activation_daa` in the binary (0 string hits; 2b6d23ef has 3) | `/tmp/igneum-devnet/override-v3.json` `{33000, 84100}` | f10a4eab... |
|
||||
| The seed 188.245.5.161 | `/opt/igneum/v4/bin/igneumd` c98a23da..., the 0.3.5 cross-build, glibc 2.34; Debian 12, glibc 2.36 | `/etc/igneum/override-v3.json` `{33000, 84100}` | f10a4eab... |
|
||||
| PC 37ba0461 | 0.3.7, silent since 13:52Z | | |
|
||||
| Sam's Mac 3a9bf309 | 0.3.5, node 20139145, silent since 09:43Z; reads the OLD downloads folder | | |
|
||||
|
||||
So the three hand-run nodes cannot read a `fees_v1_activation_daa` line at all: they must move to the 2b6d23ef node
|
||||
before the switch. The 0.3.6 digest check (release-0.3.6.md 8g) showed 2b6d23ef with the same override file gives
|
||||
the same digest f10a4eab..., so that swap changes nothing on the network. The Mac arm64 2b6d23ef binary is the DMG's
|
||||
(`vendor/igneum-node-036/target-integration/release/igneumd`, 64138a17...). The PC 1 Linux build of 2b6d23ef
|
||||
(c24fd2c5..., in the 0.3.6 worktree) needs glibc 2.38 and the seed refuses it (`GLIBC_2.38 not found`), so the seed's
|
||||
binary is the Mac zig cross-build (`infra/cross/build-linux.sh`, glibc 2.36 target), started 15:41Z under the lock
|
||||
(`NODE_SRC=vendor/igneum-node-036`, target dir `vendor/igneum-node/target-release-linux`, the 0.3.5 cross-build's cache).
|
||||
|
||||
The hand nodes moved first, 15:44Z, with the UNCHANGED override file (the scratchpad script extended to take the
|
||||
binary and an optional H: `restart-hand-nodes-039.sh 84100`): observer restarted 15:44:04Z, node 1 15:44:16Z, both
|
||||
`igneumd/2.1.0-2b6d23ef`, both `Fees on igneum-devnet: ... calibrated v1 from DAA score never`, both digest
|
||||
f10a4eab... (unchanged), peers reconnected within 20 s and blocks accepted at DAA 112,496. The field itself was
|
||||
checked on the same binary with a scratch node and `fees_v1_activation_daa: 200000` (15:42Z, 25 s, ports 60995/60996):
|
||||
`Calibrated v1 fees from the override file: chain blocks metered with the adopted table, budgets and floors from DAA
|
||||
score 200000`, digest d5b5028b... (the digest moves with H, so the H of the runbook has its own).
|
||||
|
||||
The cross build: try 1 (15:41 to 15:54Z) compiled every crate and was killed at the final link of `igneumd` by a
|
||||
SIGTERM from outside this session (not a compile error; the sender is unknown); try 2 (15:55 to 15:59:11Z, 270 s,
|
||||
the link only) gave `igneumd` c28756d08a61194d8ef945885ce22d8c48d1045843bbb01a41f0e2358b226e3e (47,451,112 bytes,
|
||||
`GLIBC_2.34` at most, 2b6d23ef in its strings, the fee field 3 times) and `igneum-miner` a122885a... (9,631,272).
|
||||
The seed moved at 16:00:21Z with the UNCHANGED override file (the scratchpad `restart-seed-039.sh 84100`, which
|
||||
copies the file by scp and swaps the binary as the 0.3.5 hot-swap did; its first run aborted at `igneumd.new
|
||||
--version` because the node's `--version` exits non-zero under `set -e`, nothing changed, `|| true` added, run
|
||||
again): `/opt/igneum/v4/bin/igneumd` c28756d0..., previous kept as `igneumd.prev-035`, unit active 16:00:22Z,
|
||||
`igneumd/2.1.0-2b6d23ef`, `calibrated v1 from DAA score never`, digest f10a4eab... (unchanged), first peer back at
|
||||
16:00:29Z. So from 16:00Z every node on the devnet runs 2b6d23ef and can read the switch.
|
||||
|
||||
Downloads folders: the rotation was executed at 15:25Z (`rotation-phase-2.md` section 8): `dl-token.next` became
|
||||
`dl-token`, the OLD folder was stripped to the 0.3.8 manifest, its DMG and its installer for Sam's 0.3.5 Mac. So
|
||||
`--dl-both` (which needs `dl-token.next`) no longer applies; the ship publishes the NEW folder (every 0.3.6+ app) and
|
||||
the OLD folder gets the same 0.3.9 manifest, DMG and installer by hand (`publish-manifest.sh --dest --base-url`).
|
||||
|
||||
## 5. The Mac binaries and the DMG
|
||||
|
||||
The Mac node of fork a24ab01a: `CARGO_TARGET_DIR=vendor/igneum-node/target-036 cargo build --release -j 4 -p kaspad -p igneum-miner --features kaspad/igneum-pow`
|
||||
from `vendor/igneum-node-036`, under the lock, 16:24:19 to 16:28:53Z (incremental on the 0.3.6 target): `igneumd`
|
||||
03b8959054d89448023e5b4cec21c8fc2425e53eac900e1813631769ec24386e (40,968,064 bytes, `a24ab01a` in its strings),
|
||||
`igneum-miner` ef438be2... (8,514,864, byte-identical to 0.3.6's: the miner did not change). Copied into
|
||||
`vendor/igneum-node-036/target-integration/release/` (the 2b6d23ef igneumd kept beside it as `igneumd.2b6d23ef`).
|
||||
|
||||
### 5a. The hand nodes on a24ab01a
|
||||
|
||||
The observer (16:30:25Z) and node 1 (16:30:37Z) restarted on the a24ab01a Mac binary with today's override (the
|
||||
scratchpad script, `BIN=` the new build): `igneumd/2.1.0-a24ab01a`, digest f10a4eab... on both, peers back within 20 s,
|
||||
new pids 16875 and 17017 (node 1 under caffeinate 17019). The digest of a24ab01a was read first with a scratch node
|
||||
(ports 60995/60996, 22 s each): today's override `{33000, 84100}` -> f10a4eab... (16:29:19Z); the switch override
|
||||
`{33000, 84100, fees_v1_activation_daa 210000}` -> `Calibrated v1 fees from the override file: ... from DAA score
|
||||
210000`, digest ab8847da538dead1dc10e046dfaadab3c1c35928e3748810c4e050d4a886087a (16:29:45Z), equal to the runbook's
|
||||
reading on 2b6d23ef: the RPC change moves no parameter.
|
||||
|
||||
### 5b. The Windows payload inputs (16:31 to 16:32Z)
|
||||
|
||||
The Windows exes by the Mac cross-build (`CARGO_TARGET_DIR=vendor/igneum-node/target-036-win proto-cuda/windows-node/cross-build.sh vendor/igneum-node-036 4`,
|
||||
under the lock, 16:24:23 to 16:29:04Z, 4 min 39 s incremental on the 0.3.7 target): `igneumd.exe`
|
||||
0e844ff7b5e82ed987f97c1cd7197a16ca609de7fa4688f0a2ca6e420007bb41 (50,779,136 bytes, `a24ab01a` in its strings),
|
||||
`igneum-miner.exe` eb77bf93... (10,778,624, byte-identical to 0.3.7's). Installed into
|
||||
`vendor/igneum-node-036/target-integration/x86_64-pc-windows-gnu/release/` (the 0.3.7 pair kept in `0.3.7-exes/`), then
|
||||
`IGNEUM_WIN_RELEASE=<that> IGNEUM_NODE_SRC=vendor/igneum-node-036 packaging/windows/push-inputs.sh` from the worktree:
|
||||
signed, deployed, `payload-inputs.json` HTTP 200 at 16:32:09Z, `node-source.pin` a24ab01a2e10cecf575bcea372310b871081ec64.
|
||||
|
||||
PC 1 build job `build-20261005-162451` (`--targets linux`, 16:24:51Z, done 16:29:15Z, 219 s): every stage ok, Linux
|
||||
igneumd 445b25fa... (48,736,744, glibc 2.39, for HiveOS, not the seed), placed under `infra/cross/out/`.
|
||||
`cargo check --release` of the merged prover workspace (core, export, host): ok, 16:26 to 16:30Z.
|
||||
|
||||
### 5c. The seed on a24ab01a
|
||||
|
||||
The Linux node of a24ab01a for the seed: `infra/cross/build-linux.sh` (zig, glibc 2.36 target) from
|
||||
`vendor/igneum-node-036` under the lock, 16:30:10 to 16:41:04Z (654 s): `igneumd`
|
||||
7e26e374586ad8ba539e371c6cbbd74f0f77aee1e2e97cd25f0182fcbda458a5 (47,453,736 bytes, `GLIBC_2.34` at most, `a24ab01a` in
|
||||
its strings), kept in the main checkout's `infra/cross/out-039/`. Staged on the seed as `/root/v4/out/igneumd.039x`
|
||||
(sha equal, `--version` runs on Debian 12), then the hot-swap with today's override (scratchpad `restart-seed-039.sh 84100`):
|
||||
restart 16:41:37Z, unit active 16:41:38Z (MainPID 117943), `igneumd/2.1.0-a24ab01a`, `calibrated v1 from DAA score
|
||||
never`, digest f10a4eab... (unchanged), a peer back within 10 s; the 2b6d23ef binary kept as `igneumd.prev-035`
|
||||
(the name the 16:00Z swap gave the 0.3.5 one is now `igneumd.prev-035` too: the second swap overwrote that copy with
|
||||
the 2b6d23ef binary, so the 0.3.5 binary survives only as `/root/v4/out/igneumd.035`).
|
||||
|
||||
The repository's `infra/devnet/restart-hand-nodes.sh` and `restart-seed.sh` (from `fee-switch`) are adjusted on this
|
||||
branch for the new tip: the hand-node script checks for `IGNEUMD_COMMIT` (default a24ab01a) instead of 2b6d23ef; the
|
||||
seed script takes `IGNEUMD_LINUX` (default `infra/cross/out-039/igneumd`) and `IGNEUMD_LINUX_SHA256` (default
|
||||
7e26e374...) instead of the PC 1 build c24fd2c5..., which the seed's glibc 2.36 refuses (`GLIBC_2.38 not found`,
|
||||
tried 15:36Z); both still take the whole override object and print the pids and the digest lines. They are the
|
||||
scripts of section 10 steps (c) and (d).
|
||||
|
||||
### 5d. The app, the prover tools and the fixtures (the chained script, 16:33 to 16:43Z)
|
||||
|
||||
`build-chain-039.sh` (the 0.3.8 chain with the paths changed), under the lock: `cargo build --release` of the app
|
||||
(16:33 to 16:42Z, the housekeeping merge rebuilt the engine and the signer), then
|
||||
`cargo build --release -p igneum-prove-export -p igneum-prove-host` in `proving/igneum-prove` (16:42 to 16:43Z, the
|
||||
host embeds the NEW `elf/`; no Succinct toolchain). `igneum-prove-host --mode id` on this tree:
|
||||
|
||||
```
|
||||
pinned guests: shard program id 0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a (2832504 bytes, sha256 0x150f4c05a2951fc5) aggregator id 0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896
|
||||
```
|
||||
|
||||
Both equal `elf/manifest.json` (pinned 2026-10-05T16:20:38Z, SP1 6.8.1, circuit v6.1.0). `--mode native` (the package
|
||||
gate's native half) on every fixture in `proving/fixtures/`: the nine block fixtures (338, 341, 344, 56 x2, 58927,
|
||||
72803, 72854, 78) and the three fee-switch fixtures (`fees-switch-prototype`, `fees-v1-shards2`, `fees-v1-shards3`)
|
||||
all ok. The chain's loop had stopped at `block-72803-skipped-copies.json.node-plan.json`, the node-plan SIDECAR that
|
||||
the `block-*.json` glob now matches (`missing field format`: not a fixture), so the last two block fixtures and the
|
||||
three fee-switch ones were run by hand afterwards. The chain's DMG step therefore ran separately (below).
|
||||
|
||||
### 5e. The DMG (16:44:09 to 16:45:08Z, under the lock)
|
||||
|
||||
`NODE=<fork>/target-integration/release/igneumd MINER=.../igneum-miner packaging/mac/build-dmg.sh` from the worktree:
|
||||
node igneumd 2.1.0 (a24ab01a, 03b89590...), engine 0.3.9, the prover host 6ede0b9e... (58,544,672 bytes before the
|
||||
strip, 45,314,144 in the bundle) and export 347da361..., manifest folder fingerprint ed9c4d2e (`dl-token`, the
|
||||
rotated one), `hdiutil verify` VALID.
|
||||
|
||||
| Artefact | sha256 | Size |
|
||||
|---|---|---|
|
||||
| `packaging/mac/dist/Igneum-Miner-0.3.9.dmg` (build 202610051644) | 5e57c5735dc99e44475c43fba8ecffadae9dbd3a150c32ef4858587a98256de3 | 41,333,873 |
|
||||
|
||||
86,454 bytes larger than 0.3.8's (41,247,419): the new ELFs and the host's fee mirror.
|
||||
|
||||
## 6. The prover package for PC 2
|
||||
|
||||
`SKIP_GATE=1 proving/windows-wsl2/make-package.sh <scratch>/igneum-prove-wsl2-039.zip` from the worktree at 1269db8 (16:34Z):
|
||||
b5e5fa6ed4d62fee43b8fc737ce41c3665b5f4573cf9426e34012874031a282a, 1,530,932 bytes; `package/proving/igneum-prove/elf/`
|
||||
carries the NEW ELFs (program 2,832,504 bytes, aggregator 319,744), the two keys and `manifest.json` (shard
|
||||
`0x2b1a81cb...`, aggregator `0x474678f3...`). The gate skipped on instruction as in 0.3.8; its native half runs in the
|
||||
chained build on the DMG's host (section 5).
|
||||
|
||||
The fetch job `fetch-prove-039` (`--dir prove --extract --extract-dir igneum-prove-wsl2-039 --fresh`) was added at 16:34:54Z
|
||||
through the MAIN checkout's `publish-jobs.sh` (coordinator's rule, 16:31Z: that script writes the signed envelope
|
||||
`igneum-jobs.signed.json`; a publish from an older script leaves it stale, which is exactly what `prove-off-pc2-039` had done at
|
||||
16:02Z through this worktree's copy: live envelope 15:53:42Z against a 16:02Z pair). The add stopped at the signature:
|
||||
the main checkout's `app/igneum-app/target/release/igneum-ota-sign` was built 07:38Z, before the `sign-jobs` subcommand
|
||||
existed (the script printed the signer's usage). The signer built from this tree (the chained build's app step, which
|
||||
carries `bin/ota-sign.rs` with `sign-jobs`) is copied over it, then `publish-jobs.sh sign --deploy` publishes the file
|
||||
with the job and a fresh envelope: the signer from this tree (595,024 bytes, built 16:41Z, `sign-jobs` present) copied
|
||||
over the main checkout's (the 07:38Z one kept as `igneum-ota-sign.pre-envelope`), `publish-jobs.sh sign --deploy`
|
||||
16:42:13Z: `live jobs files verified at .../igneum-jobs.signed.json and the plain pair (try 1 of 12)`, apps woken (stamp
|
||||
2026-10-05T16:42:14Z.9e4b22bb). Lesson for the class: a script that needs a newer signer than the checkout has built
|
||||
fails with the signer's usage text and no exit code of its own; the next `publish-jobs.sh` should check for `sign-jobs`
|
||||
in the signer's usage before it writes anything (a 0.3.10 item).
|
||||
|
||||
## 7. The proving rollout order (proving/README.md), with times
|
||||
|
||||
| Step | What | When |
|
||||
|---|---|---|
|
||||
| (1) provers off | Mac: already off (the app's `/api/state`: `enabled false, status off`, 15:46Z). PC 2: run job `prove-off-pc2-039` (the 0.3.8 PowerShell script: `POST <app.url>/api/prove {"on":false}`, the app state, the node's `igneum_getProvingStatus`), published 16:02:06Z (apps woken, stamp e933f990), started early so the drain overlaps the wait for the `fee-switch` branch | ran 16:02:27 to 16:02:38Z: `api/prove off: {"ok":true}`; PC 2's node pool `{entries 18, failed 0, pending 0, verified 178}`, paidShards 388, tip DAA 113,603 |
|
||||
| (2) empty pool | A 30-s watch on the Mac app node's `igneum_getProvingStatus` that prints every change and every error line: 16:02:36Z `entries 18, pending 0, verified 178`, tip DAA 113,601; then one entry fewer every 30 to 60 s (16:03:07Z 16, 16:07:17Z 10, 16:11:48Z 5), no error line, no new record | OBSERVED empty 16:15:50Z: `entries 0, pending 0, failed 0, verified 178` (13 min 23 s after PC 2's prover went off; the 600-DAA record window at 0.965 blocks/s is 10.4 min) |
|
||||
| (3) new host on every node | (pending) | |
|
||||
| (4) `--mode id` | (pending) | |
|
||||
| (5) provers on | (pending) | |
|
||||
|
||||
## 8. The ship
|
||||
|
||||
(pending)
|
||||
|
||||
## 9. The machines after the publish
|
||||
|
||||
(pending)
|
||||
|
||||
## 10. The fee switch
|
||||
|
||||
The runbook (`docs/plans/fee-switch-devnet.md` on the `fee-switch` branch, read 15:44Z while still uncommitted): H = 210,000
|
||||
(DAA 112,227 at 15:40:13Z, 0.965 blocks/s, so about 19:50Z on 6 October; the 24-hour rule holds for a publish before
|
||||
about 19:50Z on 5 October), expected digest `ab8847da538dead1dc10e046dfaadab3c1c35928e3748810c4e050d4a886087a` with
|
||||
`{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}`. Order:
|
||||
(a) `publish-manifest.sh --version 0.3.9 --override '<that object>' --activation-height 210000 --deadline-note "fees v1" --deploy`
|
||||
(the NEW folder; the OLD folder by hand with `--dest`/`--base-url`, one deploy, `--verify-only`), (b) `update-now` to
|
||||
every app, wait for `Calibrated v1 fees from the override file: ... 210000` on every app node, (c) the hand nodes,
|
||||
(d) the seed, then the digest sweep. The app side is confirmed in code: `ota.rs write_override` writes the manifest's
|
||||
object verbatim whenever it differs from `override.json` (same version or not) and the engine restarts the node at a
|
||||
safe moment.
|
||||
|
||||
(pending: the publish itself)
|
||||
|
||||
## 10a. The fee-switch branch, as polled
|
||||
|
||||
| Time | State of `/Users/joshm/Projects/igneum-wt-feeswitch` (branch `fee-switch` at 23d11d5) |
|
||||
|---|---|
|
||||
| 15:34Z | 2 modified files (core Cargo.toml, config.rs), no runbook |
|
||||
| 15:38Z | 12 files (core, export, host, gen.mjs, net.sh) |
|
||||
| 15:43Z | 18 files; `docs/plans/fee-switch-devnet.md` present with `SHARD_ID_SECTION` unfilled; `elf/` still the 0.3.8 pin 0x0dfade07 (pinned 12:07:56Z) |
|
||||
| 15:47 to 16:11Z | 23 then 24 files; the agent's simnet driver cut round 1 (15:47 to 15:53Z), round 2 failed (`only 0 of 11 receipts after 90000 ms`, 16:09Z), resumed 16:11:15Z (`provingGasLimit 0x1d4c0` at tip DAA 874, the v1 side); no commit, no re-pin, the placeholder still in the runbook |
|
||||
|
||||
## 11. Open after the cut
|
||||
|
||||
(pending)
|
||||
|
|
@ -11,7 +11,7 @@ Designed. Every transaction pays a base fee in both gas dimensions:
|
|||
| Dimension | What it meters | Who sets it |
|
||||
|---|---|---|
|
||||
| Execution gas | EVM execution, Ethereum's rule | Ethereum's EIP-1559-style base fee over the ordered sequence |
|
||||
| Proving-cost gas | Proving cycles the transaction will cost the provers | A second base fee adjusted per block from the unproven backlog, smoothed over the difficulty window (section 2.3) so cards do not flip between hashing and proving every block |
|
||||
| Proving-cost gas | Proving cycles the transaction will cost the provers | A second base fee `f_p`, adjusted per chain block by the same EIP-1559 step as `f_e`: toward a target of `B_p / 2` of proving gas used, denominator 8, never below the floor of section 5.11 (one definition, 5 October 2026, ledger P14; `next_base_fee` in `igneum/exec/src/executor.rs`, applied per chain block in `service.rs`). The unproven backlog does not move `f_p`; it halves `B_p` (design 4.3, the backlog rule), which raises `f_p` through the step. No smoothing over the difficulty window is implemented or specified: the two-dimension step is per chain block |
|
||||
|
||||
The base fee in both dimensions is **burned in full**. A miner cannot stuff blocks with its own transactions for free; wash gas loses its whole base fee (ledger E3). The proving-cost budget per block is a consensus constant set from measured prover throughput (phase 2 gate: one shard on a 12 GB card in about 20 s, Target, unmeasured, ledger P1), so a transaction that is cheap to run and brutal to prove cannot stall the provers for everyone. How the node folds the proving-cost dimension into the quoted gas price so `eth_estimateGas` keeps working is fixed in section 7.1 (ledger P5, closed 3 October 2026).
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -175,10 +176,12 @@ p{margin:0;color:var(--ink-2);max-width:52ch}
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -91,6 +91,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -182,7 +183,7 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin
|
|||
<div class="label"><div class="k">designed</div><div class="v">6</div><p>A decision in the design document or the specification. No code, or a stub</p></div>
|
||||
<div class="label"><div class="k">implemented</div><div class="v">3</div><p>Code in the repository with test vectors that pass. Not measured as the claim</p></div>
|
||||
<div class="label"><div class="k">tested by the team</div><div class="v">21</div><p>Measured or exercised by the project on a named machine, with the command in the log</p></div>
|
||||
<div class="label"><div class="k">reproduced externally</div><div class="v">0</div><p>None yet. The repository is private until January 2027</p></div>
|
||||
<div class="label"><div class="k">reproduced externally</div><div class="v">0</div><p>None yet. The repository is private until the public testnet</p></div>
|
||||
<div class="label"><div class="k">reviewed independently</div><div class="v">0</div><p>None yet. What review would cost and who pays is in the funding plan</p></div>
|
||||
</div>
|
||||
<div class="chips" role="group" aria-label="Filter by status"><button type="button" class="chip on" aria-pressed="true" data-filter=""><b>30</b> all</button><button type="button" class="chip" aria-pressed="false" data-filter="designed"><b>6</b> designed</button><button type="button" class="chip" aria-pressed="false" data-filter="implemented"><b>3</b> implemented</button><button type="button" class="chip" aria-pressed="false" data-filter="tested by the team"><b>21</b> tested by the team</button><button type="button" class="chip" aria-pressed="false" data-filter="reproduced externally"><b>0</b> reproduced externally</button><button type="button" class="chip" aria-pressed="false" data-filter="reviewed independently"><b>0</b> reviewed independently</button></div>
|
||||
|
|
@ -226,7 +227,7 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin
|
|||
<div class="tbl small"><table><thead><tr><th>From</th><th>To</th><th>What it takes</th></tr></thead><tbody>
|
||||
<tr><td>designed</td><td>implemented</td><td>Code in this repository with test vectors that pass</td></tr>
|
||||
<tr><td>implemented</td><td>tested by the team</td><td>A bench-log entry with the machine, the date, the command and the number</td></tr>
|
||||
<tr><td>tested by the team</td><td>reproduced externally</td><td>The repository public (January 2027), the command published, and a third party's run with the same result, linked from the row</td></tr>
|
||||
<tr><td>tested by the team</td><td>reproduced externally</td><td>The repository public (at the public testnet), the command published, and a third party's run with the same result, linked from the row</td></tr>
|
||||
<tr><td>reproduced externally</td><td>reviewed independently</td><td>A named reviewer's published finding on that version. Funding for review is <code>docs/plans/funding.md</code></td></tr>
|
||||
<tr><td>any</td><td>the row's status falls back</td><td>A new version of the code or rule the row names</td></tr>
|
||||
</tbody></table></div>
|
||||
|
|
@ -264,10 +265,12 @@ code{font-family:var(--f-mono);font-size:.92em;background:var(--obsidian);paddin
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -230,10 +231,12 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -52,13 +52,18 @@
|
|||
"log": [
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
"text": "Live devnet: real transactions, the first non-empty shard proven and paid, and the exporter's block structure fixed",
|
||||
"short": "Live devnet: real transactions, the first non-empty shard proven and…"
|
||||
"text": "The prover carries both fee tables and the height switch: one pinned guest on either side of DAA 210,000",
|
||||
"short": "The prover carries both fee tables and the height switch"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
"text": "The prover carries both fee tables and the height switch: one pinned guest on either side of DAA 210,000",
|
||||
"short": "The prover carries both fee tables and the height switch"
|
||||
"text": "FUD ledger sweep round 6",
|
||||
"short": "FUD ledger sweep round 6"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
"text": "Live devnet: real transactions, the first non-empty shard proven and paid, and the exporter's block structure fixed",
|
||||
"short": "Live devnet: real transactions, the first non-empty shard proven and…"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
|
|
@ -244,11 +249,6 @@
|
|||
"date": "2026-10-03",
|
||||
"text": "RTX 5090 through NVIDIA OpenCL",
|
||||
"short": "RTX 5090 through NVIDIA OpenCL"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Igneum-node devnet v0: 3-node igneum-devnet at 1 BPS with the 80/20 coinbase and vote_key_hash",
|
||||
"short": "Devnet v0: three nodes at one block per second"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -678,12 +679,12 @@ body.all .pager{display:none}
|
|||
<section id="miners-ask">
|
||||
<h2>Questions miners ask</h2>
|
||||
<h3>Kaspa was GPU-mined too, and IceRiver shipped a chip within two years.</h3>
|
||||
<p>Kaspa never promised chip resistance, and its hash was one fixed function, simple enough to put on silicon. Igneum's program is different every hour, its dataset grows past any fixed memory, and its program space widens every era, with no human involved. In January 2027 the benchmark tool is public, so you run it on your own card and post the number to a leaderboard by card model. A standing bounty pays anyone who can show a chip design that beats a GPU by more than 2x. And if a chip ever appears, miners are the ones who signal the response.</p>
|
||||
<p>Kaspa never promised chip resistance, and its hash was one fixed function, simple enough to put on silicon. Igneum's program is different every hour, its dataset grows past any fixed memory, and its program space widens every era, with no human involved. The benchmark tool ships in January 2027, and its source is public with the repository at the public testnet, so you run it on your own card and post the number to a leaderboard by card model. A standing bounty pays anyone who can show a chip design that beats a GPU by more than 2x. And if a chip ever appears, miners are the ones who signal the response.</p>
|
||||
<h3>Finality weighted by mining history is new. New gets attacked.</h3>
|
||||
<p>Correct, and it is the first thing the external review will be paid to break. The specification is public; reviewers will be named and paid before gate 3, and a bounty is attached. Until then every finality claim here is a design claim backed by simulations and by the devnet, and the chain runs on plain GHOSTDAG without the rule, so it can be fixed without stopping the chain.</p>
|
||||
<h3>Who are you?</h3>
|
||||
<p>One founder, pseudonymous until the team page at public testnet, working with AI systems. The design, the hostile reviews, the code, the simulators and this document were produced that way, and the commit history says so. What that does and does not mean: the measurements are measurements, reproducible from the commands in the engineering log; the simulators are code anyone can run; the design claims stay design claims until people with names have tried to break them. Every criticism the project expects is kept in a ledger with its honest answer, and the entries that were right are marked conceded; the ledger is published with the node repository. No cryptographer is hired yet; the plan budgets one for phases 1 and 2, and external reviewers are named and paid before gate 3.</p>
|
||||
<p>The founders mine from genesis with disclosed addresses and the same software as everyone else, and hold no coins before block one. The team page is published at public testnet, with the mining addresses and the code history.</p>
|
||||
<p>One founder, pseudonymous, working with AI systems. The design, the hostile reviews, the code, the simulators and this document were produced that way, and the commit history says so. The software is shipped by Igneum Labs LTD, Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. The design remains the work of one founder working with AI systems, reviewed in public through the ledger. What that does and does not mean: the measurements are measurements, reproducible from the commands in the engineering log; the simulators are code anyone can run; the design claims stay design claims until people with names have tried to break them. Every criticism the project expects is kept in a ledger with its honest answer, and the entries that were right are marked conceded; the ledger is published with the repository at the public testnet. No cryptographer is hired yet; the plan budgets one for phases 1 and 2, and external reviewers are named and paid before gate 3.</p>
|
||||
<p>The founders mine from genesis with disclosed addresses and the same software as everyone else, and hold no coins before block one. The team is pseudonymous and there is no team page. The mining addresses and the code history are published with the repository at the public testnet.</p>
|
||||
<h3>Where is the miner?</h3>
|
||||
<p>On the devnet now. Igneum Ember runs on Windows, macOS and Linux, a HiveOS package exists, and the devnet's coins have no value. The public benchmark with a leaderboard by card model is January 2027. Pools and the public testnet are August 2027. All of it before any coin exists. Nothing is asked of a miner before they can run something. The <a href="#ember">Ember section</a> says what is shipped and what is still owed.</p>
|
||||
<h3>Will my card still pay in a bear market?</h3>
|
||||
|
|
@ -736,7 +737,7 @@ body.all .pager{display:none}
|
|||
<li><strong>Finality that never pauses.</strong> 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.</li>
|
||||
<li><strong>A finished protocol.</strong> 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.</li>
|
||||
</ul>
|
||||
<p>Everything in this document is subject to the gates on the roadmap. Nothing in it is an offer to sell anything. Found an error, or a criticism this document does not answer? Open an issue on the public specification repository: <a href="https://github.com/igneum-network/spec/issues" rel="noopener">github.com/igneum-network/spec/issues</a>. A mailbox follows; there is no other contact route yet.</p>
|
||||
<p>Everything in this document is subject to the gates on the roadmap. Nothing in it is an offer to sell anything. Found an error, or a criticism this document does not answer? Email <a href="mailto:hello@igneum.network">hello@igneum.network</a>, or open an issue on the public specification repository: <a href="https://github.com/igneum-network/spec/issues" rel="noopener">github.com/igneum-network/spec/issues</a>. Post reaches Igneum Labs LTD, Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre.</p>
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
|
|
@ -774,10 +775,12 @@ body.all .pager{display:none}
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -301,10 +302,12 @@ main{padding-bottom:var(--sec)}
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -263,10 +264,12 @@ pre{margin:0 0 16px;padding:16px 18px;background:var(--graphite);border-radius:v
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -421,7 +422,7 @@ pre b{color:var(--molten);font-weight:500}
|
|||
</div>
|
||||
<div class="fee reveal">
|
||||
<div class="card" style="display:flex;flex-direction:column;gap:16px">
|
||||
<p style="font-size:15px;color:var(--ink-2)">The <span data-product="name">Ember</span> software takes a visible, switchable 1% dev fee, the norm for GPU miners. One block template in 100 is requested with the dev payout address instead of yours. The choice is a template counter, never a random draw, so it is exactly 1 in 100 and anyone can audit it from the source or from the chain. A fee block still adds to your finality weight; the only thing that moves is who the execution layer pays for that one block.</p>
|
||||
<p style="font-size:15px;color:var(--ink-2)">The <span data-product="name">Ember</span> software takes a visible, switchable 1% dev fee, the norm for GPU miners. One block template in 100 is requested with the dev payout address instead of yours. The fee goes to Igneum Labs LTD, the company that ships the software. The choice is a template counter, never a random draw, so it is exactly 1 in 100 and anyone can audit it from the source or from the chain. A fee block still adds to your finality weight; the only thing that moves is who the execution layer pays for that one block.</p>
|
||||
<div class="tbl"><table style="min-width:0">
|
||||
<thead><tr><th>Where</th><th>Off with</th></tr></thead>
|
||||
<tbody>
|
||||
|
|
@ -516,10 +517,12 @@ pre b{color:var(--molten);font-weight:500}
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -220,10 +221,12 @@ th{font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;text-transform:
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -29,10 +29,12 @@
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -60,5 +60,6 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visi
|
|||
.foot-col a:hover{color:var(--ui-hot);text-decoration:none}
|
||||
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;margin-top:36px;padding-top:20px;border-top:1px solid var(--ui-line);font-size:13px;color:var(--ui-ash)}
|
||||
.foot-base span{text-wrap:balance}.foot-base .mono{font-family:var(--f-mono)}
|
||||
.foot-imprint{flex-basis:100%;text-wrap:pretty}.foot-base a{color:inherit;text-decoration:none}.foot-base a:hover{color:var(--ui-hot)}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
|
||||
</style>
|
||||
<!-- head:end -->
|
||||
|
|
@ -418,10 +419,12 @@ td.num{font-variant-numeric:tabular-nums;white-space:nowrap}
|
|||
<a href="/wallet">Add Igneum to MetaMask</a>
|
||||
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
|
||||
<a href="/miner#get">Miner downloads: public testnet</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Report a flaw</a>
|
||||
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
|
||||
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
|
||||
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
|
||||
<span class="mono">igneum.network</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
# which stays private because its remaining entries would themselves name what must stay out). Machine names, LAN
|
||||
# and overlay addresses, home paths, local time zones and the log-intake key pattern. Never a key, never a name.
|
||||
# Checked by tools/ci/identity-check.sh over the export list of igneum-public/tools/sync.sh after its generic scrub.
|
||||
# Not forbidden (decision of 5 October 2026): the registered address of Igneum Labs LTD, Innovation One, Dubai International
|
||||
# Financial Centre (DIFC). It is the one location that may appear in public text. The founder and the earlier entity stay in
|
||||
# the private list.
|
||||
DESKTOP-[A-Z0-9]{7}
|
||||
MacBook
|
||||
192\.168\.
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ HERE="$(cd "$(dirname "$0")" && pwd)"
|
|||
REPO="$(cd "$HERE/../.." && pwd)"
|
||||
PATTERNS="$HERE/forbidden-strings.txt"
|
||||
|
||||
# The export list of igneum-public/tools/sync.sh (keep in step with it).
|
||||
# The export list of igneum-public/tools/sync.sh (keep in step with it), plus the two files published with the repository
|
||||
# at the public testnet (decision of 5 October 2026: the criticism ledger and its fixes file). They are not in sync.sh,
|
||||
# because the spec mirror is public today and the repository is not until the public testnet.
|
||||
DIRS=(docs/spec docs/analysis sim igneum-pow igneum-census tools/harness proto-cuda/packs docs/benchmarks tools/finality-attacks tools/exec-attacks)
|
||||
FILES=(docs/provenance.md docs/bench-log.md docs/evidence.md proto-cuda/README.md proto-cuda/CHECKLIST.md proto-cuda/host.cu proto-cuda/build.sh
|
||||
FILES=(docs/provenance.md docs/bench-log.md docs/evidence.md docs/fud-ledger.md docs/fud-fixes.md proto-cuda/README.md proto-cuda/CHECKLIST.md proto-cuda/host.cu proto-cuda/build.sh
|
||||
proto-cuda/build.bat proto-cuda/.gitignore proto-cuda/emu/emu.sh proto-cuda/emu/shim.cpp proto-cuda/emu/cuda_runtime.h proto-metal/README.md
|
||||
proto-metal/MEMHARD.md proto-metal/TESTS.md proto-metal/main.swift proto-opencl/README.md proto-opencl/WAVEFRONT.md proto-opencl/host.c
|
||||
proto-opencl/build.sh proto-opencl/build.bat proto-opencl/.gitignore proto-opencl/emu/emu.sh proto-opencl/emu/emu_main.cpp proto-opencl/emu/emu_opencl.h)
|
||||
|
|
|
|||
12
tools/ci/install-hooks.sh
Executable file
12
tools/ci/install-hooks.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
# Installs the repository's git hooks into this checkout (pre-push: no conflict markers, the site builds).
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
cat > .git/hooks/pre-push <<'HOOK'
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
bash tools/ci/no-conflict-markers.sh
|
||||
(cd site && node build.mjs >/dev/null) || { echo "pre-push: the site build fails; fix it before pushing" >&2; exit 1; }
|
||||
HOOK
|
||||
chmod +x .git/hooks/pre-push; echo "pre-push hook installed"
|
||||
9
tools/ci/no-conflict-markers.sh
Executable file
9
tools/ci/no-conflict-markers.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
# No tracked file may carry a merge conflict marker. 5 October 2026: a marker in the generated site/journey.json broke
|
||||
# `node build.mjs` silently for two merges and a half-merged home page went live for a few minutes. Runs in CI and
|
||||
# before every push from the main checkout (git hook installed by tools/ci/install-hooks.sh).
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
hits="$(git ls-files -z | xargs -0 grep -lE '^(<<<<<<< |=======$|>>>>>>> )' 2>/dev/null | grep -vE '^tools/ci/no-conflict-markers\.sh$' || true)"
|
||||
if [ -n "$hits" ]; then echo "conflict markers in:"; echo "$hits" | sed 's/^/ /'; exit 1; fi
|
||||
echo "no conflict markers in tracked files"
|
||||
170
tools/finality-attacks/c4.mjs
Normal file
170
tools/finality-attacks/c4.mjs
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// Ledger C4 (5 October 2026, evening): does the finality overlay change GHOSTDAG's fork choice, measured. The same
|
||||
// split is run with the module ON (rule v3 from checkpoint DAA 0) and OFF (`finality.min_daa` never, so no
|
||||
// certificate can ever form and fork choice is bare GHOSTDAG on the same binary). Fast-time 3-node network on
|
||||
// ports 29800+, network igneum-devnet-980, data under /tmp/igneum-fin-c4; the live devnet is never touched.
|
||||
//
|
||||
// node tools/finality-attacks/c4.mjs on; node tools/finality-attacks/c4.mjs off # one mode per process
|
||||
// SPLIT=150 WARM=230 HEAL=200 node tools/finality-attacks/c4.mjs on
|
||||
//
|
||||
// Topology (as v3.mjs): n1 listens; n0 dials n1 through proxy P0, n2 dials n1 through proxy P2; cutting P0 isolates
|
||||
// n0 (side A) from n1 and n2 (side B).
|
||||
//
|
||||
// The scenario, "weight against work": before the cut side B holds 70% of the weight table (p0..p3 at share 0.175
|
||||
// on n1 and n2) and side A 30% (q0, q1 at 0.15 on n0), one block per second in all. At the cut every miner is
|
||||
// restarted with the rates swapped: side A mines at RA blocks/s (0.6) and side B at RB (0.4), so during the split
|
||||
// side A builds the heavier chain by blue work while side B, under the frozen weight table of rule v3, is the only
|
||||
// side that can certify a checkpoint (A holds 30% of the frozen table and cannot lock until the table expires,
|
||||
// 120 DAA of its own blocks later; B needs 50 DAA of its own blocks for its first new lock: RB / RA must exceed
|
||||
// 50 / 120 and RA must exceed RB, hence 0.6 / 0.4). At the heal GHOSTDAG alone follows A's heavier chain; the
|
||||
// overlay requires every candidate tip to pass through B's certified checkpoint. The measurement is which chain
|
||||
// the three nodes converge to, whether they converge at all, and what each node had to reorganise.
|
||||
|
||||
const ROOT = new URL('../../', import.meta.url).pathname;
|
||||
const NODE_ROOT = process.env.IGNEUM_NODE_ROOT || '/Users/joshm/Projects/igneum/';
|
||||
process.env.IGNEUM_FIN_BASE_PORT ||= '29800';
|
||||
process.env.IGNEUM_FIN_SUFFIX ||= '980';
|
||||
process.env.IGNEUM_FIN_TMP ||= '/tmp/igneum-fin-c4';
|
||||
process.env.IGNEUM_FAST_TIME ||= '1';
|
||||
// the live node line (fork 2b6d23ef, the 0.3.6 to 0.3.8 node) built on the Mac on 5 October 2026
|
||||
process.env.IGNEUMD ||= `${NODE_ROOT}vendor/igneum-node/target-036/release/igneumd`;
|
||||
process.env.IGNEUM_MINER ||= `${NODE_ROOT}vendor/igneum-node/target-036/release/igneum-miner`;
|
||||
const DELAY_MS = +(process.env.DELAY_MS || 100);
|
||||
const WARM = +(process.env.WARM || 230), SPLIT = +(process.env.SPLIT || 150), HEAL = +(process.env.HEAL || 200);
|
||||
const RA = +(process.env.RA || 0.6), RB = +(process.env.RB || 0.4);
|
||||
// ONE mode per process: lib/net.mjs reads IGNEUM_FIN_OVERRIDE_JSON when it is imported, so the override must be in
|
||||
// the environment before the import (the first draft set it inside network() and ran rule v2 twice; 5 October 2026).
|
||||
const MODE = process.argv.slice(2).filter(a => !a.startsWith('--'))[0] || 'on';
|
||||
if (MODE !== 'on' && MODE !== 'off') { console.error(`mode must be on or off, got ${MODE}`); process.exit(2); }
|
||||
process.env.IGNEUM_FIN_OVERRIDE_JSON = JSON.stringify(MODE === 'off' ? { finality: { min_daa: 9007199254740991 } } : { finality_v3_activation_daa: 0 });
|
||||
|
||||
const { Node, Miner, Proxy, stopAll, sleep, log, assertBinaries, TMP, IGNEUMD } = await import('./lib/net.mjs');
|
||||
const { mkdirSync, writeFileSync, appendFileSync } = await import('node:fs');
|
||||
mkdirSync(TMP, { recursive: true });
|
||||
const results = [];
|
||||
const out = (line) => { console.log(line); appendFileSync(`${TMP}/results-${MODE}.md`, line + '\n'); };
|
||||
|
||||
const lockedMap = (cp) => new Map((cp?.checkpoints || []).filter(c => c.state === 'locked').map(c => [c.index, c.hash]));
|
||||
const maxLocked = (cp) => Math.max(0, ...lockedMap(cp).keys());
|
||||
async function checkpoints(node, last = 800) { return node.rpc.call('getFinalityCheckpoints', { last }).catch(() => null); }
|
||||
async function peers(node) { const r = await node.rpc.call('getConnectedPeerInfo', {}).catch(() => null); return (r?.peerInfo || r?.infos || []).length; }
|
||||
async function dag(node) { return node.rpc.call('getBlockDagInfo', {}).catch(() => null); }
|
||||
async function blueScore(node, hash) { const r = await node.rpc.call('getBlock', { hash, includeTransactions: false }).catch(() => null); return Number(r?.block?.verboseData?.blueScore ?? NaN); }
|
||||
async function isChainAncestor(node, hash) {
|
||||
// the block is on the node's selected chain when the node's own checkpoint record for its index names it; cheaper and
|
||||
// exact: ask the chain from the pruning point to the sink and look for it
|
||||
const d = await dag(node); if (!d) return null;
|
||||
const r = await node.rpc.call('getVirtualChainFromBlock', { startHash: d.pruningPointHash, includeAcceptedTransactionIds: false }).catch(() => null);
|
||||
if (!r) return null;
|
||||
return (r.addedChainBlockHashes || []).includes(hash);
|
||||
}
|
||||
|
||||
async function network(mode) {
|
||||
const n1 = new Node(1, { name: 'n1' });
|
||||
await n1.start();
|
||||
const p0 = new Proxy(0, n1.p2pPort, { delayMs: DELAY_MS }); await p0.start();
|
||||
const p2 = new Proxy(2, n1.p2pPort, { delayMs: DELAY_MS }); await p2.start();
|
||||
const n0 = new Node(0, { name: 'n0', connect: [p0.addr] });
|
||||
const n2 = new Node(2, { name: 'n2', connect: [p2.addr] });
|
||||
await n0.start(); await n2.start();
|
||||
await sleep(3000);
|
||||
log(`network up (${mode}): peers n0 ${await peers(n0)} n1 ${await peers(n1)} n2 ${await peers(n2)}; override ${process.env.IGNEUM_FIN_OVERRIDE_JSON}`);
|
||||
return { n0, n1, n2, p0, p2 };
|
||||
}
|
||||
|
||||
async function run(mode) {
|
||||
const name = `weight-vs-work-${mode}`;
|
||||
const { n0, n1, n2, p0 } = await network(mode);
|
||||
const secsWarm = WARM + 30, secsSplit = SPLIT + HEAL + 60;
|
||||
const warmPlan = [[n0, 'q0', 0.15], [n0, 'q1', 0.15], [n1, 'p0', 0.175], [n1, 'p1', 0.175], [n2, 'p2', 0.175], [n2, 'p3', 0.175]];
|
||||
let miners = warmPlan.map(([node, label, share]) => new Miner(node, { label, share, bps: 1, secs: secsWarm }).start());
|
||||
await sleep(WARM * 1000);
|
||||
const w = await n1.rpc.call('getFinalityWeights', {}).catch(() => ({}));
|
||||
const before = await Promise.all([n0, n1, n2].map(n => checkpoints(n)));
|
||||
const beforeMax = before.map(maxLocked);
|
||||
const preMax = Math.max(...beforeMax);
|
||||
const dagsCut = await Promise.all([n0, n1, n2].map(dag));
|
||||
log(`${name}: cut at warm ${WARM} s: window daa ~${w.daaScore}, voters ${w.voters}, max locked ${beforeMax.join('/')}, blocks ${dagsCut.map(d => d?.blockCount).join('/')}`);
|
||||
// the cut, and the rates swapped: A at RA (two keys), B at RB (four keys)
|
||||
for (const m of miners) await m.stop();
|
||||
const tCut = Date.now();
|
||||
p0.cut();
|
||||
const splitPlan = [[n0, 'q0', RA / 2], [n0, 'q1', RA / 2], [n1, 'p0', RB / 4], [n1, 'p1', RB / 4], [n2, 'p2', RB / 4], [n2, 'p3', RB / 4]];
|
||||
miners = splitPlan.map(([node, label, share]) => new Miner(node, { label, share, bps: 1, secs: secsSplit }).start());
|
||||
const firstNew = [null, null, null], maxNew = [...beforeMax];
|
||||
while (Date.now() - tCut < SPLIT * 1000) {
|
||||
const cps = await Promise.all([n0, n1, n2].map(n => checkpoints(n)));
|
||||
cps.forEach((cp, i) => {
|
||||
const m = maxLocked(cp);
|
||||
if (m > maxNew[i]) maxNew[i] = m;
|
||||
if (firstNew[i] == null && m > preMax) firstNew[i] = Math.round((Date.now() - tCut) / 1000);
|
||||
});
|
||||
await sleep(3000);
|
||||
}
|
||||
const newLocks = maxNew.map((m, i) => Math.max(0, m - preMax));
|
||||
// the two chains at the end of the split
|
||||
const dagsEnd = await Promise.all([n0, n1, n2].map(dag));
|
||||
const sinkA = dagsEnd[0]?.sink, sinkB = dagsEnd[1]?.sink;
|
||||
const bsA = await blueScore(n0, sinkA), bsB = await blueScore(n1, sinkB);
|
||||
const cpsEnd = await Promise.all([n0, n1, n2].map(n => checkpoints(n)));
|
||||
const bLockedDuring = [...lockedMap(cpsEnd[1]).entries()].filter(([i]) => i > preMax);
|
||||
log(`${name}: end of split: A sink blue score ${bsA} (${dagsEnd[0]?.blockCount} blocks), B sink blue score ${bsB} (${dagsEnd[1]?.blockCount} blocks); B locked ${bLockedDuring.length} new index(es) ${bLockedDuring.map(([i]) => i).join(',')}; A locked ${newLocks[0]}`);
|
||||
p0.heal();
|
||||
const tHeal = Date.now();
|
||||
let reconnected = null;
|
||||
while (Date.now() - tHeal < HEAL * 1000) {
|
||||
if (reconnected == null && (await peers(n0)) > 0) reconnected = Math.round((Date.now() - tHeal) / 1000);
|
||||
await sleep(3000);
|
||||
}
|
||||
for (const m of miners) await m.stop();
|
||||
await sleep(4000);
|
||||
const after = await Promise.all([n0, n1, n2].map(n => checkpoints(n)));
|
||||
const afterMax = after.map(maxLocked);
|
||||
const dagsAfter = await Promise.all([n0, n1, n2].map(dag));
|
||||
const sinks = dagsAfter.map(d => d?.sink);
|
||||
const converged = new Set(sinks).size === 1;
|
||||
// where did the network end: on A's split chain, on B's, or on neither (a merge of both is still "through" one)
|
||||
const onA = await Promise.all([n0, n1, n2].map(n => isChainAncestor(n, sinkA)));
|
||||
const onB = await Promise.all([n0, n1, n2].map(n => isChainAncestor(n, sinkB)));
|
||||
const maps = after.map(lockedMap);
|
||||
let disagree = 0;
|
||||
const common = new Set([...maps[0].keys()].filter(k => maps[1].has(k) && maps[2].has(k)));
|
||||
for (const k of common) if (new Set(maps.map(m => m.get(k))).size > 1) disagree++;
|
||||
const bAdoptedByA = bLockedDuring.every(([i, h]) => maps[0].get(i) === h);
|
||||
const conflicts = [n0, n1, n2].map(n => n.grepLog(/CONFLICTING certificate/).length);
|
||||
const redetermined = [n0, n1, n2].map(n => n.grepLog(/re-determined/).length);
|
||||
const reorgs = [n0, n1, n2].map(n => n.grepLog(/reorg deeper than the snapshot ring|Reorg|reorg/i).length);
|
||||
await stopAll();
|
||||
const heavier = bsA > bsB ? 'A' : 'B';
|
||||
const ended = converged ? (onB[0] && !onA[0] ? 'B' : onA[0] && !onB[0] ? 'A' : onA[0] && onB[0] ? 'both merged' : 'neither') : 'not converged';
|
||||
const pass = mode === 'on'
|
||||
? (newLocks[0] === 0 && bLockedDuring.length > 0 && converged && ended === 'B' && conflicts.every(c => c === 0) && disagree === 0)
|
||||
: (newLocks.every(x => x === 0) && converged && ended === heavier);
|
||||
out(`\n### ${name}: warm ${WARM} s at 1 block/s (B 70% of weight, A 30%), split ${SPLIT} s with A at ${RA} and B at ${RB} blocks/s, heal window ${HEAL} s, link delay ${DELAY_MS} ms, module ${mode} (${mode === 'on' ? 'rule v3 from checkpoint DAA 0' : 'min_daa never: no certificate can form'}), node ${IGNEUMD.split('/').slice(-3).join('/')}\n`);
|
||||
out('| measure | n0 (side A, work majority) | n1 (side B, weight majority) | n2 (side B) |');
|
||||
out('|---|---|---|---|');
|
||||
out(`| max locked index at the cut | ${beforeMax.join(' | ')} |`);
|
||||
out(`| new locks during the split (index above ${preMax}) | ${newLocks.join(' | ')} |`);
|
||||
out(`| first new lock, s after the cut | ${firstNew.map(x => x ?? 'none').join(' | ')} |`);
|
||||
out(`| max locked index at the end of the heal window | ${afterMax.join(' | ')} |`);
|
||||
out(`| sink at the end of the heal window | ${sinks.map(s => String(s).slice(0, 10)).join(' | ')} |`);
|
||||
out(`| A's split tip on the final chain / B's split tip on the final chain | ${onA.map((a, i) => `${a} / ${onB[i]}`).join(' | ')} |`);
|
||||
out(`| conflicting certificates logged | ${conflicts.join(' | ')} |`);
|
||||
out(`| re-determined lines (F24) | ${redetermined.join(' | ')} |`);
|
||||
out(`| reorg lines in the node log | ${reorgs.join(' | ')} |`);
|
||||
out(`\nAt the end of the split: A's sink blue score ${bsA} against B's ${bsB} (the heavier chain by blue work is ${heavier}'s); B locked ${bLockedDuring.length} new checkpoint(s) during the split${bLockedDuring.length ? ' at index ' + bLockedDuring.map(([i]) => i).join(', ') : ''}. After the heal: n0 reconnected ${reconnected == null ? 'not within the heal window' : reconnected + ' s after the gate reopened'}; the three sinks ${converged ? 'agree' : 'DISAGREE'}; the network ended on ${ended}'s chain; A adopted B's split-time locks: ${bAdoptedByA}; locked indices disagreeing across the three nodes: ${disagree}. ${pass ? 'PASS' : 'FAIL'} against the expectation for module ${mode} (${mode === 'on' ? "B's certified chain wins although A's is heavier" : 'the heavier chain wins'}).`);
|
||||
results.push({ name, pass, heavier, ended, converged, bsA, bsB, newLocks, bLocked: bLockedDuring.length, conflicts, disagree });
|
||||
}
|
||||
|
||||
async function main() {
|
||||
assertBinaries();
|
||||
for (const mode of [MODE]) {
|
||||
log(`=== module ${mode} starting ===`);
|
||||
try { await run(mode); } catch (e) { log(`${mode} threw: ${e.stack || e}`); results.push({ name: mode, pass: false }); await stopAll(); }
|
||||
log(`=== module ${mode} done ===`);
|
||||
}
|
||||
out('\n' + results.map(r => `[${r.pass ? 'PASS' : 'FAIL'}] ${r.name}`).join('\n'));
|
||||
writeFileSync(`${TMP}/results-${MODE}.json`, JSON.stringify(results, null, 2));
|
||||
await stopAll();
|
||||
process.exit(results.some(r => !r.pass) ? 1 : 0);
|
||||
}
|
||||
main();
|
||||
Loading…
Reference in a new issue