From ff6be6ccdb371774d6bff6c6095ea5dc61aba3b3 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:32:04 +0000 Subject: [PATCH] FUD sweep round 6, C4 measured: the overlay holds during a split and fails at the heal in the shipped node (a certificate over an off-chain block stays pending, GHOSTDAG never reorgs to it, the heavier side locks alone one window later); module-off control converges Co-Authored-By: Claude Fable 5.1 --- docs/bench-log.md | 5 +++++ docs/fud-ledger.md | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/bench-log.md b/docs/bench-log.md index 760a3064a..1b10132cd 100644 --- a/docs/bench-log.md +++ b/docs/bench-log.md @@ -1470,3 +1470,8 @@ What is measured: one BLS12-381 aggregate signature over 16 summed G1 keys plus | Run | Rule | New locks during the split A / B | First lock A / B (s) | Blue score A / B at the heal | Sinks after the heal | Final chain | Conflicting certificates | Disagreeing locked indices | |---|---|---|---|---|---|---|---|---| | control | v2 (the live devnet's rule), `min_daa` 120 | 4 / 3 | 133 / 9 | 335 / 296 | apart (n0 on its own) | none (a finality fork, F21) | 1 on n0 | 1 | +| off | no certificates (`min_daa` never) | 0 / 0 | none / none | 330 / 301 | one sink on all three | A's (the heavier) | 0 | 0; B's nodes re-determined 2 indices onto A's chain; n0 reconnected 36 s after the heal | +| on, split 150 s | v3 from checkpoint DAA 0 | 0 / 2 | none / 39 | 326 / 313 | apart | none | 3 on n0 | 2 (n0 reconnected 66 s after the heal, A's chain past the 120-DAA table by then) | +| on, split 90 s | v3 | 0 / 2 | none / 3 | 278 / 265 | apart | none | 3 on n0 | 2 (n0 reconnected 6 s after the heal, A's chain at about 58 DAA, inside the table) | + +Reading (the NEW finding, ledger C4). With the module off GHOSTDAG alone converges on the heavier chain and the losing side's records re-determine (F24 works when the chain moves). With the module on the overlay holds during the split (A, with 30% of the frozen table, locks nothing; B locks 7 and 8) and then fails at the heal in the shipped node: B's certificates for blocks off n0's chain are "kept pending until the chain decides (no lock at this index)", n0's chain never decides because GHOSTDAG keeps its heavier tip and nothing turns the certificate into a fork-choice constraint, and once n0's last lock (index 7, DAA 209) is one window old (DAA 329) the frozen table stops applying on A's chain ("no frozen table (no lock on this chain inside the window)"), A's two keys are 100% of A's own window (B's post-cut blocks are red there) and n0 locks 10, 11, 12 alone; B's certificates for 10 and 11 then log CONFLICTING on n0 (n0 log, 17:27:04 to 17:29:54 BST). A finality fork from a 96-s honest partition, no attacker, table intact at the heal; the 150-s run and the v2 control end the same way. The spec's fork choice ("GHOSTDAG among tips through all certified checkpoints", 3.5) is therefore implemented only for certificates over blocks already on the node's chain. Fix named in the ledger entry: verify an off-chain certificate against the table at its own block and let it constrain fork choice (a certificate-driven reorg), then re-determine. Raw: `scratchpad fud-a/c4-results-*.md`, node logs `c4-on90-tmp/`, `c4-v2-control-tmp/`. diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 93878b2cd..72bd564f2 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -574,12 +574,14 @@ Evidence: none in repository; `vendor/rusty-kaspa` to be cloned and cited. Fix: ### C4. vs Kaspa: a finality overlay changes GHOSTDAG's guarantees "GHOSTDAG's safety comes from blue work. A certificate that overrides blue work and a pruning point that never passes the latest lock are changes to the security model, not features on top." -Status: Open, experiment scheduled. Sweep (5 October 2026): the overlay has now run on a real DAG (cloud devnet, 4 October): with the module on, two partitions produced 0 conflicting locks, the 15.8% side locked nothing, the 84.2% side locked every interval, and the minority reorganised 423 to 496 blocks at the heal and adopted the majority's certificates within 15 s; the same day's F21 finding (a long honest partition locks alone from day 10 at 50/50) is the one real change to GHOSTDAG's guarantees found so far, and rule v3 answers it. The module-off comparison and the trace-driven adversary of O-3.8 are still owed. +Status: Measured on the live node line, and the overlay does NOT do what the spec says at a heal: a NEW SERIOUS FINDING (5 October 2026, evening sweep; owner: cryptographer and consensus engineer, decision owner the project lead). Was: Open, experiment scheduled. Sweep (5 October 2026): the overlay has now run on a real DAG (cloud devnet, 4 October): with the module on, two partitions produced 0 conflicting locks, the 15.8% side locked nothing, the 84.2% side locked every interval, and the minority reorganised 423 to 496 blocks at the heal and adopted the majority's certificates within 15 s; the same day's F21 finding (a long honest partition locks alone from day 10 at 50/50) is the one real change to GHOSTDAG's guarantees found so far, and rule v3 answers it. The module-off comparison and the trace-driven adversary of O-3.8 are still owed. Answer: True. Among candidate tips (those passing through every certified checkpoint) GHOSTDAG selects by blue work under the 3,600-second merge-depth bound; a certified checkpoint removes other tips from candidacy. That is a change, and its interaction with pruning, with red blocks in the attacker's weight and with latency is exactly what the gate 3 devnet measures. The module is separable so GHOSTDAG alone remains the fallback. Evidence: design doc Finality v2, Fork choice items 1 to 4; `sim/results.md` final section. +Sweep (5 October 2026, evening): the module-on against module-off comparison of O-3.8, run on the fast-time harness with the live node line (`tools/finality-attacks/c4.mjs`, fork 2b6d23ef, 3 nodes, 100-ms proxied links; raw tables in `docs/bench-log.md`, "FUD ledger sweep round 6", C4). The scenario separates weight from work: side B (n1, n2, four keys) holds 70% of the weight table and side A (n0, two keys) 30% when the link is cut; from the cut A mines at 0.6 blocks/s and B at 0.4, so A's chain is the heavier one by blue work while only B can certify under rule v3 (A holds 30% of the frozen table). Module off (`min_daa` never, so no certificate can form, fork choice bare GHOSTDAG): after a 150-s split the three nodes converged on A's heavier chain within 36 s of the heal, B's nodes re-determined their two split-time checkpoints onto it (F24), 0 conflicts. Module on (rule v3 from checkpoint DAA 0), 90-s split, n0 back on the link 6 s after the heal, A's chain at about 58 DAA of its own time, well inside the 120-DAA frozen table: during the split A locked nothing and B locked indices 7 and 8 on its own blocks, as designed; after the heal n0 did not switch. Its log: B's certificates for 8 and 9 arrived and were "kept pending until the chain decides (no lock at this index)" (the F24 path), n0's chain never changed because GHOSTDAG prefers its heavier tip and nothing in the node turns a verified certificate over an off-chain block into a fork-choice constraint, and one window after n0's last lock (index 7 at DAA 209, so from DAA 329) the frozen table no longer applied on A's chain ("no frozen table (no lock on this chain inside the window)"), A's two keys were 100% of A's own window table (B's post-cut blocks are red there and earn nothing), and n0 locked 10, 11 and 12 alone; B's certificates for 10 and 11 then logged CONFLICTING on n0, and B's nodes kept their certified chain. End state: sinks apart, 2 locked indices disagreeing across the nodes, a finality fork from a 96-s honest partition with no attacker and the frozen table intact at the heal; the same shape with a 150-s split (the table expired at the heal) and under rule v2 (the control: 1 conflict, sinks apart). So the answer to the critic is sharper than conceded: the overlay is specified to override blue work (spec 3.5, "GHOSTDAG among tips through all certified checkpoints") but the shipped node applies a certificate only to a block on its own chain, holds the rest pending a reorg that GHOSTDAG alone never produces, and after one window the heavier side certifies its own chain. Two honest views never reconcile. What closes it: a verified certificate over a block the node does not have on its selected chain must verify against the weight table at THAT block (its signers' weight there) and, when valid, constrain fork choice to tips through it, forcing the reorg (a certificate-driven reorg, bounded by the finality depth), with the node's own unlocked records re-determined on the new chain (F24); until then the exchange guidance of 3.9 (a node partitioned for more than a minute treats its locks as proof of work until it has seen the network's certificates agree with its own) is the only protection, and the 3.11.7 row for this case ("a certificate over a chain the node is not on") is missing. On the live devnet the window is 7,200 DAA (two hours) and the cliff is two hours after a side's last lock; a miner who joins with more hashrate than the weight table credits is the realistic work-majority side. The trace-driven adversary of O-3.8 is still owed. Spec rows: 3.5, 3.11.4, 3.11.7; node: `processes/finality.rs` (`ingest_certificate`'s pending branch, `fork_choice_lock`). Decision owner: the project lead (gate 3; a rule change to the node's fork choice). + ### C5. vs Ethereum: you compare inclusion to finality "'Included in about one second, against twelve on Ethereum.' Inclusion in a DAG is not confirmation. Ethereum's twelve seconds is a slot, its finality is about thirteen minutes, and you compare your two-minute lock to that as if a two-minute lock by a pool committee were the same thing."