Fork: vendor/igneum-node-c4 branch c4-fix on release-0.3.6 a24ab01a. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
84 KiB
Igneum protocol specification, section 3: sustained-mining finality, version 2
Spec version 0.1, 3 October 2026. Status of this section: Designed. Simulated at the checkpoint level with latency, partitions and eclipses but without a DAG (sim/finality_v2.py, sim/results_v2.md, docs/bench-log.md entry "sim/finality_v2.py"). Not implemented. Not externally reviewed. Gate 3 is the external review that tries to break it.
The rule is exactly the design document's "Finality rule, version 2, after the second hostile review" with the quorum floor added on 3 October 2026 after the second simulation and raised to two thirds of total weight on 4 October 2026 (the project lead's decision, O-3.15). The rule in two sentences: a checkpoint locks when two thirds of all 30-day mining weight has signed it. Finality pauses whenever less than two thirds of that weight is connected and signing, the chain continues on proof of work meanwhile, and the node reports it. CLAUDE.md's FINALITY RULE V2 paragraph is the short form (its 56.7% figure predates the decision). Every quantity is in blue score, DAA seconds or past-median time, never wall-clock (section 0.6). Past-median time, mt(B), is the median timestamp of a block's sampled past (Kaspa's consensus/src/processes/past_median_time.rs, PAST_MEDIAN_TIME_SAMPLE_INTERVAL 10, kept): consensus data computed from the block's past, which a burst of blocks cannot run fast the way it runs DAA score (ledger M14 and F14, round 3).
Two statements frame everything below. Finality is miner-only and self-contained: no stake, no bond, no other chain, no committee that is not the set of recent miners. Equivocation costs history, not coins, because there are no coins to slash.
3.1 Weight
- W1. Every block header names a vote key by
vote_key_hash(section 2.4): the hash of a BLS12-381 G1 compressed public key. The first block that uses a key reveals the key in its coinbase payload. A header whosevote_key_hashhas never been revealed is valid; the key simply cannot vote until it is revealed. - W2. Weight is counted in blocks and denominated in past-median time (rule of 3 October 2026, ledger M14 and F14, round 3; the simulated form is kept below). Cut the trailing 30 days of past-median time before C,
(mt(C) - 2,592,000 s, mt(C)], into 43,200 buckets of 60 s; a blue block in C's past falls in the bucket that holds its own past-median time. The weight of key k at C is the sum over buckets of k's share of the blue blocks in that bucket (an empty bucket contributes 0 to everyone). A bucket is worth 1 whatever it holds, so 50x the blocks in one minute is one minute of weight, and a retarget lag can neither inflate a key's count nor age the window. No damping, no cap, no floor. Blocks are the only thing in proof of work that cannot be forged, so weight is counted in blocks; time is the denominator because blocks per unit of DAA time is exactly what a lagging controller lets a renter buy (section 2.3;docs/review/round-3-2026-10-03.md, "Tonight's devnet"). As simulated (sim/results_v2.md, every run): the number of blue blocks in C's past whose header names k and whose DAA score is in(daa(C) - 2,592,000, daa(C)]. The two forms agree whenever the controller holds the target; O-3.14 runs the simulation under both with the DAA in the loop and confirms or reverts this rule at gate 3. The damped rule of version 1 was removed because its 2x cap was defeated by splitting into free keys (sim/results.mdtable C;docs/bench-log.mdfinality_sim entry). - W3. Dust: a key with fewer than 100 blue blocks in the window (a block count, not bucket weight) is not a voter and is in no denominator. Measured consequence (
sim/results_v2.mdA and G): every honest key in a 1,000-key Pareto network clears 100 blocks by day 20 from zero history and the smallest new keys need up to 25 days after a doubling; a 9x renter's victims lose about one point to dust (B). - W4. Steady state: weight equals hashrate. Simulated correlation 1.00000 at day 60, Gini equal to three figures, weight-to-hash ratio within 0.82 to 1.12 for every key (
sim/results_v2.mdA). - W5. Key succession: a message signed by the old key naming a new key, included in any block, moves the old key's weight history to the new key once. The old key is dead thereafter: its later blocks earn nothing and its votes are invalid.
- W6. Keys are free. Nothing in the protocol prices a vote key and the devnet launcher mints one per worker process (ledger F17, round 3). Weight is the only Sybil-resistant quantity in this specification, so every rule that draws from the voter population draws by weight and never per key: W2 (no damping, no per-key cap), the shard sortition of section 7.2 (drawn by weight since 3 October 2026) and the sub-user sortition of S2. A rule that counts keys is a rule a splitter wins.
The headline arithmetic (W2 with constant hashrate): an attacker with share a of hashrate for t days holds weight share (t/30) x a/(1+a), verified by simulation to 0.04 points for a = 1 and 2 (sim/results_v2.md B).
| Attacker hashrate relative to honest (a) | Reaches 1/3 (can veto) | Reaches 2/3 (locks alone) |
|---|---|---|
| 1x (50% of blocks) | day 20.0 | never (ceiling 50%) |
| 2x (67%) | day 15.0 | day 30.0 |
| 4x (80%) | day 12.5 | day 25.0 |
| 9x (90%) | day 11.1 | day 22.2 |
| unbounded (100% of blocks, honest miners gone) | day 10 | day 20 |
All in public, on the hashrate charts. 51% never reaches 2/3 while honest miners keep mining.
3.2 Checkpoints
- C1. Checkpoint i is the selected-chain block at blue score 30 i. It is determined once the virtual's blue score reaches 30 i + d. d = 60 at 1 block per second is a placeholder (ledger F7): the gate 3 devnet records the reorg-depth distribution and sets d so that a vote split at one index is rare and self-heals at the next. d scales with block rate. Re-determination (rule of 4 October 2026, night, ledger F24): while index i is not locked, a node whose selected chain moves past C_i (a reorg deeper than d) determines index i again on its new chain; its own votes for the old block stand (a key never signs two blocks at one index) and a certificate the network formed over the new block, received meanwhile and held pending, is then verified. A locked index is never re-determined (3.11.4): fork choice keeps the chain through its block, and a certificate for another block there is a conflict (C4). A lock lands about 90 to 120 s after a transaction (Designed; simulated lock latency after the checkpoint block is median 2.5 s, p99 4.6 s at a 2-s inter-region delay,
sim/results_v2.mdA). - C2. A vote is a BLS signature over
(chain_id, i, hash(C_i))under a fixed domain-separation tag. Votes gossip as their own message type. - C3. A lock certificate for index i is an aggregate BLS signature over one checkpoint block hash with a bitmap of signers, whose signed weight meets Q3. Every block carries the highest certificate its producer knows. A block whose selected chain does not pass through every certified checkpoint in its past is invalid (section 2.4).
- C4. A node holding a LOCK at index i rejects any other certificate for index i and publishes the pair as evidence (section 3.6). A certificate over a block that is not the node's own determination at an index it has not locked is not a conflict: the node verifies it at that block and, when it is valid there, locks the index on it and moves its chain (3.5, the certificate-driven reorg, rule of 5 October 2026 night, ledger C4). A block the node does not have yet is kept pending, bounded, and tried again as the DAG arrives (ledger F24). A certificate naming a block that cannot be index i's checkpoint on any chain (its blue score is under 30 i, or its selected parent's is not) is refused outright.
- C5. No certificate may form in the chain's first 3,600 DAA seconds (design document). See 3.8 for the proposed first-month rule.
3.3 Quorum
- Q1. Presence window P = 7,200 s of past-median time: index j is in the window of index i when
0 < mt(C_i) - mt(C_j) <= 7,200. About 240 indices at the target rate. Denominated in median time, not indices or DAA seconds, so a burst of blocks cannot shrink the window to minutes (ledger M14 and F14, round 3; the simulation ran with a fixed 240 indices). - Q2. Participation of key k at index i, "block reading" (rule of 3 October 2026, ledger F3): the number of indices j in the presence window of i (Q1) for which a valid vote by k at index j appears in the past of C_i, divided by the number of indices in that window, capped at 1. A vote "appears in the past of C_i" when it is carried, as a vote or inside a certificate, by any block in the past of C_i, blue or red. A key whose first block is younger than the presence window counts 1. Votes are block payload: every block MUST carry every valid vote its producer has received for i_b or an index in its presence window (i_b the highest checkpoint index determined in the block's past) that is not already carried by a block in its past, up to the per-block vote bound of O-3.3; votes for one
(index, checkpoint hash)pair MAY be aggregated inside the block into one BLS signature with a bitmap. A block that omits a vote it has received is not invalid (no node can prove what another received); the rule binds honest producers and the argument of 3.3.2 says why that is enough. This reading is objective, since every node computes it from the same past of C_i, and self-healing, since a missed index rolls out of the window after two hours of median time. The "cert reading" of the simulation (only votes inside certificates count) is a subset of it and was the reading the simulation ran with; the node-local "seen" reading is rejected as not objective and the "frozen" reading as total with extra steps (sim/results_v2.md, "Recommended parameters"). - Q3. Active weight at i is the sum over voters of weight x participation. Total weight at i is the sum of weight over all keys above dust. A certificate for index i locks when the unscaled weight of its signers is at least 2/3 of active weight AND at least 2/3 of total weight (the floor; 17/30 from 3 October 2026 until the project lead raised it to two thirds on 4 October 2026, O-3.15). Both comparisons are inclusive: exactly two thirds locks. Both tests use weights and participation computed at C_i, so any node can verify a certificate from C_i's past. Since active weight never exceeds total weight, the second test implies the first: in plain words, a checkpoint locks when two thirds of all 30-day weight has signed it, and finality pauses whenever less than two thirds of that weight is connected and signing, with the chain continuing on proof of work meanwhile and the node reporting the pause (3.9). The active test and the participation of Q2 stay in the rule as the liveness-side report: they are what the node shows operators about who is present, and they are the test that would bind again if a later review lowered the floor.
- Q4. Certificate fold (rule v3, 4 October 2026, evening, ledger F22; replaces the grace timer of O-3.4): a certificate forms the moment Q3 is met, so lock latency is not held back. Once every voter has signed, or
certificate_foldDAA seconds after the checkpoint's determination (3 on devnet, 6 on mainnet; a relay-latency allowance, not a clock of the protocol), a node that holds a certificate rebuilds it from every vote it has seen when that carries more weight and gossips it, and every node replaces a held certificate with a verified certificate over the same block that carries more signed weight. A block carries the heaviest certificate its producer holds; a block that carries a lighter one is as valid as before, since every certificate still verifies against the table at C_i. The lock is never withdrawn by a replacement (3.11.4): a replacement only adds signers over the same block. Why: on the 12-node cloud devnet of 4 October 2026 the first certificate was built median 1.24 s after the first determination with 7 to 10 of 12 signers, while the last of the 12 votes was issued median 1.45 s, p90 2.36 s after it (infra/cloud-devnet/results/2026-10-04/f22-vote-timing.md), so two checkpoints locked at 66.8% of total with every key connected. The fold carries the votes that arrive after quorum. - Q5. The frozen weight table (rule v3, 4 October 2026, evening, ledger F21; active for checkpoints at or above
finality_v3_activation_daa): letC_fbe the highest certified checkpoint below i whose block is on the selected chain of C_i, andT_fthe weight table atC_f(W2 atC_f, bans applied). A certificate for index i locks only if, in addition to Q3, its signers hold at least two thirds ofT_fat the weights ofT_f; a key outsideT_f's voter list (born since, under dust there, stripped) adds nothing.T_fstands whiledaa(C_i) < daa(C_f) + 2,592,000(one weight window); once a window has passed without a certified checkpoint the frozen table is empty and Q3 alone decides, as before v3. Before the first certificate there is no frozen table. In a connected networkC_fis i - 1 or i - 2 andT_fdiffers from the table at C_i by a minute of blocks, so the test is Q3 with a 30-s lag. Across a partitionT_fis the last table both sides certified together: a side holds its pre-split share of it whatever it mines afterwards, so no side under two thirds locks until that table has expired, 30 days after the last certified checkpoint (3.7 item 9).
3.3.1 Why the floor, and why two thirds, from the simulation
The active denominator alone fails (sim/results_v2.md, seed 7, seed 11 agrees on B and E): a side that cannot see the other side's votes sees stalls, stalls shrink its denominator by 1/240 per index, and once the denominator has fallen to 1.5x the side's own weight the side certifies alone, after 240 x (1 - 1.5 s) / s slots for a side of share s (confirmed within 5% across the sweep): 60 min for a 50% side, 120 for 40%, 180 for 33%. A 50/50 honest partition produced 90 conflicting locks in 150 min, a 60/40 one 624 in 360 min, a 33/33/34 one 1,198, and a 34% attacker poisoning one eclipsed 20% pool finalised a private fork in 49 min (F2). The floor is the second test of Q3 and makes it bind before that point. Its level was 0.85 x 2/3 = 17/30 from 3 October 2026 (chosen because no honest side of any tested split held 56.7% and 40% silent still recovered in 13 minutes) and is 2/3 since 4 October 2026 (the project lead, O-3.15), after 3.11.2 showed that every point of liveness the lower floor bought past one third cost two points of partition safety, and after attack scenario 6A showed the lower floor falling on the devnet.
The two floors, measured (sim/results_v2.md: the 3 October tables at 0.85, the "Floor 2/3" section at 2/3, five seeds; every cell at 2/3 equals the total-denominator column of the 3 October tables, as the arithmetic requires):
| Scenario | Active alone (cert reading, P = 240) | Floor 0.85 (lock needs 56.7% of total) | Floor 2/3 (lock needs 66.7% of total, Q3) |
|---|---|---|---|
| H: 50/50 honest partition with an equivocator holding a of total, 150 and 360 min, retarget | breaks at every a | 0 conflicts up to 13%; 14% (sides 57.0%) conflicts in some seeds from minute 48; 20% (60%) 256 to 276 conflicts from minute 12; 34% from minute 0 | 0 conflicts and no lock on either side up to 33% (sides 66.5%); 34% (sides 67.0%) 2 to 54 conflicts, first at minute 2 to 77, the sides at the knife edge against the 2.2% outage shortfall |
| I: 40/40 honest with a 20% equivocator reaching both (sides 60/60) | breaks | 256 to 276 conflicts, first at minute 12 to 16 | 0 conflicts, no lock on either side |
| I: 40/40/20 honest, with or without a 10% or 20% equivocator | breaks | 0 conflicts, no side locks | 0 conflicts, no side locks |
| E: 60/40 honest, 360 min | 624 conflicts | 0; the 60 side locks from minute 13 | 0; neither side locks |
| F2 and L3: 34% attacker poisons one eclipsed 20% pool, 1 / 2 / 4 h | 10 / 65 / 174 conflicts, first at 49 min | 0 (floor 0.80 gave 10 / 65 / 174, because the eclipsed side's 54% clears 53.3%) | 0 conflicts, 0 locks on the eclipsed side, every seed |
| C, J, L1: weight silent, keeps mining | 0 min at 34%, 13 min at 40%, 20 min at 45% | 0 min at 34%; 13 min and 138 intermittent stalls at 40%; never at 45% | every checkpoint at 30% (one seed 40 stalls in 6 h); 69 to 100% of checkpoints at 32%; 0 to 11% at 33%; never at 34% and above, for as long as they stay silent |
| D, L2: churn (stops mining and signing) | 2 min at 35%, 31 min at 50% | 2 min at 35% (98 intermittent stalls); 4.1 days at 50% | 1.7 days at 35% (analytic 1.4), 10.1 to 10.3 days at 50% (analytic 10.0) |
| K: bought keys worth 40% withhold their votes, 30 days | not run | 305 to 1,085 stalled checkpoints of 86,400 | 63,307 to 68,716 stalled: the pause lasts until the bought weight has decayed below one third, day 19 to 20 |
| L4: long honest partition, each side counting only the blocks it has seen, 12 days | not run | 50/50: both sides lock alone from day 4.1; 60/40: the 60 side at once, the 40 side from day 8.5; 55/45: day 1.2 and 6.5 | 50/50: both from day 10.1 to 10.3; 60/40: the 60 side from day 5.1, the 40 side never in 12 days; 55/45: day 7.9 and 12.0 |
What two thirds buys: the safety bound is one third of total weight in every scenario, including partitions and eclipses of any tested length, because two certificates at one index need two thirds of total each, 4/3 in all, so at least a third signed both (3.11.2). The 13.3% bound of the lower floor, the 14% knife edge and the 60/60 case are gone.
What two thirds costs: finality pauses whenever less than two thirds of 30-day weight is connected and signing. In the model, whose honest keys are in outage 2.2% of the time, the pause begins between 32% and 34% of weight silent, a silent set that keeps mining holds it for as long as it stays silent, and a departed set holds it for 30 (1 - 1/(3x)) days (1.4 days at 35%, 10 days at 50%, the figures ledger F9 quotes). The chain continues on proof of work meanwhile, every certified checkpoint stays binding, the node reports the pause, and the first lock comes 0 minutes after the missing weight returns (J, L1). That is the rule in two sentences, and the litepaper states it.
What no floor removes, and what Q5 does with it: the weight table is per view. A side of an honest partition fills its own window with its own blocks, holds s + (1 - s) t / 30 of its own table on day t for a pre-split share s, and reaches two thirds of it on day 30 (2/3 - s) / (1 - s): 10 days at 50/50 (4 under the old floor), 5 days for the 60 side of 60/40 (0 under the old floor). L4 measures this within the outage shortfall; the devnet found the young-window form of it first (attack scenario 6A, docs/bench-log.md: the old floor fell at 84 s of a 1,439-DAA window, the bound being 2F / (13R) for a window weight F and a side rate R, which at two thirds becomes F / (2R), 3.25x longer; re-measured on a full 1,800-DAA window at the 2/3 floor, "finality floor 2/3": the bound is W / (3R) = 200 s, the floor held for the 150-s split and fell at 205 s, and the fork it left was not undone by the heal). Rule v3 (Q5) tests the signers against the table frozen at the last certified checkpoint as well, which a side cannot fill with its own blocks: the bound moves from 30 (2/3 - s) / (1 - s) days to one full window, 30 days after the last certified checkpoint for every split under two thirds (sim/results_v2.md M2 and M3: never in 12 days at 50/50, 60/40 and 55/45, both sides at day 30.00 of a 31-day split). On the devnet scale the same bound is W / R of DAA time per side instead of W / (3R). 3.7 item 9 and the exchange guidance of 3.9 carry what remains.
The simulation ran with the cert reading of participation. The block reading of Q2 credits a superset of the same votes (every vote in a certificate is in a block, and votes carried outside certificates are added), so a key's participation under the block reading is never lower than under the cert reading. For a key that is silent (C) or gone (D) nothing changes, because it emits no votes. For a key whose votes arrive late (F1 below) the block reading keeps it in the denominator for longer, which raises the weight a lock needs. That direction is safe; its cost in lock latency and in the C and D stall figures is the re-run named in O-3.3, with the per-block vote bound as the parameter.
3.3.2 The eclipse case (ledger F2): closed by the floor
Decision of 3 October 2026, floor raised 4 October 2026. The presence window of Q1 is an eclipse vector on its own: a faction that keeps the big pools' votes from the rest of the network for two hours, without stopping their blocks, becomes the whole of active weight and locks alone. The answer is not a longer window or a silent-key rule; it is the second test of Q3, already in the rule. A lock needs two thirds of total weight whatever the presence window says, so an eclipsed or isolated faction can never lock unless it holds two thirds of all 30-day weight, and a faction that holds that much is the twenty-day public event of 3.1, not an eclipse.
The numbers (sim/results_v2.md, section F, seed 7, 1,000 keys, one pool holding 20% of total weight always online in its own region):
| Scenario | Denominator | Conflicting locks at 1 / 2 / 4 h | First conflict | Pool participation, minimum | Pool back to 1 after the eclipse ends |
|---|---|---|---|---|---|
| F1: pool receives every block and vote D hours late and votes correctly, late | any | 0 / 0 / 0 | never | 0.500 at 1 h, 0.000 at 2 and 4 h | 120 to 125 min |
| F2: a 34% attacker feeds the pool a private fork, signs both forks; eclipsed side holds 54% of weight, honest side 46% | active alone (cert reading) | 10 / 65 / 174 | 49 min | 0.787 / 0.562 / 0.108 | 115 / 85 / 20 min |
| F2, same | active + floor 0.80 (lock needs 53.3% of total) | 10 / 65 / 174 | 49 min | same as active alone | same |
| F2, same | active + floor 0.85 (lock needs 56.7% of total, the rule of 3 October) | 0 / 0 / 0 | never | 0.738 / 0.471 / 0.000 | 125 min |
| F2, same | active + floor 2/3 (lock needs 66.7% of total, rule Q3 since 4 October; L3, five seeds) | 0 / 0 / 0 | never | 0.725 to 0.738 / 0.442 to 0.471 / 0.000 | 120 to 125 min |
| F2, same | total alone | 0 / 0 / 0 | never | 0.738 / 0.471 / 0.000 | 125 min |
Why the floor and not the window: the eclipsed side in F2 holds 54% of total weight, which clears a 53.3% floor, fails a 56.7% one and fails two thirds by a wide margin. Under the active denominator alone the eclipsed view certifies the attacker's fork 49 minutes in, once its denominator has decayed below 54% / (2/3) = 81%; any floor above 54% binds before that point at every eclipse length tested, and the honest side saw 0 stalls during and after the heal in every row. At two thirds the same attacker would need a 33% pool beside its own 34% to bring the eclipsed side to the floor, which is two thirds of the network inside one eclipse, the 51% event of 3.1 and not an eclipse. Re-measured at the 2/3 floor in sim/results_v2.md L3 (five seeds, 1, 2 and 4 h): 0 conflicting locks, 0 locks on the eclipsed side. A pure delay (F1) never produced a conflicting lock under any denominator because 80% of weight kept signing; its only cost falls on the delayed pool, which leaves the denominator and returns to participation 1 about two hours after its view catches up.
What this does not prove. The model grants the attacker the eclipse for free and lets it mine its fork at its full rate for the pool alone while still signing the honest chain (sim/results_v2.md, "cannot tell us"). The attacker in F2 holds 34%, above the 1/3 safety bound of 3.7, which is the point: with the floor, even a faction above the bound cannot turn an eclipse into a conflicting lock. The devnet single-node eclipse of O-3.7 confirms the rule against a real network; it does not reopen the choice of rule.
3.4 Sortition
- S1. At launch every voter signs every checkpoint. A private VRF, keyed to the vote key and the checkpoint, selects 8 aggregators per checkpoint who publish certificates; anyone MAY aggregate and publish. Aggregator failure costs latency, not safety: the simulation's lock latency (median 2.5 s) assumes one aggregator per region and no failures, so it is a lower bound (
sim/results_v2.md, "cannot tell us"). - S2. If the number of voters above dust exceeds 8,192 at a checkpoint, the genesis rules switch, at that checkpoint and without a release, to Algorand-style binomial sub-user sortition with an expected 4,000 sub-users per checkpoint and both Q3 thresholds applied to expected sampled weight. The exact VRF construction, the binomial sampling procedure and the threshold on sampled weight are Open (O-3.5).
3.4.1 Participation grinding (ledger F3): closed by the block reading
Decision of 3 October 2026. Under a cert-only reading, whoever aggregates and whoever produces blocks could shape a rival's participation: drop its votes from the certificates you publish and carry, and after two hours its factor has fallen and your share of active weight has risen. Q2 closes this by computing participation from every vote seen in blocks over the presence window, never only from the votes an aggregator chose to certify. Aggregators choose what goes into a certificate; they choose nothing about participation.
Why an aggregator or a block producer cannot push a key's participation below the honest level:
- A vote is credited if it appears in any block in the past of C_i, blue or red, as a vote or inside a certificate. Certificates are one carrier among many, so the aggregator's bitmap selects nothing. An aggregator that drops a vote from its certificate changes which certificate locks (Q3 still has to be met by the votes it kept), not whether the vote counts for presence.
- A single block producer controls one block's payload. To keep k's vote for index j out of the past of C_i, every producer of every block that ends up in the past of C_i, over the about 240 indices between j and i, has to omit it, and the rule of Q2 makes every honest producer carry it. Under GHOSTDAG the past of C_i includes red blocks and every block merged within the 3,600-s bound, so an honest block that carries the vote is in the past of C_i within an hour of being mined.
- k is a voter only if it holds weight, which means it mined at least 100 blue blocks in the window. k carries its own votes in its own blocks, so suppressing k's participation means keeping k's own blocks out of the DAG for the whole presence window. That is excluding a miner from the chain for two hours, which is the eclipse of 3.3.2, where the floor already stops a lock, or a majority attack of 3.1, which the rule never claimed to survive.
- Nobody can raise participation falsely, because a vote is a BLS signature by k. Nobody can be made to vote twice at one index without producing equivocation evidence (3.6).
The honest level is therefore the number of indices at which k actually voted and its vote reached any honest producer within the window. A producer that receives votes and omits them lowers nothing while one honest block carries them; it only spends its own block space on less. The per-block vote bound, the window the carriage rule covers, and the lock latency and C and D stall figures under the block reading are the parameter re-run of O-3.3.
3.5 Fork choice
- F1. Candidate tips are tips whose selected chain passes through the highest certified checkpoint the node holds and every lower certified checkpoint.
- F2. Among candidates, GHOSTDAG selects by accumulated blue work under Kaspa's merge-depth bound of 3,600 DAA s (section 2.1). A certified checkpoint removes other tips from candidacy; it does not change how blue work is computed.
- F3. The pruning point never advances past the latest certified checkpoint.
virtual_finality_pointreturns the latest certified checkpoint when it is newer than the depth-based finality point (fork map e2). - F4. There is no hidden-block penalty in consensus. It was removed in review round 2 because it breaks DAG determinism and amplifies eclipse attacks. First-seen MAY break ties in a node's own block template only.
- F5. A node started with a configured trusted certificate follows it. A node started cold selects the DAG with the most accumulated blue work, then follows certificates found in it. A private DAG that out-works the public one over the window is a public 51% event lasting weeks.
Certificate-driven reorg (rule of 5 October 2026, night; ledger C4; design document Finality v2, Fork choice items 1 to 4). A node that holds a valid certificate for a checkpoint block that is not on its selected chain MUST move its virtual to the heaviest tip through that block. Valid means: the block is index i's checkpoint on its own chain (C1), it lies on the chain through every lock the node holds, the certificate verifies against the canonical voter list at that block (C3), and its signers meet Q3 and, under rule v3, Q5 there, every input a function of the block's own past. The node records the lock at i on that block, replaces its own record there, and determines its unlocked records again on the new chain (C1 re-determination). Merge depth does not bound this move. Finality outranks merge depth by design (item 2 above: a certified checkpoint removes other tips from candidacy, blue work decides only among candidates), and the certified chain's blocks are valid under their own merge-depth roots. The depth-based finality point does bound it, as F1 already implies: a certified block that is not in the future of the node's depth-based finality point is beyond what any rule can follow (section 2's pruning safety) and needs the operator's trusted certificate (F5). A certificate for a chain that misses a lock the node holds, at any index, is a conflict under 3.11.4: the lock stands and the pair is reported. While a node holds locks, its own determination at a higher index locks only on the chain through them. Before this rule the node held such a certificate pending a reorg that GHOSTDAG alone never produced, and a 96-s honest partition with no attacker ended in a permanent finality fork (bench-log "FUD ledger sweep round 6", C4; the fix and its measurement under "the C4 fix", 5 October 2026 night).
What a node does when it holds two valid certificates at one index after a partition heals is not modelled and not defined (sim/results_v2.md, "cannot tell us"; O-3.6). C4 says it publishes the pair. The proposal for gate 3: both certificates are evidence against every key that signed both; the node re-evaluates both against Q3 with those keys' weight struck, and if exactly one still locks it follows that one; if neither or both still lock, F2 decides among the two checkpoint blocks' descendants and the index is treated as uncertified.
3.6 Equivocation evidence
Two votes by one key for different checkpoint blocks at one index are equivocation. The evidence (the two votes) is a transaction that any block MAY include. On inclusion: the key's weight is zero for the rest of the current window and its blocks earn no weight for the next 2,592,000 DAA s. There is no coin penalty. The ban is a function of the chain (rule of 4 October 2026, night, ledger F23): at checkpoint C the key is stripped exactly when some block in the past of C carries the evidence and daa(C) < daa(e) + 2,592,000, where e is the carrier of lowest DAA score in C's past (the evidence block). Evidence a node has seen but no block in C's past carries strips nothing at C, so a node that detected the equivocation itself, from two votes over RPC or gossip, puts the evidence in its next block and waits for the chain. Every node with C's past computes the same voter list at C, whenever and however it first saw the evidence; before this rule a node stamped its own detection time and honest nodes refused each other's certificates for the length of the discrepancy. In the simulation, evidence is detected only at the heal and the penalty is forward-looking only; the model does not revoke the conflicting certificates (sim/results_v2.md, "cannot tell us"), which is why 3.5's post-heal proposal strikes the equivocators' weight retroactively for the re-evaluation.
3.7 Residual risks, stated
- Safety holds with under one third of window weight under hostile keys, in every scenario tested, including partitions of any length over which the weight tables agree: two certificates at one index need two thirds of total weight each, 4/3 in all, so at least one third of the weight signed both and that weight is equivocating (3.11.2). The bound does not depend on the presence window, on synchrony or on how long a partition lasts. Reaching a third takes ten days of 100% hashrate or twenty days of 51%, in public. At a third and beyond, two locks can coexist under a partition (H: a 34% equivocator across a 50/50 split gives each side 67% and both lock at minute 0; 33% gives 66.5% and neither locks) and equivocation costs history, not coins.
- Liveness pauses whenever less than two thirds of 30-day weight is connected and signing (Q3). With the model's 2.2% of honest weight in outage at any moment, the pause begins at about 32% silent in the simulation and is total from 34% (
sim/results_v2.mdL1); a set that keeps mining can hold the pause for as long as it stays silent. A set that stops mining AND signing at once ages out of the sliding table over 30 (1 - 1/(3x)) days for a share x (1.4 days at 35%, 10 days at 50%, L2 and D), but under rule v3 (Q5) it stays in the frozen table until that table expires, so a sudden departure of a third or more pauses finality for 30 days after the last certified checkpoint (M4: 35% from 1.7 to 30.0 days, 50% from 10.1 to 30.0). A gradual departure costs nothing extra, because every certified checkpoint re-freezes the table and keys that leave while locks continue age out of it as they age out of the sliding one. That is the price of item 9's bound moving from 10 days to 30; the project lead asked for the pause over the fork on 4 October 2026 (ledger F21). During a pause the chain continues on proof of work: blocks, GHOSTDAG ordering and execution go on, every certified checkpoint stays binding, and the node reportsfinality_activefalse with the reasonpausedso that exchanges credit nothing until the next lock (3.9). The pause is the price of the one-third safety bound of item 1; the project lead took it on 4 October 2026 (O-3.15). - Pools hold their hashers' votes. Vote concentration equals pool concentration, as on Bitcoin, and is public. Stratum v2 job declaration changes transaction choice, not the vote key (ledger F10, G6).
- A 51% owner who drives half the honest miners away and holds for 30 days owns finality thereafter. Same as Bitcoin, with a month's warning.
- The delay function (section 4) is a new dependency. The evaluator ships in every node.
- The dust threshold excludes solo miners under 100 blocks a month from voting, not from rewards.
- New honest miners are under-weighted for the whole window: after an overnight doubling the new cohort holds t/60 of weight on day t and the old cohort can lock without a single new signature for 19 days (
sim/results_v2.mdG). A doubling and a 1x renter are the same event to the rule, by design. - The simulation has no DAG: a partition side's checkpoint block is "the block at blue score 30 i in that view" and conflict counts are index collisions, not reorg depths. Real GHOSTDAG merge under the 3,600-s bound, DAA lag (of the order of an hour, approximate), VRF aggregator noise, uptime (the 0.978 resting participation is a guess), regional silent sets and the cost of keys are all outside the model.
- The weight table is per view. A side of an honest partition sees only its own blocks after the split, so its share of its own 30-day table rises as
s + (1 - s) t / 30on day t for a pre-split share s, and it holds two thirds of its own table from day30 (2/3 - s) / (1 - s): day 10 at 50/50, day 5 for the 60 side of 60/40, day 7.8 for the 55 side of 55/45 (3.3.1, measured insim/results_v2.mdL4 and found first on the devnet by attack scenario 6A, where the old floor fell at 84 s of a young window). From that day the side locks alone and two sides can hold conflicting locks at the heal with no attacker. The heal does not undo it: the other side's blocks arrive and are merged red, which only raises each side's share of its own table (W2 counts blue blocks), each side certifies its own checkpoints, and F1 pins every node to the chain its certificates name, so the network heals and finality stays forked until an operator sets a trusted certificate (F5; 3.11.4). Measured on the devnet: a 50/50 split on a full 1,800-DAA window at 3 blocks/s held for 150 s and both sides locked alone at 205 and 215 s against a predicted W / (3R) = 200 s, leaving 23 locked indices in disagreement across three nodes with no equivocation (docs/bench-log.md, "finality floor 2/3", 6A long heal). Item 1's bound is about the weight each view counts; a partition that lasts a third of the window changes what the views count. Rule v3 (Q5, 4 October 2026 evening) adds the table frozen at the last certified checkpoint to the lock test, which a side cannot fill: under it neither side of a split under two thirds locks until a full window has passed without a certified checkpoint (day 30 after the last lock,sim/results_v2.mdM2 and M3; on the devnet scaleW / Rof a side's DAA time instead ofW / (3R)), the heal then resumes locking on one chain with 0 conflicting certificates, and a side at or above two thirds (the 4/2 split at 70/30) locks at once as before. A partition longer than a window still forks as described above. The exchange guidance of 3.9 therefore treats a pause combined with peer loss as proof of work, and 3.11.4 says what the node does with the pair.
3.8 The first month
W2 gives the chain no weight at genesis. From zero history the honest network holds 3.3% of a full window on day 1, 33.4% on day 10 and 100% on day 30; 905 of 1,000 keys are under dust on day 1 and all are above it by day 20 (sim/results_v2.md A). Ledger F1 shows the consequence: with a one-day honest head start an attacker producing 75% of blocks from day 2 crosses two thirds on day 9 of the chain's life, and the 30-day emission ramp lowers the prize without removing the attack.
Two rules are on the table:
| Rule | Status |
|---|---|
| C5 as written: no certificate in the first 3,600 DAA s | Designed (design document) |
| No certificate may form until the window holds 30 days of history: before DAA second 2,592,000 the chain runs plain GHOSTDAG under the merge-depth and finality-depth bounds, exchanges are told so, and the node flag of 3.9 is false | Proposed (ledger F1), Open (O-3.1). This specification recommends it: the first month has no weight to defend with, so a lock in that month is a lock by whoever showed up, and the finality depth of section 2.1 already bounds a reorg to 12 hours (ledger F15: the merge-depth bound limits which old blocks can be merged, not which chain the node follows) |
Gate 3 decides, with the launch-month simulation that does not yet exist. Either way the litepaper states the rule.
3.9 Exchange confirmation guidance
Designed. The node exposes finality_active (true when a certificate has formed within the last 240 indices and the first-month rule of 3.8 has passed) and last_certified (index, block hash, DAA score).
| Situation | Guidance |
|---|---|
finality_active and the deposit's block is in the past of last_certified |
Credit. Expected wait about 90 to 120 s after inclusion |
finality_active, deposit not yet covered |
Wait for the next certificate; do not count blocks |
finality_active false (first month, or a pause under 3.7 item 2: less than two thirds of 30-day weight connected and signing, reason paused) |
Treat the chain as proof of work. The reorg bound to rely on is the finality depth of section 2.1, 43,200 DAA s: the node follows any heavier selected chain forked above it (ledger F15, round 3). Merge depth, 3,600 DAA s, limits which old blocks can be merged and is not a reorg bound. Credit nothing until the deposit's block is at least 12 hours of past-median time below the selected tip; count median time, not DAA score, because DAA seconds run fast during a retarget lag (ledger M14). For amounts that matter apply the operator's own hashrate judgement, as for any young proof-of-work chain. Listings are not sought before launch in any case (ledger X8) |
| Two certificates at one index observed (C4 evidence) | Suspend credits until the node's view resolves under 3.5 |
A certified checkpoint overrides the heaviest chain, so fresh hashrate cannot reorganise past last_certified; two thirds of 30-day weight can, and 3.1 says what that costs. A pause is not an attack: it means less than two thirds of the weight is signing, which the node also shows as the participation of each key (Q2) and which an operator sees coming as keys drop out of the presence window. A pause together with a loss of peers is a partition; under 3.7 item 9 the side the node is on may come to lock alone after days, so a node that has been partitioned for more than a day should be treated as proof of work until it has rejoined and finality_active is true again.
3.10 Implementation notes (devnet v2, 3 October 2026)
Status of this section: Implemented in vendor/igneum-node (reading guide in docs/fork-divergence.md, "Finality v2"), tested on a private four-miner test network and as a follower of the live devnet (docs/bench-log.md, entry "igneum-node devnet v2"). Where the implementation departs from the rule above or fills a gap it leaves, the departure is listed here, not silently. Update of 4 October 2026 (branch fin-fixes, worktree vendor/igneum-node-fin-fixes, after the attack harness of tools/finality-attacks): the S1 draw is by weight (ledger F17) and the first-month rule of 3.8 is the min_daa parameter (ledger F1); the rows for C5, Q4, S1 and 3.9 below say what landed. Measured in docs/bench-log.md, entry "finality fixes F17 and F1" of 4 October 2026. Update of 4 October 2026 (evening, branch finality-fixes, worktree vendor/igneum-node-finality from the proving head 8c0cff15): rule v3 (Q4 fold, Q5 frozen table) behind the height switch finality_v3_activation_daa (default never on every network; the override file sets it, as difficulty_v2_activation_daa); the Q4 and Q5 rows say what landed, docs/bench-log.md "finality rule v3" what was measured, docs/plans/finality-v3-rollout-devnet.md how it reaches the devnet.
| Clause | Implementation | Departure or gap |
|---|---|---|
| W1 | vote_key_hash = BLAKE2b (domain IgneumVoteKeyHash) of the 48-byte compressed G1 key. The key is revealed with a proof of possession in the miner's coinbase extra data (IGNK plus 288 hex characters) and a node registers it only when the hash matches the header. A vote carries the public key too, so a key that votes is revealed by its vote |
The reveal is hex, not binary, because the template RPC carries extra data as a UTF-8 string. Mainnet should carry the reveal in a dedicated field or transaction |
| W2 | Blue blocks per key in (daa(C) - window, daa(C)], counted along C's selected chain through every chain block's mergeset blues, C included |
O(window) per checkpoint: fine at the devnet window of 7,200 DAA seconds, not at 2,592,000. Mainnet needs an incremental window kept per chain block |
| W3, W5 | Dust excludes a key from the voter list and from both denominators | Key succession (W5) is not implemented |
| C1 | Checkpoint i is the lowest selected-chain block with blue score at least 30 i (blue scores along the chain can skip values), determined when the sink's blue score reaches 30 i + d, d = 20 on devnet. Re-determination (branch fud-consensus, 4 October 2026 night, ledger F24): after every virtual change, every unlocked record whose block is no longer a chain ancestor of the sink is determined again on the new chain (on_virtual_changed, "re-determined" log line); the certificate held over the old block is dropped, the fold clock restarts, and the certificates kept pending over the new block (pending_certificates, at most 4 per index, indices up to 64 ahead of the next determination) are verified. A locked record is never revisited. Unit test reorg_past_an_unlocked_checkpoint_re_determines_it_and_verifies_the_pending_certificate (a 6-block side chain's certificate is pending with no conflict, the 15-block side chain overtakes, index 13 is re-determined and locks from it; a block with the wrong blue score is refused) and a_locked_checkpoint_pins_the_chain_and_a_certificate_against_it_conflicts (a side chain twice as long does not become the sink past a lock, the certificate against the lock is the one conflict) |
d = 20 is below the placeholder 60; the devnet reorg-depth distribution that sets d has not been recorded. Measured in docs/bench-log.md, "round-4 consensus items" (reorg run) |
| C2 | BLS signature over "igneum-vote-v1/" || chain_id || 0 || index || hash(C_i) under IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_; the chain id is the prefixed network name (igneum-devnet, igneum-devnet-7); votes are p2p message 70 and ride in the coinbase extra data of every block |
|
| C3 | Certificate = index, checkpoint, voter count, signer bitmap over the canonical voter list (keys above dust and not stripped, sorted by key hash), aggregate signature, aggregator key hash and sortition proof. Every template carries the certificates not yet in its past | The validity rule (a block whose selected chain misses a certified checkpoint is invalid) is NOT enforced; only fork choice (F1, F2) is |
| C4 | A certificate at an index for a block other than the one LOCKED there is kept and logged as CONFLICTING (conflicting_certificates), as is one whose block is not on the chain through the node's nearest locks at any index; at an unlocked index over a block this node holds it goes through the certificate-driven reorg (ingest_off_chain, 5 October 2026 night, ledger C4: verified against voters_at of that block, Q3 and Q5 by quorum_at from the block's own past, then LOCKED there, "LOCKED by certificate" log line, and the virtual processor is asked to resolve again, VirtualStateProcessingMessage::Resolve); over a block this node does not have it is held pending (F24 above) and tried again on every virtual change |
Not published as evidence. The rule is now fixed by 3.11 item 4 (the node keeps the certificate it verified first, never re-evaluates it, and reports the conflict); the node does not yet clear finality_active or expose finality_conflict when the pair appears. Until 4 October 2026 night a reorg deeper than d made the node log every certificate at the moved index as CONFLICTING (ledger F24) |
| C5, 3.8 | min_daa = weight_window (2,592,000 DAA s on mainnet, 7,200 on devnet; a unit test pins the equality). evaluate never locks, and ingest_certificate refuses a certificate from any source, while the checkpoint's DAA score is below min_daa; the node logs "finality not active, window filling, N of M" at every determination until the sink's DAA score reaches min_daa and reports the same through getFinalityCheckpoints (finality_reason, window_filled_daa, window_full_daa). Unit test processes::finality::tests::no_certificate_while_the_window_is_filling: one key holding 100% of the weight signs every checkpoint of a 150-block chain at a 60-DAA window; nothing certifies below DAA 60, a hand-built certificate at an early index is refused, every checkpoint from DAA 60 locks (fin-fixes, 4 October 2026) |
Implemented on 3.8's recommendation ahead of the launch-month simulation (O-3.1), which is still not run; gate 3 can lower the gate but not remove it without reopening ledger F1. The sink's DAA score the report compares is the one the virtual processor last handed the manager, so a restarted node reports the window as filling until its first virtual resolution |
| Q1, Q2 | Presence window 20 indices on devnet (240 mainnet). Block reading: participation counts the indices in [i - P, i - 1] at which a vote by the key is carried by any block, blue or red, in the past of C_i; a key whose first block in the window is younger than P x 30 DAA seconds counts the full window; every template carries up to 48 votes not already in its past, certificates and evidence first |
The per-block vote bound (48) is the devnet value of O-3.3. Participation is credited for any vote by the key at the index, whatever block it names; 3.11.1 requires the vote to name the checkpoint on the crediting chain, else a key can stay in the active denominator by voting for blocks of its own and never add to a certificate (O-3.19) |
| Q3 | Integer tests: 3 x signed x P >= 2 x active_num (active_num = sum of weight x participation count) and 3 x signed >= 2 x total (was 30 x signed >= 17 x total until 4 October 2026; FinalityParams::FLOOR_NUM / FLOOR_DEN = 2/3 on branch devnet-v4, with quorum_met, floor_met and locks as pure functions), both inclusive, both at C_i; bans known at evaluation time are applied to the voter list. Unit test floor_is_two_thirds_of_total_and_inclusive: 4 of 6 locks, 3 of 6 does not, 67 of 100 locks, 66 does not, the total test implies the active test for every participation. Measured on the three-node, six-voter network of docs/bench-log.md, "finality floor 2/3" (4 October 2026): no lock on either side of a 3/3 split, the 4 side of a 4/2 split locks at exactly two thirds |
|
| Q4 | No grace: a node that serves an eligible aggregator (S1) aggregates and gossips a certificate the moment the votes it has seen meet Q3, naming that aggregator; any other node waits until the sink is checkpoint_depth + aggregator_fallback DAA seconds past the checkpoint block (fallback 15 on both networks) and then aggregates with a zero aggregator (anyone MAY aggregate, the liveness fallback; fin-fixes, 4 October 2026). Rule v3 fold (branch finality-fixes, 4 October 2026 evening, behind finality_v3_activation_daa): once every voter has signed, or certificate_fold DAA seconds after the determination (FinalityParams::certificate_fold, 3 on devnet, 6 on mainnet, serde default 3 for older files), a node holding a certificate rebuilds it from every vote seen when heavier and gossips it (evaluate, "certificate ... folded"); ingest_certificate replaces a held certificate with a verified heavier one over the same block ("replaced by a heavier one"); templates carry the held one. Unit test fold_round_carries_late_votes_and_heavier_certificates_replace: 4 of 6 signers lock, a fifth vote is folded in 2 DAA seconds later, a lighter hand-built certificate does not replace it, a heavier one does |
The fold clock (determined_at) is node-local and not persisted: a restarted node folds from daa(C_i) + depth. Measured in docs/bench-log.md, "finality rule v3" |
| Q5 | Rule v3 (same branch and switch): frozen_table finds the highest locked index below i whose block is an ancestor of C_i (state.locks, reachability), takes voters_at of that block with the bans known now, and drops it when daa(C_i) >= daa(C_f) + weight_window; evaluate requires floor_met(frozen_signed, frozen.total) of the signers (and of a held certificate's signers) on top of Q3; a locked checkpoint is never downgraded. The LOCKED log line carries the frozen fraction and the frozen lock's index; a checkpoint that passes Q3 and fails Q5 logs "held by the frozen table" at debug. Unit test frozen_table_holds_a_side_without_the_other_keys_for_one_window: A at 60% and B at 40% lock together; B leaves; under v2 A locks alone within 30 DAA of B's last block, under v3 not before the last lock is one window old, and then it does |
The reference is the node's own highest lock on the chain (not the certificate carried in C_i's past), so a node that has not seen the newest certificate tests against the previous lock's table, which in a connected network differs by 30 s of blocks |
| S1 | VRF output = SHA-256 of the voter's BLS signature over "igneum-sortition-v1/" || chain_id || 0 || index || hash under the sortition tag (unique per key and message, so the signature is the proof); eligible when output x total_weight < 8 x weight x 2^64, drawn by weight (W6, ledger F17, fin-fixes 4 October 2026): the expected number of aggregators is 8 by weight whatever the key count, a key with no weight never draws, a key holding 1/8 of total weight or more always does (so with 8 or fewer equal voters everyone is eligible). Unit test sortition_is_by_weight_not_key_count: 200 dust keys draw nothing, 6 real keys draw sum min(1, 8 w / T), 16 equal keys draw 8.00, a key split into 10 or 200 parts draws what it drew whole |
Was output x voters < 8 x 2^64 (per key) until 4 October 2026; measured on the attack harness (docs/bench-log.md, "finality v2 attack harness" S2, then "finality fixes F17 and F1"). A key above 1/8 of total weight that splits itself gains seats (its single ticket was capped at 1); seats carry no reward and no power, since anyone MAY aggregate and Q3 is tested by weight |
| S2 | Not implemented (sub-user sortition above 8,192 voters) | |
| F1, F2 | In resolve_virtual the highest locked checkpoint that is in the future of the depth-based finality point and in the past of some body tip replaces the finality point: tips outside its future are not sink candidates. Since 5 October 2026 night (ledger C4) a lock can be a block off the node's selected chain, adopted from a certificate (ingest_off_chain), so this is the certificate-driven reorg: the sink search keeps only tips through it, whatever the blue work of the old chain and whatever the merge depth; evaluate locks the node's own determination only on the chain through its nearest locks (off_lock_chain) |
A lock that no body tip passes through is logged and ignored for that resolution; a lock not in the future of the depth-based finality point (a certified chain deeper than the finality depth) is logged once and cannot be followed (F5) |
| F3 | Not implemented: the pruning point and virtual_finality_point ignore locks |
Must land before any pruning network |
| F5 | Not implemented (trusted certificate at start) | |
| 3.6 | A second vote by one key at one index for another block is evidence, carried in blocks (EvidenceRecord: the two votes, the carriers with their DAA scores). Branch fud-consensus (4 October 2026 night, ledger F23): the ban at checkpoint C is computed from C's own past (bans_at): the key is stripped at C when a carrier lies in C's past and daa(C) < daa(lowest carrier) + ban (7,200 DAA seconds on devnet); detection over RPC or gossip only puts the evidence into this node's templates ("detected here: carried in this node's next block"). Evidence records are bounded (4,096, the oldest dropped; a record goes once its ban ended two windows below the sink or it was never carried within one ban of being seen; 16 carriers per record). Unit test ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list: three nodes on one chain, one takes the equivocating vote over RPC, two see it from the carrier block only; 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, and the third node verifies the first two's certificates at every locked index |
A carrier the reachability store no longer holds (pruned) counts as in the past of every checkpoint more than the merge depth younger than it. Until 4 October 2026 night the ban was stamped node-locally (ledger F23). Measured in docs/bench-log.md, "round-4 consensus items" (ban run) |
| 3.9 | getFinalityCheckpoints reports finality_active (the window is full and a lock exists within the last P indices), the latest lock, and since 4 October 2026 finality_reason (active, window filling, N of M with N the sink's DAA score capped at min_daa and M min_daa, or paused) with window_filled_daa and window_full_daa; the miner prints a FINALITY line whenever the reason changes |
last_certified as a DAA score is not reported; the conflict reason of 3.11 item 4 (two certificates at one index) is not reported (O-3.17), so a conflict still reads as active or paused |
| 3.11 item 6 (seed source) | The devnet keys the hourly program on the header's own daa_score (epoch_seed, docs/review/round-3-2026-10-03.md, R3.26), not on a checkpoint block |
The seed_source rule (section 4.3 with the uncertified fallback of 3.11 item 6) is not implemented; nothing on the devnet exercises a seed during a finality pause |
| 3.11 test table | The four-miner test network of the bench-log entry is the only measurement on a real DAG: 93 checkpoints, 0 conflicting certificates, one equivocation strip, one 12-checkpoint pause under the floor, one heal; since 5 October 2026 night the fast-time harness row for the certificate-driven reorg (3.11.7) | d = 20, presence 20 indices and a 7,200-s window are devnet values; the measured pause and heal are at those values, not the mainnet ones |
Node state is one persisted blob (DatabaseStorePrefixes::IgneumFinality), written at most once a second; votes received over RPC but not yet carried by a block are lost on restart, votes in blocks are not.
3.11 Guarantees
Status of this section: Designed, 3 October 2026. Every bound below is derived from Q3 by arithmetic shown in place, and every bound is tied in 3.11.7 to a simulation or a test-network measurement, or marked not yet run. Where this section and 3.3.1 or 3.7 differ, this section is the statement and O-3.16 carries the text fix. "The rule" means W1 to W6, C1 to C5, Q1 to Q4, S1, S2, F1 to F5 and 3.6. The form follows CometBFT's: safety and liveness are stated separately, each with the fraction of weight it assumes and the network condition it needs.
3.11.1 The model
- Voters and weight. As W1 to W6. At checkpoint index i,
T(i)is the total weight (every key above dust and not stripped) andA(i)the active weight (weight times participation, Q2), both computed atC_ifrom its past. Weight is a property of blocks, not of keys: a key holds exactly the blue blocks in the window that name it, and nothing else changes that number. - The adversary. Controls a set of keys holding together a fraction
aofT(i)at every index considered (ais the largest such fraction over the indices in question). Since weight is blocks, holdingaof total weight means those keys producedaof the blue blocks in the 30-day window, whether by the adversary's own hashrate or by purchase (3.11.5). The adversary MAY: sign two different blocks at one index (equivocate); withhold any vote; drop votes, certificates and evidence from the blocks it produces; aggregate as it likes (publish certificates over any subset of valid votes it holds, or none); buy or be given old keys with their history; delay and reorder its own messages; mine privately. It MAY NOT forge a BLS signature or produce blocks without the hashrate of section 1. Its share of active weight is not bounded byaalone: an honest view that lacks other honest keys' votes has a smallerA, which is why Q3 has two tests. - Honest voters. Follow the rule. They sign the checkpoint on their own selected chain at every index they determine (C1), sign exactly one block per index, carry every vote and certificate they receive (Q2, C3), aggregate what they receive (S1: anyone MAY aggregate), and never select or sign a chain that misses a certified checkpoint they hold (F1). Participation (Q2) is credited to key k at index j only for a vote that names
C_jas it lies on the selected chain ofC_i; a vote for any other block earns no participation on that chain (the implementation credits any vote at the index, O-3.19). - Network. Partial synchrony. After an unknown global stabilisation time (GST) every message between honest nodes arrives within a one-way bound
Delta; before GST messages between honest nodes may be delayed arbitrarily. A partition or an eclipse is a period before GST for the nodes involved. The simulation usedDelta = 2 sbetween regions (0.5 and 5 s swept) and the certificate grace of Q4 MUST be at least3 Delta. Honest hashrate is a majority of hashrate (a GHOSTDAG assumption, section 2); what finality adds is bounded in weight, not hashrate. - Key-set changes. Dust (W3): a key enters
Twhen its window count reaches 100 blue blocks and leaves when it falls below; a key below dust holds no vote. Succession (W5): weight moves once and the old key's later votes are invalid, so a successor pair cannot vote twice. Equivocation stripping (3.6): on inclusion of evidence the key's weight is zero for the rest of the window; stripping lowersTandAby the same amount and never raises either; two votes by one key at one index are evidence whoever holds the key. - Clock. Every interval is past-median time (Q1),
P = 7,200 sthe presence window,I = 30blue score the checkpoint interval,dthe determination depth (60 placeholder),Gthe grace.
3.11.2 Safety
S. As long as the adversary holds less than X of total weight, the honest nodes never hold two certificates at one index naming different blocks, and never hold a certificate whose checkpoint block is off the chain of a lower certified checkpoint. S does not depend on synchrony: it holds before and after GST.
The arithmetic. A certificate verified at C_i in a view v has signer weight at least q_v T where q_v = max(2/3 x A_v / T, 2/3) = 2/3 (Q3 with the floor at two thirds: since A_v <= T the floor always binds, so the binding fraction is two thirds in every view, whatever its presence window holds). Honest keys sign one block per index, so for two certificates at index i on different blocks, with signer weights s_1 and s_2, the weight that signed both is at least s_1 + s_2 - T >= 4T/3 - T = T/3, and that weight is adversary weight (equivocators). So a conflicting pair needs a >= 1/3, and X = 1/3.
What the floor removed. Under the 0.85 floor of 3 October 2026 the binding fraction fell with the view's active weight, q_v = max(2/3 x A_v / T, 17/30), so a view that had lost honest votes to a partition, an eclipse (3.3.2) or silence needed less than two thirds of total to lock, and X = 2 q_v - 1 fell from 1/3 in a connected network to 4/30 = 13.3% once a partition had outlasted the presence decay (41 minutes of median time under the block reading of Q2, 18 under the cert reading the simulator runs; measured in H: a 14% equivocator conflicted from minute 48, a 20% one from minute 12). With the floor at two thirds the active weight of a view no longer enters the lock threshold, so the bound has no time term: X = 1/3 of total weight against a connected network, against a partition of any length over which the weight tables agree, against an eclipse, and with the adversary reaching every side. Measured in H at the 2/3 floor (five seeds, 150 and 360 min, each side retargeting at once): 0 conflicting locks and no lock on either side of a 50/50 split with equivocators of 10%, 13%, 14%, 20%, 30% and 33% (each side holds 55% to 66.5% of total, under the floor); at 34% each side holds 67% and both lock from minute 0. The one-third line is 3.1's headline: ten days of 100% hashrate, twenty days of 51%, in public.
The trade the floor sets was linear, and it was decided. With the floor at f x 2/3 the partition bound is 4f/3 - 1 and the liveness bound of 3.11.3 is 1 - 2f/3 of weight silent: 13.3% and 43.3% at f = 0.85, 33.3% and 33.3% at f = 1. the project lead chose f = 1 on 4 October 2026 (O-3.15): one third on both sides, a pause whenever less than two thirds of the weight is signing, no scenario in which a faction under a third can split finality.
What remains is the weight table itself (3.7 item 9). The bound above is about the total weight T as each view computes it from its own past. In a partition each side's window fills with its own blocks only, so a side with pre-split share s holds s + (1 - s) t / 30 of its own table on day t and reaches two thirds of it on day 30 (2/3 - s) / (1 - s): 10 days at 50/50, 5 days for the 60 side of 60/40 (measured within the uptime shortfall in sim/results_v2.md L4; 4 days and 0 days under the old floor). From that day the side locks alone with a = 0, and two such sides hold conflicting certificates at the heal. That is the twenty-day event of 3.1 seen from inside a partition, with the clock started at the split: the floor at two thirds moved it from day 4 to day 10 and cannot remove it, because a view cannot count blocks it has never seen. Rule v3 (Q5) moves it to day 30 for every split under two thirds: the signers must also hold two thirds of the table frozen at the last certified checkpoint, which both sides share and neither can fill, and that table stands for one window. S under v3: with a < 1/3 no two honest views hold conflicting certificates across any partition shorter than one weight window since the last certified checkpoint (sim/results_v2.md M2, M3, M5: 0 conflicts in 12-day splits, the first conflict at day 30.00 to 30.06 of a 31-day split, the 34% equivocator still conflicts from minute 14). Beyond a window the frozen table is empty and the paragraph above applies.
The second clause of S (chain of a lower certified checkpoint) follows from the first with F1 and C3. Once an honest node holds a certificate for C_i it never selects or signs a chain that misses C_i, and after GST every honest node holds every certificate within one block interval plus Delta (C3 carriage and gossip). A certificate at j > i off C_i's chain therefore needs q T of weight that lacks C_i's certificate, which before GST is a side of a partition, and the first clause already bounds any lock that side forms; after GST only the adversary lacks it, and a < q. The residual is honest votes for C_i in flight across a partition boundary in the Delta before the split, which strengthen C_i's certificate and nothing else.
At and above X. Two valid certificates can exist at one index, each held by honest nodes. The rule does not resolve the pair (3.11.4) and does not promise to; equivocation evidence strips the keys that signed both for 30 days (3.6), which lowers the adversary's weight but does not undo the pair. At a >= 2/3 of total the adversary certifies any chain it likes from then on, which takes twenty days of 100% hashrate (3.1) and is a public event; it still cannot make an honest node abandon a certificate it holds (3.11.4).
3.11.3 Liveness
L. After GST, if honest voters holding at least Y = 2/3 of total weight are mutually connected within Delta and signing, a new checkpoint certifies within T of the moment that condition holds, whatever the adversary does within the model, where
T = I + d + G + Delta = 107 s at I = 30 s, d = 60 s, G = 15 s, Delta = 2 s.
The arithmetic. The floor needs Y >= 2/3 of total, which no behaviour of the rest can raise or lower (silence leaves T unchanged; equivocation lowers it). The active test needs Y >= 2/3 x A / T, which Y >= 2/3 satisfies at once because A <= T; the presence decay of Q2 no longer enters the bound (under the 0.85 floor it added a term D(Y) of up to 41 minutes for 17/30 <= Y < 2/3; O-3.18 is narrowed accordingly). I + d is the wait for the next checkpoint to be determined (one interval plus the determination depth), G + Delta the vote round trip and the grace of Q4. Below Y = 2/3 there is no bound: finality pauses.
Honest connected and signing weight Y |
T |
|---|---|
| 2/3 or more | 107 s (simulated lock latency after the checkpoint block: median 2.5 s, p99 4.6 s, A; the test network: median 1.0 s) |
| under 2/3 | finality pauses: no certificate until Y reaches 2/3 again, by silent keys returning or absent keys' blocks ageing out of the window |
Why the adversary cannot block L within the model: withholding votes changes nothing above; equivocating strips its weight and lowers T; dropping votes from its own blocks delays a vote's entry into the DAG by one honest block, since Q2 needs one block in C_i's past to carry it and honest producers carry every vote they receive; aggregating dishonestly costs nothing because anyone MAY aggregate (S1) and every honest node aggregates the votes it holds; buying keys moves weight between holders and leaves Y's arithmetic as it is.
When finality pauses. Finality pauses whenever less than two thirds of the weight is connected and signing. In the model, whose honest keys are in outage 2.2% of the time, that is reached once about 32% of weight is silent (L1: 30% silent locks every checkpoint, 32% locks 88% of them, 33% locks 11% with a first gap of 49 minutes, 34% locks none for as long as it stays silent), and a key that keeps mining never ages out, so a 34% silent set holds the pause for as long as it stays silent (J and L1: 0 conflicts, the first lock 0 minutes after it returns). A set that stops mining ages out: with a share x gone and the survivors inheriting the block supply, the live share of total is 1 - x (30 - t) / 30 on day t and reaches two thirds on day 30 (1 - 1/(3x)): 1.4 days at 35%, 10 days at 50% (L2 and D's total column). Under rule v3 (Q5) a set of one third or more that leaves at once also leaves the frozen table only when that table expires, so the first lock after such a departure comes on day 30 whatever x (M4: 30.00 days at 35% and at 50%); L is therefore: after GST, if honest voters holding two thirds of total weight AND two thirds of the frozen table are connected and signing, a checkpoint certifies within T; a departure that outweighs the frozen margin pauses finality for one window, and the node reports it. The chain does not stop: blocks, GHOSTDAG ordering (F2 among the tips through the last certified checkpoints) and execution continue on proof of work, every certified checkpoint stays binding, and the node reports finality_active false with the reason paused (3.9: the exchange guidance for that state is the finality depth in median time). The honest name for this state is "finality temporarily unavailable", and it is the state the test network showed for 12 checkpoints with one voter at 39.6% of total weight (3.11.7) and the state the floor test network showed on both sides of a 3/3 split (bench-log, "finality floor 2/3"). The litepaper says so in its Finality section and in "What Igneum does not claim" (R3.18).
3.11.4 Recovery and what "irreversible" means
Recovery after a partition, a < X. By S at most one side certified during the partition. At the heal, certificates reach every honest node by C3 carriage and gossip within one block interval plus Delta; F1 removes from candidacy every tip whose chain misses them, so every honest node selects the certified side's chain; the other side's blocks since the split merge under the 3,600-s merge-depth bound where they can and are otherwise abandoned, and the transactions in them were never under a certificate (that side's nodes reported finality_active false, or their last_certified predates the split). The outcome is a deterministic function of the DAG and the certificates, so every honest node reaches the same chain. If neither side certified (a 50/50 honest split), F2 picks the heavier chain and finality resumes within T of the heal by L. The simulation checks, in every run of H and I, that every certificate any side held before the heal is in the merged view after it ("every pre-heal lock kept"), and the test network's heal locked 13 pending checkpoints within 30 s with no conflicting certificate (3.11.7).
No certified checkpoint is ever reversed. A node MUST NOT delete, downgrade or re-evaluate a certificate it has verified, and MUST NOT report as not final a block it has reported as final. When a node holds two valid certificates at one index (a >= X): it keeps following the certificate it verified first under F1, publishes the pair as evidence (C4), sets finality_active false with the reason conflict, and stops reporting new locks until an operator resolves the split with a configured trusted certificate (F5). The protocol does not pick a winner, because any automatic choice would withdraw a lock some honest node has reported. This is how Kaspa treats a finality conflict: a FinalityConflict notification to the operator, no rule that resolves it (vendor/rusty-kaspa/consensus/notify/src/notification.rs). This rule replaces the re-evaluation proposal of 3.5 (R3.17; O-3.17).
To a user. A block in the past of last_certified on a node with finality_active true will remain on the chain that node follows, every honest node holding the same certificate agrees, and no weight of hashrate can change that; only an adversary over X can produce a conflicting certificate, and even then no honest node withdraws the one it holds. Not covered by this section: that the block's body is available and was validated by the signers (a certificate is a statement about a header chain by voters who validated it; availability and pruning are F3 and section 2); that the block's execution is correct (section 7's proofs); the first month (3.8) and any period with finality_active false, where 3.9's proof-of-work guidance applies; and any state the model excludes (3.7 item 8).
3.11.5 Acquired old keys against fresh hashrate
Weight is the count of a key's blue blocks in the window (W2), and each block leaves the window 30 days after it was mined whoever holds the key. A key bought with b of total window weight therefore carries b on the day of purchase and b (1 - t/30) on day t, while the buyer's own hashrate r (as a share of the network) adds r t/30. The buyer's share is
share(t) = b (1 - t/30) + r t/30,
which moves monotonically from b to r and never exceeds max(b, r). Buying keys worth b is exactly the position of having mined b of the network's blocks over the previous 30 days, which is what the sellers did and what the price reflects; it is the same purchase as buying b of hashrate for the same period, delivered in advance. To hold the veto (1/3) for a day the buyer needs max(b, r) > 1/3; to lock alone it needs 2/3 bought or 2/3 of hashrate for 30 days (3.1). With r = 30%: keys worth 20% rise to 30% at day 30 and never reach 1/3; keys worth 40% hold the veto from day 0 and lose it on day 20, then decay to 30%. If the buyer withholds its votes it is scenario C's silent set, with the stall figures of 3.3.1 shrinking as the bought weight decays.
The equivocation strip applies to the key, so it applies to the buyer: one pair of votes at one index by the bought key, from either the buyer or a seller who kept a copy, strips the key for 30 days. A sale that leaves the seller a copy buys a key the seller can destroy at will; the clean transfer is W5 succession, which moves the weight once to the buyer's own key and makes the old key's later votes invalid. Measured in K (3.11.7).
3.11.6 Seeds during a pause
The epoch seed (4.3) and the era seed (4.4) are VDF outputs of a checkpoint block at least 1,200 (epoch) or 7,200 (era) DAA seconds before the boundary. If that block had to be certified, a pause longer than the lead would hand every following epoch the same stale checkpoint and the hourly program would stop changing, and a pause at launch under 3.8 would stop it for a month. Rule adopted from O-4.3, 3 October 2026: the seed checkpoint C(e) is the selected-chain block at the checkpoint blue score the lead rule names, on the header's own selected chain, certified or not. Every header names it by seed_source and is valid only if that block is on its own selected chain at the blue score of index i(C(e)) (4.3 step 4), so the choice is a function of the header's past and two nodes validating one header derive one program. Mining therefore never waits for a certificate: the program changes every hour through any pause, including the first month.
What a later certification does. If the certificate for index i(C(e)) names the block the headers named, nothing changes. If it names another block, every header that named the losing block lies on a chain that misses a certified checkpoint, and that chain is already discarded by F1 and C3; no header on the certified chain ever named the losing block, because seed_source must lie on the header's own selected chain. A certificate can never land on a block other than the one at blue score 30 i of the certified chain (C1), so a later certification confirms the seed the certified chain used or discards a branch the fork rule has already discarded; it never changes the program of any block on the certified chain. The lead of 1,200 DAA seconds plus d makes a reorg across the seed block a reorg of at least 20 minutes of the selected chain, which the finality depth bounds (3.9), not merge depth. Not yet exercised on the devnet (O-4.3, implementation pending).
3.11.7 Test table
Each guarantee, the scenario that tests it, and the measured result. Bench-log citations are to docs/bench-log.md, entry "igneum-node devnet v2" (3 October 2026), by its paragraph; sim/results_v2.md by section letter.
| Guarantee | Scenario | Measured |
|---|---|---|
| Weight equals blocks and tracks hashrate (3.11.1) | results A, 60 days; test network checkpoint 4 | corr(hash, weight) 1.00000, weight:hash 0.82 to 1.12 (A); weights 34 + 31 + 30 + 24 blocks for four miners, total 119 (bench-log "Key reveal") |
S, connected network, a < 1/3 |
results A (no attacker, 60 days); test network, four miners, 53 minutes | 0 conflicting locks in 172,883 checkpoints (A); 93 checkpoints, every one locked on all three nodes, 0 conflicting certificates, identical hashes and weights at every RPC sample (bench-log "Checkpoints and locks") |
S under an honest partition, a = 0 |
results E, floor rows, 50/50, 60/40, 67/33, 80/20, 33/33/34 for 360 min with retarget; results I, 40/40/20 | 0 conflicts in every split (E); 40/40/20 honest three-way split: 0 conflicts and 0 locks on any side for 150 and 360 min (finality paused on all three), first lock 0 min after the heal, five seeds (I) |
| S under a partition with an equivocator below 1/3 | results H at the 2/3 floor, 50/50 honest, attacker 10%, 13%, 14%, 20%, 30% and 33%, 150 and 360 min, five seeds; results I, 40/40 plus a 20% equivocator reaching both (sides 60/60) | 0 conflicting locks and no lock on either side at every attacker share up to 33% (each side 55.0% to 66.5% of total) for 150 and 360 min in every seed (H); 0 conflicts and no lock in the 60/60 case that gave 256 to 276 conflicts under the 0.85 floor (I); the 3/3 split of the three-node devnet: no lock on either side for the whole 150-s split (bench-log "finality floor 2/3", 6A) |
| S fails at and above 1/3 under a partition (the bound) | results H, attacker 34%; results I, 40/40 plus a 34% equivocator reaching both | 34% (each side 67.0%): 2 to 54 conflicts in 150 to 360 min, first at minute 2 to 77 against 0 predicted, the model's 2.2% outage shortfall holding the sides at the knife edge (H, I) |
| S under an eclipse | results F2 and L3, 34% attacker plus a 20% pool (54% side), 1, 2, 4 h, five seeds | 0 conflicting locks and 0 locks on the eclipsed side at every length in every seed (L3) |
| S under a long honest partition, each side counting only what it has seen (3.7 item 9) | results L4, 50/50, 60/40 and 55/45 for 12 days, three seeds, floor 2/3 against 0.85; devnet 6A on a young window | 50/50: both sides lock alone from day 10.1 to 10.3 (predicted 10.0; 4.1 under the old floor); 60/40: the 60 side from day 5.1 (predicted 5.0; at once under the old floor), the 40 side never in 12 days (predicted 13.3); 55/45: day 7.9 and 12.0 (predicted 7.8 and 11.8); every pre-heal lock kept at the heal (L4); the old floor fell at 84 s of a 1,439-DAA devnet window (bench-log "finality v2 attack harness", S6A); at the 2/3 floor a 50/50 split on a full 1,800-DAA window at 3 blocks/s held for 150 s and both sides locked alone at 205 and 215 s (predicted 200), after which 26 conflicting certificates and 23 disagreeing locked indices stood across three healed nodes with no equivocation (bench-log "finality floor 2/3", 6A long heal) |
L at Y >= 2/3: T = 107 s |
results A lock latency; test network steady state; devnet 6B, the 4 side of a 4/2 split at exactly two thirds | median 2.5 s, p99 4.6 s after the checkpoint block at Delta = 2 s (A); determination to lock median 0.80 s, p90 1.08 s, max 1.55 s (bench-log "Checkpoints and locks"); the 4 side locks at exactly 2/3 of total and of active, the comparison inclusive (bench-log "finality floor 2/3", 6B) |
| Pause below two thirds, chain continues | results L1, 25% to 45% silent for 1 and 6 h; results J, 34%, 40%, 45% for 1, 6, 24 h; test network phase B, one voter alone; devnet 6A, both sides of a 3/3 split | 25% and 30% silent lock every checkpoint (one seed at 30% stalls 40 of 720 in 6 h); 32% locks 54 to 100% of checkpoints (1 h) and 69 to 95% (6 h); 33% locks 0 to 11%, the first lock after 24 to 266 min when there is one; 34% and above lock nothing for the whole 1, 6 and 24 h, longest gap 60, 360 and 1,440 min, 0 conflicts (L1, J); 0 locks in 12 checkpoints with 39.6% of total and 72.3% of active, finality_active reporting the pause (bench-log "Partition test", phase B); no lock on either side of the 3/3 split, each holding one half (bench-log "finality floor 2/3", 6A) |
Resume after the pause within T |
results J, after the silent set resumes; test network phase C | first lock 0 min after the silent set resumes at every weight and length, 0 stalls in the 3 h after (J); checkpoints 73 to 85 locked within 30 s of the restart, 86 to 92 at the steady cadence (bench-log phase C) |
| Deterministic heal, no lock reversed | results H and I, every pre-heal certificate present after the heal; results E post-heal stalls; test network heal | every pre-heal certificate present after the heal in all 60 runs of H and 40 of I, 0 post-heal stalls (H, I); 0 post-heal stalls in every E run; no conflicting certificate and no stall on any node through the heal (bench-log phase C) |
| Equivocation strips the key, locks continue | test network, miner m4 with --equivocate from index 43; results E and F, strip at the heal |
stripped on every node at index 43, voter list 3, locks at 3 of 3 votes from index 44 (bench-log "Equivocation"); post-heal stalls 0 with the attacker stripped (E) |
| Weight ages out: churn | results L2 and D, 35% and 50% stop mining and signing, three seeds | first lock 1.7 days at 35% (analytic 1.4) with 1,322 to 1,518 intermittent stalls in the 3 days after; 10.1 to 10.3 days at 50% (analytic 10.0); 0 conflicts (L2, floor 2/3; D's total column agrees at 41 h and 10.1 days) |
| Acquired keys decay as the window moves (3.11.5) | results K, keys worth 20% and 40% bought, 30% hashrate, signing and silent, 30 days, five seeds | share follows b (1 - t/30) + 0.3 t/30 within 0.6 points at every sampled day in every seed; keys worth 20% rise to 30% on day 30 and never reach 1/3; keys worth 40% hold the veto from day 1 to day 19 or 20 (formula 20) and end at 30%; withholding its votes, the 40% buyer stalls 63,307 to 68,716 of 86,400 checkpoints in 30 days (the pause lasts until it has decayed below one third) and the 20% buyer 304 to 1,045; 0 conflicts (K, floor 2/3) |
| Signing stops while mining continues, 1, 6, 24 h | results J and L1 | 34% and above: every checkpoint stalled for the whole silence; 33%: 665 to 727 of 720 in 6 h; 32%: 35 to 221; 30%: 0 to 40; first lock after resume 0 min at every weight; 0 conflicts (J, L1) |
| Seeds during a pause (3.11.6) | devnet epoch boundary through a forced pause | not yet run (O-4.3 implementation) |
| A certificate over a chain the node is not on: the certificate-driven reorg (3.5) | fast-time harness tools/finality-attacks/c4.mjs, weight against work, 130-s split, 240-DAA window, rule v2 (the live devnet's) |
the work-majority node fetched the certified chain, locked 12, 13 and 14 by certificate within 2 s of the first block, re-determined 11, and all three nodes ended on the certified chain with 0 conflicting certificates and 0 disagreeing locks; the module-off control took the heavier chain (bench-log "the C4 fix", 5 October 2026 night); the same under rule v3 is unit-tested, the harness row with the certifying side locking during the split is still owed |
| Two certificates at one index: no lock withdrawn (3.11.4) | devnet with a forced double certificate | not yet run (O-3.17) |
T under the block reading (3.11.3) |
O-3.3 re-run | not yet run (O-3.18) |
| Participation credited only for the chain's checkpoint (3.11.1) | results C with an adversary voting for private blocks | not yet run (O-3.19) |
| The first month (3.8) | launch-month simulation | not yet run (O-3.1) |