Simulator harness over sim/difficulty/sim.py with multi-miner attribution and in-rule timestamp forging, a 3-node CPU test network (ports 27700+), results and bench-log entry. Timestamp stretching inside Kaspa's rules drops the Igneum block rate 34 to 88% (the per-step clamp cancels forged and honest pairs to zero time); proposed 10 s timestamp bounds plus a sanitised running clock in the chain steps (+0.7% to +1.1% drift at 50% in the simulator). Block flood underflows the 192-bit work after 4,142 blocks; a 2^128 target floor proposed. Rule not changed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| attacks | ||
| devnet-2026-10-03.csv | ||
| README.md | ||
| results.md | ||
| sim.py | ||
| testnet-igneum-2026-10-03.csv | ||
| testnet-kaspa-2026-10-03.csv | ||
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.