igneum/sim/difficulty
igneum-labs 2622fd2ccb Difficulty: timestamp attack fixed in spec 2.3, simulator, analysis addendum, ledger M23
Spec 2.3: rule 1 measures every chain step on a sanitised clock stored per header
(c(b) = max(c(p) + clamp(t(b) - c(p), -20 T, +20 T), t(b) - 60 T), step min(c(b) - c(p),
20 T)); rule 4 bounds the output to [2^128, MAX_DIFFICULTY_TARGET]; the timestamp rules
are Igneum's own, 10 s ahead of the clock and 10 s behind the selected parent beside the
unchanged past-median rule; new parameter rows, the bounds paragraph rewritten (the old
"next honest block cancels it" was the attack), the attack and test-network results added.

sim/difficulty/sim.py: class Igneum carries the same clock, lag bound and floor, so the
rule as simulated is the rule as coded (attacks.py's igneum-san is now identical to it).

docs/analysis/difficulty-2026-10-03.md section 11: the attack, the three parts, before and
after tables (simulator seeds 7 to 9, base-profile regression within 10% on the 3-seed
means, pool hopping unchanged, the two 15-minute 3-node forger runs), unit tests, limits.

docs/bench-log.md: the 4 October entry. docs/fud-ledger.md: M23, status Fixed.

Node side: vendor/igneum-node branch difficulty, commit 52eacad9.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 00:56:20 +00:00
..
attacks Difficulty under attack: hopping, pulsed rental, timestamp stretching, oscillation, epoch games, polluted window, flood; two FAILs with proposed diffs 2026-10-04 00:04:44 +00:00
devnet-2026-10-03.csv Difficulty: Igneum dual-lane rule measured against Kaspa, Monero and LWMA; spec 2.3, analysis, simulator, devnet and test-network records 2026-10-03 22:11:27 +00:00
README.md Difficulty: Igneum dual-lane rule measured against Kaspa, Monero and LWMA; spec 2.3, analysis, simulator, devnet and test-network records 2026-10-03 22:11:27 +00:00
results.md Difficulty: Igneum dual-lane rule measured against Kaspa, Monero and LWMA; spec 2.3, analysis, simulator, devnet and test-network records 2026-10-03 22:11:27 +00:00
sim.py Difficulty: timestamp attack fixed in spec 2.3, simulator, analysis addendum, ledger M23 2026-10-04 00:56:20 +00:00
testnet-igneum-2026-10-03.csv Difficulty: Igneum dual-lane rule measured against Kaspa, Monero and LWMA; spec 2.3, analysis, simulator, devnet and test-network records 2026-10-03 22:11:27 +00:00
testnet-kaspa-2026-10-03.csv Difficulty: Igneum dual-lane rule measured against Kaspa, Monero and LWMA; spec 2.3, analysis, simulator, devnet and test-network records 2026-10-03 22:11:27 +00:00

sim/difficulty

Difficulty controller simulator for Igneum (3 October 2026). Model, candidates, results and the devnet record behind docs/analysis/difficulty-2026-10-03.md and section 2.3 of docs/spec/02-consensus.md.

Files

File What
sim.py the simulator: block production from a hash-rate profile through six controllers, metrics as markdown
devnet-2026-10-03.csv every header of the overnight devnet (observer node wRPC, ws://127.0.0.1:28640): hash, DAA score, blue score, timestamp, bits, difficulty (2^255 / target, the node's convention), log2 target, epoch, chain flag, parent count, selected parent
results.md raw simulator output: synthetic set, timestamp-noise set, tuning sweeps, record replay, test-network comparison
testnet-igneum-2026-10-03.csv, testnet-kaspa-2026-10-03.csv every header of the two 3-node CPU test networks (Igneum rule, 20 min; Kaspa rule, 10 min), same columns

Model

One selected chain, DAA score = height, target 1 block per second, solve times exponential with mean (expected hashes per block) / (hash rate). A hash-rate profile is piecewise constant in time (miners joining and leaving) or keyed to the 3,600-block epoch (program cost steps). Timestamps are the true times in milliseconds; --ts-noise N adds uniform +-N ms miner clock jitter.

Metrics per step: first time the 121-block centred mean of the expected block rate is within 10% of target; "settled" = the first time it then stays within 10% for 100 blocks; overshoot past target on the far side; blocks spent above 2x and below 0.5x target rate; worst inter-block gap. Steady state: standard deviation of the expected rate ratio over a steady hour, blocks-per-minute coefficient of variation (Poisson alone gives 0.129 at 60 blocks per minute).

Controllers

Name Rule
kaspa KIP-4 sampled DAA exactly as the fork runs it: samples at every 4th block, 661 samples, average target of the window without its earliest block, times measured over expected, genesis bits held until 150 samples (600 blocks)
monero Monero next_difficulty: 720 blocks, timestamps sorted, 60 cut from each end, lag 15
lwma60, lwma120 Zawy LWMA-1 (2018 reference), linear weights, solvetimes in [-132 s, 6 T]
igneum the Igneum rule of spec 2.3 (two lanes, work-over-time estimators, epoch windows, 3% harden and 10% ease clamps)
igneum-literal the same with the brief's literal trigger (short-window rate off target by 25%), kept to show the chatter

Runs

python3 sim.py                                   synthetic set, every controller
python3 sim.py --ts-noise 500                    the same with +-500 ms timestamp jitter
python3 sim.py --tune                            parameter sweep for the Igneum rule
python3 sim.py --record devnet-2026-10-03.csv --events 2026-10-03T19:28:05+00:00,2026-10-03T19:42:40+00:00
                                                 exact replay check of Kaspa's rule on the record,
                                                 then the record as a hash-rate profile through every controller
python3 sim.py --dump up50:igneum                per-block trajectory (t ms, height, D, hash rate, rate ratio)

Requirements: Python 3 only (numpy not needed). The full synthetic set takes about two minutes.

Limits

No DAG (one chain, no parallel blocks, no reds), no network latency, no miner template refresh delay, honest timestamps unless --ts-noise. The exact-replay check of Kaspa's rule matches the record bit for bit while the devnet was a chain and diverges once it widened past one block per second, because a chain-only replay cannot see the merged blocks that the sampled window includes.