From d4af7db711f133e5a6b171f4f290682e702d2c7c Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Sat, 3 Oct 2026 20:46:40 +0000 Subject: [PATCH] Review round 3: litepaper reorg bound and emission sentences, design 5.5 veto (F15, E10, P11) Litepaper Finality: the reorg bound users rely on is the 12-hour finality depth in median time; Kaspa's one-hour merge depth is a merge limit, not a reorganisation bound; first-month sentence and "does not claim" item 4 say the same. Litepaper Speed: emission per block on a schedule keyed to difficulty-adjusted time, reds in the window paid, coins track blocks within the controller's accuracy. Design 5.5 and D12: the native-execution veto is relative to the carrying block's own selected-parent chain; two-node reorg test added to 8.5. Ledger P11, F15, E10 statuses and fixes rows 79, 82, 84 updated. Co-Authored-By: Claude Fable 5.1 --- docs/design/execution-layer.md | 5 +++-- docs/fud-fixes.md | 6 +++--- docs/fud-ledger.md | 6 +++--- site/litepaper.html | 8 ++++---- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/design/execution-layer.md b/docs/design/execution-layer.md index 8eeb30082..cc9c71825 100644 --- a/docs/design/execution-layer.md +++ b/docs/design/execution-layer.md @@ -23,7 +23,7 @@ What this document rests on, fixed by the design document and CLAUDE.md and not | D9 | Gas has two dimensions: execution gas on Ethereum's schedule, unchanged; proving gas (pgas) on a per-opcode and per-precompile table calibrated in reference prover kilocycles. One transaction gas limit; the wei budget `gas_limit x max_fee_per_gas` caps both dimensions. Base fee per dimension, EIP-1559 adjusted, burned | 4 | | D10 | Developer attribution per call frame by execution gas, to the registration of the account whose code runs; registration by the deployer at deployment through a system registry; created contracts inherit the creator's registration unless re-registered in the same transaction; unregistered frames' 20% is burned | 4.5 | | D11 | Shards are cut from the native execution trace by pgas, never splitting a transaction; continuations for one transaction above the shard budget. Sortition assigns each shard to 8 eligible provers for a 10 s exclusive window, then open. No claim bond in-chain; the bond is for the external job market only | 5 | -| D12 | A full node rejects a block whose proof record disagrees with its own native execution (the native-execution veto). Proof system versioned in consensus, three-month overlap, 90% signalling, latest proof wrapped once at the switch | 5.5 | +| D12 | A block is invalid if a proof record it carries disagrees with the native execution of the named segment along the carrying block's own selected-parent chain (the native-execution veto, relative to the block's past, not the node's current chain; ledger P11). Proof system versioned in consensus, three-month overlap, 90% signalling, latest proof wrapped once at the switch | 5.5 | | D13 | Native proving precompile at a fixed system address: request now, result delivered by a later proof record that runs a callback; paid by the requester with the external-job split | 6 | | D14 | Light clients at launch verify the execution proof chain from a certificate they are given. Phase two adds the consensus proof | 7 | | D15 | Chain id 4461 mainnet, 4462 testnet, 4463 devnet. Standard `eth_*` surface; chain blocks are the RPC blocks; `igneum_*` exposes the DAG, skipped transactions and the executed, proven, locked status | 8 | @@ -267,7 +267,7 @@ Full nodes verify `proof` natively (a compressed SP1 proof verifies in well unde ### 5.5 The native-execution veto -Decision. A block is invalid if any proof record it carries has `post_root` or `receipts` different from the node's own native execution of that segment, or fails cryptographic verification, or names a segment not on the node's selected chain. The record is a claim about an earlier segment that every full node can check by running it, so this is not a state claim the producer must execute to make; it is a claim the producer can check before including. A forged proof from a soundness bug (ledger P7) is therefore rejected by every full node, and the damage is limited to light clients that saw it before a full node did. The emergency path for a live soundness bug is human: a release that bumps the proof system version with a shortened overlap, activated by miner signalling, and the litepaper says so. +Decision (reworded 3 October 2026, ledger P11, round 3; spec 7.2 item 5 is the rule). A block B is invalid if any proof record it carries fails cryptographic verification, names a chain block that is not on B's own selected-parent chain, or has `post_root` or `receipts` different from the native execution of that segment along B's chain. The test is relative to B's own past, never to the validating node's current selected chain: that chain is a property of the node's virtual and differs between honest nodes every second on a DAG, so the earlier wording ("the node's selected chain", "the node's own native execution") let two honest nodes disagree on one block during a one-block reorg. Written against B's chain, validity is a function of the block and its past and every node computes it identically. The record is a claim about an earlier segment that every full node can check by running it along the carrying block's chain, so this is not a state claim the producer must execute to make; it is a claim the producer can check before including. A forged proof from a soundness bug (ledger P7) is therefore rejected by every full node, and the damage is limited to light clients that saw it before a full node did. The emergency path for a live soundness bug is human: a release that bumps the proof system version with a shortened overlap, activated by miner signalling, and the litepaper says so. ### 5.6 The versioned prover trait and the swap procedure @@ -377,6 +377,7 @@ Blockscout indexes through standard RPC and needs: `eth_getBlockByNumber` with c | Skip rule | Inject duplicates, nonce gaps, under-funded senders and over-budget transactions into parallel blocks | Executed set and state roots identical across 3 independent node implementations of the skip rule (two Rust, one Python oracle) | | pgas determinism | Replay 10,000 mainnet-shaped transactions on 3 machines | Identical pgas per transaction | | Native versus proven | For 1,000 segments, prove with the SP1 implementation and compare the claim to native | Zero disagreements; any disagreement is a release blocker | +| Veto under reorg (ledger P11) | Two nodes with different tips validate the same proof-bearing block during a simnet one-block reorg, 1,000 trials | Both nodes return the same validity for every block, because the veto of 5.5 is evaluated along the carrying block's own chain | ## 9. Risks, open questions, acceptance criteria diff --git a/docs/fud-fixes.md b/docs/fud-fixes.md index f2414967b..cd3c3e587 100644 --- a/docs/fud-fixes.md +++ b/docs/fud-fixes.md @@ -128,12 +128,12 @@ Added after `docs/review/round-3-2026-10-03.md`. Rows continue the numbering of | 76 | P13 | LP Proving: "Miners claim shards with a small bond" | Fixed 3 October 2026: "Shards are assigned by lot to eight provers for ten seconds, then open to anyone; there is no bond" | Claude | done | no | | 77 | E11 | HP tile "IGN burned from jobs, at launch"; the quoted paragraph had already left the trimmed page | Fixed 3 October 2026: tile reads "phase two"; caption adds "Jobs are paid on the customer's chain at launch; settlement in IGN with a 10% burn follows the proof bridge in phase two" | Claude | done | no | | 78 | L7 | LP Economics heading "Where the price comes from" and the burn-reduces-supply sentence | Fixed 3 October 2026: heading "Where fees go", sentence deleted. Counsel reads the section under row 46 | Claude; counsel | done; before public repo | no | -| 79 | P11 | Native-execution veto written against the node's current selected chain | Spec 7.2 item 5 rewritten 3 October 2026, relative to the carrying block's own selected-parent chain. Left: `docs/design/execution-layer.md` 5.5 to match, and the two-node reorg test in its 8.5 | Claude | now | no | +| 79 | P11 | Native-execution veto written against the node's current selected chain | Spec 7.2 item 5 rewritten 3 October 2026, relative to the carrying block's own selected-parent chain. `docs/design/execution-layer.md` 5.5 and D12 rewritten and the two-node reorg test added to its 8.5 the same evening | Claude | done | no | | 80 | F17, P8 | Shard sortition per key; keys are free; launcher mints 8 per card | Spec 7.2 step 2 draws by weight and spec 3.1 W6 states the principle, 3 October 2026. Left: client default of one vote key per operator (`MINERS` multiplies workers, not keys); S2 and the bitmap size (O-3.5, O-3.12) before the voter count can cross 8,192 | Claude (spec, done); miner client (default) | before testnet | no | | 81 | M14, F14 | Weight and presence windows in DAA seconds under a lagging retarget; no finality run with a DAA model | Spec 3.1 W2 and 3.3 Q1 in past-median time, weight per 60-s bucket, 3 October 2026 (simulated form kept beside it). O-3.14 added: `finality_v2.py` with the DAA in the loop, 50x pulsed renter, both W2 forms, logged in the bench-log. Controller choice is gate 2 (O-2.1) | Claude (spec, done); measurement (O-3.14) | before testnet | no | -| 82 | F15 | Merge depth called the reorg bound; the code's bound is the finality depth, 43,200 DAA s | Spec 2.1, 3.8 and 3.9 name the finality depth, in median time (12 h), 3 October 2026; simnet reorg test (2, 6, 13 h forks) written into 2.1 for gate 2. Left: LP Finality "Kaspa's one-hour merge-depth bound limits any reorganisation" and "What Igneum does not claim" item 4 "bounded to one hour" | Claude (LP text); measurement (simnet) | now (LP); before testnet | no | +| 82 | F15 | Merge depth called the reorg bound; the code's bound is the finality depth, 43,200 DAA s | Spec 2.1, 3.8 and 3.9 name the finality depth, in median time (12 h), 3 October 2026; simnet reorg test (2, 6, 13 h forks) written into 2.1 for gate 2. LP Finality (first-month and merge-depth sentences) and "What Igneum does not claim" item 4 rewritten the same evening: 12-hour finality depth, merge depth a merge limit. Left: the simnet test | Claude (done); measurement (simnet) | before testnet | no | | 83 | E9 | Spec year 365 days; code 365.25 (31,557,600 s, halving 63,115,200 s, 3,168,808,781 sompi/s) | Spec 2.5 follows the code, 3 October 2026. Divergence record for the code owner: the spec was changed, the code was not; add a test that reads the published numbers (year, halving interval, per-second rate, ramp) and asserts them against `consensus/core/src/igneum.rs`, and decide O-2.6 (8 decimals fits the u64 cap, 18 does not) before the first testnet genesis | code, owner consensus engineer | before testnet | no | -| 84 | E10 | Spec said reds unpaid and "more blocks never means more coins"; code pays reds in the DAA window to the merger and mints per block | Spec 2.5 follows the code, 3 October 2026. Divergence record for the code owner: no code change; the litepaper Speed sentence "Emission is paid per unit of difficulty-adjusted work, never per block, so a faster chain never means more coins" is now wrong and must be rewritten (schedule in DAA seconds, paid per block, short-run rate set by the controller) | Claude (LP text) | now | no | +| 84 | E10 | Spec said reds unpaid and "more blocks never means more coins"; code pays reds in the DAA window to the merger and mints per block | Spec 2.5 follows the code, 3 October 2026. Divergence record for the code owner: no code change; the litepaper Speed sentence ("never per block") was rewritten the same evening to match 2.5: emission per block on a schedule keyed to difficulty-adjusted time, reds in the window paid, coins track blocks within the controller's accuracy | Claude | done | no | | 85 | G9 | Release key: single steward, lost key unrevocable | Spec 8.2 items 2 and 5 rewritten 3 October 2026: key chain, rotation signed by the current key, revocation signed by the previous key (pre-signed certificate for K0), published in a block; policy before the client ships, with entity and jurisdiction. Left: the policy itself and the second holder (O-8.1, L1) | the project lead (custody), counsel | before testnet | EXPOSES: the policy names the entity, never a person's residence | | 86 | M15 | Pre-validation PoW cost: any past timestamp or claimed DAA score forces a 256 MiB cache fill before the checks that would reject the header | Run `check_difficulty_and_daa_score` and the past-median check before `check_pow_and_calc_block_level` in `validate_header`; derive the day from DAA score or the selected parent's window; `KEEP` 4; per-peer cap on cache builds. Review's first of five | code, owner consensus engineer | now | no | | 87 | M20 | Pruning proofs validated with the kHeavyHash stub: a fresh node cannot sync from a lottery-mined pruning point; a loosened check is forgeable with an existing ASIC | Thread the epoch and day seeds through `pruning_proof/validate.rs`, `apply.rs` and `mod.rs` (fork map a4, O-2.5); test by syncing a fresh node from the 30-hour devnet | code, owner consensus engineer | before testnet | no | diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 70e7ae067..3f51e85ec 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -1123,7 +1123,7 @@ Evidence: spec 3.1 W2, 3.3 Q1; `sim/results_v2.md` assumptions. Experiment: the ### F15. Merge depth is not the reorg bound; the finality depth is "You tell exchanges that in month one the one-hour merge-depth bound limits a reorganisation. `check_bounded_merge_depth` only forbids merging an old red. The virtual switches to any heavier chain until the finality point, which you kept at 12 hours." -Status: Spec fixed (3 October 2026): spec 2.1 names the finality depth as the reorg bound and merge depth as a merge limit only, spec 3.8 and 3.9 tell exchanges to wait 12 hours of past-median time when `finality_active` is false, and the simnet reorg test is written into 2.1 for gate 2. Still to change: the litepaper Finality sentence ("one-hour merge-depth bound") and "What Igneum does not claim" item 4 ("bounded to one hour"). Was: Open, text and rule fix named. +Status: Spec fixed (3 October 2026): spec 2.1 names the finality depth as the reorg bound and merge depth as a merge limit only, spec 3.8 and 3.9 tell exchanges to wait 12 hours of past-median time when `finality_active` is false, and the simnet reorg test is written into 2.1 for gate 2. The litepaper Finality paragraph (first-month sentence and the merge-depth sentence) and "What Igneum does not claim" item 4 now name the 12-hour finality depth and call merge depth a merge limit (same evening). Was: Open, text and rule fix named. Answer: Correct on reading the fork. `post_pow_validation.rs:79` bounds which reds a block may merge; the selected-chain switch is bounded by the finality point (`virtual_processor/processor.rs:1626`, `FINALITY_DURATION` 43,200 DAA seconds). So the month-one reorg bound is 12 hours of DAA time, not one hour, and spec 3.8, 3.9, litepaper "Finality" and "What Igneum does not claim" item 4 rest on the wrong constant. Fix: state the finality depth as the bound, in median time (M14 explains why not DAA time), or lower `FINALITY_DURATION` and accept Kaspa's finality-conflict handling at that depth; test with a heavier private chain forked 2, 6 and 13 hours back on simnet. @@ -1159,7 +1159,7 @@ Evidence: `sim/results_v2.md` C and D; spec 3.3.1; `site/litepaper.html` Finalit ### P11. The native-execution veto makes block validity depend on the node's current selected chain "Section 5.5: a block is invalid if a proof record names a segment not on the node's selected chain, or disagrees with the node's own execution. Two honest nodes with different tips disagree on the same block. You removed the hidden-block penalty for this exact reason." -Status: Fixed in the spec (3 October 2026): spec 7.2 item 5 is relative to the carrying block's own selected-parent chain and supersedes the design document's 5.5 wording. Still to follow: `docs/design/execution-layer.md` 5.5 itself and the two-node reorg test in its 8.5. Was: Open, text fix named. +Status: Fixed (3 October 2026): spec 7.2 item 5 and `docs/design/execution-layer.md` 5.5 and D12 are relative to the carrying block's own selected-parent chain; the two-node reorg test is a row in the design document's 8.5. Was: Open, text fix named. Answer: Correct. `docs/design/execution-layer.md` 5.5 (D12) and spec 7.2 item 5 reference the node's selected chain, which is a property of its virtual, not of the block's past. Fix: a proof record is valid if the chain block it names is on the carrying block's own selected-parent chain and its `post_root` and receipts equal the execution of that segment along that chain, which every node computes from the block's past. Add a two-node reorg test to section 8.5. @@ -1213,7 +1213,7 @@ Evidence: the two files. Review id R3.19. ### E10. Reds are paid in the code and "more blocks never means more coins" is false "Spec 2.5: red blocks are unpaid, emission is keyed to DAA score so more blocks never means more coins. `coinbase.rs` pays a red's 80% to the merging miner and its 20% to the pool, and every blue block in the DAA window mints `E(daa)`. Tonight your chain minted 4.7x the schedule for eight minutes." -Status: Fixed (3 October 2026): spec 2.5 says reds inside the DAA window are paid to the merging miner (80%) and the pool (20%), that `E` is paid per block so coins are blocks times `E` under the controller's rate, and that the cap is unaffected; "more blocks never means more coins" is withdrawn. The litepaper Speed sentence "never per block, so a faster chain never means more coins" is a separate text fix, rowed in `docs/fud-fixes.md`. Was: Conceded, text fix named. +Status: Fixed (3 October 2026): spec 2.5 says reds inside the DAA window are paid to the merging miner (80%) and the pool (20%), that `E` is paid per block so coins are blocks times `E` under the controller's rate, and that the cap is unaffected; "more blocks never means more coins" is withdrawn. The litepaper Speed sentence ("never per block") was rewritten the same evening: emission per block on a schedule keyed to difficulty-adjusted time, reds in the window paid, coins track blocks within the controller's accuracy. Was: Conceded, text fix named. Answer: Correct. `consensus/src/processes/coinbase.rs:102` to `109` follows Kaspa's rule for reds; `block_subsidy` is paid per blue (and red) block in the DAA window, so coins are blocks times `E` and the controller's rate sets the short-run emission, as on every proof-of-work chain. Timestamps still cannot mint. Fix: spec 2.5 to say what the code does (reds paid to the merger, emission per block under the controller's rate, the cap unaffected), or the code to say what the spec does; the review recommends the code's rule. diff --git a/site/litepaper.html b/site/litepaper.html index 3635b2dbb..923712fb0 100644 --- a/site/litepaper.html +++ b/site/litepaper.html @@ -320,12 +320,12 @@ body.all .pager{display:none}

