diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index da8e18d10..4092d636b 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -152,7 +152,7 @@ Evidence: `docs/bench-log.md`, two-card table. ### F1. Finality is attackable for the first month "Vote weight is 30 days of blocks. At genesis there are zero days. For the first weeks weight equals hashrate share, so anyone with two thirds of a tiny launch hashrate locks checkpoints alone. You say 'no certificate in the first hour'. An hour." -Status: Rule implemented and measured; launch month simulated (5 October 2026 sweep). Rule: `min_daa = weight_window` (branch `fin-fixes`, 4 October 2026, merged into `devnet-v4`; 2,592,000 DAA s on mainnet, 7,200 on devnet, a unit test pins the equality); `evaluate` never locks and `ingest_certificate` refuses any certificate while the checkpoint's DAA score is under it; the node reports "window filling, N of M". Measured on the fork: harness s5 before the fix locked checkpoints 1 to 10 by one 20-s burster alone; after, 0 locks under `min_daa` and the first lock by 5 of 6 voters at 84.7% (`docs/bench-log.md`, "finality fixes F17 and F1"); the live devnet's first lock came at checkpoint 242, two hours after genesis, once the 7,200 window was full. Launch month under the gate (arithmetic, `docs/review/ledger-sweep-2026-10-05.md`): no certificate exists before day 30, and on day 30 an attacker producing share s of all blocks from day k holds s (31 - k) / 30 of the window, so the critic's 75% from day 2 holds 72.5% and would lock alone on day 30, 51% from day 1 holds 51% and cannot, and the share needed to lock alone on day 30 is 69% from day 2 and 95% from day 10; without the gate the old active-weight denominator crossed two thirds on day 9. The gate therefore turns the first month into the standing bound (an attacker over two thirds of all hashrate, which no proof-of-work rule resists) and nothing weaker. The v1 model's zero-history ramp (`sim/finality_sim.py --scenarios A`) is re-run in the sweep's batch. The litepaper statement is public text (testnet-prep). Was: Conceded, not yet stated in the litepaper. +Status: Rule implemented and measured; launch month simulated (5 October 2026 sweep). Rule: `min_daa = weight_window` (branch `fin-fixes`, 4 October 2026, merged into `devnet-v4`; 2,592,000 DAA s on mainnet, 7,200 on devnet, a unit test pins the equality); `evaluate` never locks and `ingest_certificate` refuses any certificate while the checkpoint's DAA score is under it; the node reports "window filling, N of M". Measured on the fork: harness s5 before the fix locked checkpoints 1 to 10 by one 20-s burster alone; after, 0 locks under `min_daa` and the first lock by 5 of 6 voters at 84.7% (`docs/bench-log.md`, "finality fixes F17 and F1"); the live devnet's first lock came at checkpoint 242, two hours after genesis, once the 7,200 window was full. Launch month under the gate (arithmetic, `docs/review/ledger-sweep-2026-10-05.md`): no certificate exists before day 30, and on day 30 an attacker producing share s of all blocks from day k holds s (31 - k) / 30 of the window, so the critic's 75% from day 2 holds 72.5% and would lock alone on day 30, 51% from day 1 holds 51% and cannot, and the share needed to lock alone on day 30 is 69% from day 2 and 95% from day 10; without the gate the old active-weight denominator crossed two thirds on day 9. The gate therefore turns the first month into the standing bound (an attacker over two thirds of all hashrate, which no proof-of-work rule resists) and nothing weaker. The v1 model's zero-history ramp (`sim/finality_sim.py --scenarios A`) is re-run in the sweep's batch. The litepaper statement is public text (testnet-prep). Was: Conceded, not yet stated in the litepaper. Zero-history ramp of the v1 model (`python3 sim/finality_sim.py --scenarios A --floors 1,100`, 5 October 2026): the network's total weight first reaches 99% of a full window on day 41 (floor 1) or day 35 (floor 100), so the gate's day 30 is the day the window is full by construction and the earliest a lock is possible. Answer: Correct, and this is the most dangerous entry in the ledger. With the active-weight denominator and a one-day honest head start, an attacker producing 75% of blocks from day 2 holds 0.75k/(1+k) of weight after k days and crosses two thirds on day 9 of the chain's life; an attacker arriving in hour two crosses it the same day. The window is empty, so the defence is absent. The 30-day emission ramp (10% to 100%) lowers the incentive without removing the attack. The design doc's answer, the one-hour merge-depth bound protecting the first month, bounds the damage of a reorg and does nothing about a bad lock. The rule under consideration: no certificate may form until the window has 30 days of history, so the chain runs plain GHOSTDAG under the one-hour merge-depth bound for its first month, exchanges are told to treat it so, and listings follow launch in any case. This goes to the gate 3 simulation and the litepaper will state it either way. @@ -1055,7 +1055,7 @@ Added by `docs/review/round-3-2026-10-03.md`, which holds the full argument for ### M14. A pulsed rental against the block-count DAA buys weight at a discount "Bring 50x the hashrate for two minutes once an hour. Kaspa's window keeps the 661 most recent samples, so you mine thousands of blocks at the old target before it moves, and when you leave the honest network crawls for hours at your difficulty. Weight is blocks over a window of blocks. You get a third of the window in a week for the price of a 1.6x average." -Status: Open, experiment scheduled as O-3.14 (3 October 2026). The weight half is written into the spec, see F14; the controller half is gate 2 (O-2.1). +Status: Answered with evidence for the controller half (5 October 2026 sweep); the finality run with the DAA inside `finality_v2.py` (O-3.14) is still owed (fud-fixes row 123). Chain model, `sim/difficulty/attacks/attacks.py --scenario pulse --rules 'igneum:ref_window=600+long_min=100000,kaspa' --seeds 3` (rule v2, the live rule since DAA 33,000, and Kaspa's DAA; 36 s, 5 October 2026): a 50x pulse for 10 min of every hour earns 3.7% of the always-on base's blocks per hash under rule v2 (weight per hash 0.262, worst seed 0.266) and 85.5% under Kaspa's rule (0.983); a single pulse earns 2.8% (0.130) and 56.8% (0.871). Under neither rule does a pulse earn more blocks per hash than steady mining, so the amplifier the critic describes is at most 1.0 in the chain model and the pulse is a loss; the cost it imposes on others is the crawl afterwards (rule v2: the base's blocks per hash down 36% in the hour after, worst gap 199 s, peak 185 blocks a minute; Kaspa's rule: peak 1,734 blocks a minute, 70 to 88% of blocks to the pulser for 81 to 89% of hashes). On the fork itself, `tools/finality-attacks` s5 (10x for 20 s of every 120 s under Kaspa's DAA, 4 October) measured weight share 35.3% against block share 35.3%, ratio 0.999. The hop profiles are in `sim/difficulty/results.md` (hop3, hop10, polluted). Was: Open, experiment scheduled as O-3.14 (3 October 2026). Answer: Correct in mechanism and unmeasured in size. `sim/results_v2.md` runs every scenario with a perfect retarget (its assumption table) and no finality run has a DAA model (O-3.9). Tonight's honest step on the devnet showed the lag: 5.67 blocks a second in a two-minute bucket after the first retarget, 2,248 blocks in eight minutes against 480 expected, and 1.5 blocks a second an hour later (`docs/review/round-3-2026-10-03.md`, "Tonight's devnet"). The review's estimate is that a pulse buys under two windows of blocks (about 5,000) and the chain crawls after each, so the amplifier over the formula is about 2x at the cost of a visible attack; the estimate is not a simulation. The same lag is the farm operator's hop profit (`sim/difficulty/sim.py` profiles `hop3`, `hop10`, `polluted`), for which no result is in the bench-log. Fix in two parts: the controller (gate 2, O-2.1, with the simulation results logged) and the weight rule (F14). @@ -1432,7 +1432,7 @@ Evidence: `site/litepaper.html` Governance; spec 10.6, 4.5; G7, E2. Experiment: ### X16. An evidence page with four labels "Every claim needs a status, a software version, the test that produced it, the result and whether anyone outside reproduced it. 'Implemented', 'tested by the team', 'reproduced externally' and 'reviewed independently' are four different things, and your bench-log uses one voice for all of them." -Status: Written (4 October 2026): `docs/evidence.md`, one row per public claim with five labels (tonight: designed 10, implemented 9, tested by the team 28, reproduced externally 4, reviewed independently 3). Publication with the benchmark release is still O-X.3. Was: Open, publication scheduled (O-X.3). +Status: Written (4 October 2026): `docs/evidence.md`, one row per public claim with five labels (tonight, counting the label column of the claims table: designed 9, implemented 8, tested by the team 26, reproduced externally 3, reviewed independently 2). Publication with the benchmark release is still O-X.3. Was: Open, publication scheduled (O-X.3). Answer: Correct. The bench-log records machine, command and number; the spec labels rules Designed, Measured, Target or Decided; neither says who ran a test or whether anyone else has. The evidence page ships with the benchmark release and carries one row per public claim: the claim, its status, the exact version (commit and release), the reproducible test (command or script), the result with its bench-log entry, and one of the four labels, with audits and reviews tied to the version they read. "Tested by the team" is the only label any row can carry tonight; G2's disclosure applies to the whole page. The ledger's own statuses map onto the labels and are not replaced by them. @@ -1802,7 +1802,7 @@ Evidence: the files above. ### E17. Unlogged inputs behind the economics, minor "The cap's 110 MH/s and its draw are not in the bench-log; the Mac's draw is not logged; the economy sim's one measured input is a 229 MH/s card against today's 124; mining-versus-pool flips from 4.9x for mining on today's devnet to 930x for proving at 10,000 cards and no document says it depends on fleet size; the app-share text omits '100,000-gas calls' and the open base unit; emission ran at up to 2x schedule; shard-scale prover cost is unmeasured on any GPU; the iGPU default off is right." -Status: Open, minor (4 October 2026). +Status: Open, minor; the simulator half re-run (5 October 2026 sweep). `sim/economy/sim.py` with the 5090 class at 124 MH/s (the devnet's measured rate) in place of 229, scenarios a and b, 2 seeds, 111 s: baseline profit USD 5.59 per 5090 card-day (6.37 at 229), 3090 2.73 (1.66), 3060 1.34 (0.78), small 0.74 (0.39); under the b shock 4.52 / 2.25 / 1.46 / 0.30; no backlog, every block proven within 60 s, hash trough 75% of pre-event under b (82% at 229), 5% of cards off (10%), oscillation flag in 1 of 2 seeds. The direction is as the review said: a slower flagship card shifts income toward the smaller classes and makes the fleet more sensitive to the price shock. The draw lines (`nvidia-smi` on both PCs, `powermetrics` on the Mac) need the machines (person). Was: Open, minor (4 October 2026). Answer: Correct on each point; `docs/review/round-4-2026-10-04.md` section 7 holds the arithmetic. Fix: one `nvidia-smi` draw line per setting with the rate beside it on both PCs; one `powermetrics` line on the Mac; the sim rerun at 124 MH/s with the comparison stated as a function of fleet size; "a million 100,000-gas calls a day" in the litepaper. Review ids R4.7.7 to R4.7.13.