Speed and finality, powered by miners alone

Speed

-

Igneum orders blocks with GHOSTDAG, the BlockDAG consensus proven on Kaspa. Blocks arrive in parallel and are ordered rather than orphaned, so the chain runs at one block a second at launch with scheduled steps to four and ten. A transaction is included in about one second, against twelve on Ethereum, and locked in about two minutes against roughly thirteen. Emission is paid per unit of difficulty-adjusted work, never per block, so a faster chain never means more coins.

+

Igneum orders blocks with GHOSTDAG, the BlockDAG consensus proven on Kaspa. Blocks arrive in parallel and are ordered rather than orphaned, so the chain runs at one block a second at launch with scheduled steps to four and ten. A transaction is included in about one second, against twelve on Ethereum, and locked in about two minutes against roughly thirteen. Emission per block is a schedule keyed to difficulty-adjusted time, and every block in the window is paid at that rate, red or blue, so coins track blocks within the accuracy of the difficulty controller.

Finality

-

Every 30 seconds of chain a checkpoint forms, deep enough past the tip that the DAG will not reorder it. Every miner with at least 100 blocks in the last 30 days signs it, and the checkpoint locks when signatures representing two thirds of the active mining weight arrive. Once a checkpoint is locked it overrides the heaviest chain, so no amount of fresh hashrate can reorganise past it. In the chain's first month the weights behind those locks are thin, because nobody has a long history yet, and the chain leans on proof of work and the one-hour depth limit the way every new proof-of-work chain does.

+

Every 30 seconds of chain a checkpoint forms, deep enough past the tip that the DAG will not reorder it. Every miner with at least 100 blocks in the last 30 days signs it, and the checkpoint locks when signatures representing two thirds of the active mining weight arrive. Once a checkpoint is locked it overrides the heaviest chain, so no amount of fresh hashrate can reorganise past it. In the chain's first month the weights behind those locks are thin, because nobody has a long history yet, and the chain leans on proof of work and its 12-hour finality depth the way every new proof-of-work chain does.

The word sustained is the whole defence. Block rewards go to whoever mines, new or old. The right to lock history is earned.

A miner's vote weight is simply the blocks it has mined over the trailing 30 days, measured by work, so splitting into many keys buys nothing and joining a pool costs nothing. Hashrate that arrived today holds almost none of it. Even an attacker who brought the whole network's hashrate would need ten days of mining in public to hold a third of the weight, and twenty days to hold two thirds. At 51% of the network they never reach two thirds at all while the honest miners keep mining. Rental is priced by the hour. The only route left is to drive honest miners off the chain and hold two thirds for a month on the public hashrate charts, which is the same limit Bitcoin lives with, with a month's warning attached.

-

Two further rules close the gaps. A key that stops signing drops out of the active count within two hours. A lock still needs 56.7% of all 30-day weight, so if more than about 42% of weight goes quiet finality pauses until it returns or ages out, up to 30 days, and the chain runs on proof of work meanwhile. The node reports the pause. And Kaspa's one-hour merge-depth bound limits any reorganisation beneath the latest lock. Signing two different checkpoints at the same height is equivocation, provable by anyone, and it strips the key of its vote for 30 days.

+

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

What is not here

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

@@ -500,7 +500,7 @@ body.all .pager{display:none}
  • A proof in seconds. Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second.
  • A chip is impossible. No. A chip is pointless, because the target moves before it ships. The honest efficiency ceiling for a fixed chip on a memory-bound program is under 2x, approximate, and Igneum's generator changes under it every hour.
  • A guaranteed income floor. No. External proving is a small market today. Igneum's miners have the lowest cost in it, which is an edge and nothing more.
  • -
  • Finality that no amount of hardware can break. No. A miner holding a third of the last 30 days of blocks can split finality during a network partition, and two thirds can lock a bad checkpoint for a double-spend bounded to one hour. Reaching a third takes at least ten days of the whole network's hashrate, in public. That is harder than attacking Bitcoin, where a majority can reorganise at once, and it is the limit of proof of work without stake or an outside chain. Igneum chose those limits on purpose.
  • +
  • Finality that no amount of hardware can break. No. A miner holding a third of the last 30 days of blocks can split finality during a network partition, and two thirds can lock a bad checkpoint for a double-spend bounded by the 12-hour finality depth. Reaching a third takes at least ten days of the whole network's hashrate, in public. That is harder than attacking Bitcoin, where a majority can reorganise at once, and it is the limit of proof of work without stake or an outside chain. Igneum chose those limits on purpose.
  • Finality that never pauses. No. A lock needs 56.7% of all 30-day mining weight. If more than about 42% of that weight stops 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.
  • A finished protocol. The sustained-mining finality rule is the newest piece and the one that external review will try hardest to break. The specification, the review and the benchmarks are published as they happen.