igneum/sim/difficulty/README.md
igneum-labs 70bed1065a CI on every push: igneum-pow tests, census build, simulator quick modes, site build + link check, identity grep
GitHub Actions workflow (.github/workflows/ci.yml) on push and pull_request with three jobs on the free runners:
igneum-pow `cargo test --release` and the igneum-census build; the two Python simulators' --quick modes under a
120-second timeout; the site build, an internal link check of site/*.html (tools/ci/link-check.mjs) and a gh-free
identity grep of the public export list (tools/ci/identity-check.sh over tools/ci/forbidden-strings.txt: machine
names, LAN and overlay addresses, home paths, local time zones, the log-intake key pattern; never a key or a name).
The node fork is too big for CI today and the workflow says so.

sim/finality_v2.py --quick is now a genuine smoke run (one day or hour per scenario, one partition and one eclipse
setting): 149 s at nice 19 on a loaded Mac, was 745 s. sim/difficulty/sim.py gains --quick (up50 and warmup-hard,
kaspa and igneum controllers, 36 s). One bench-log time-zone label reworded so the identity grep passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 09:57:34 +00:00

56 lines
3.8 KiB
Markdown

# 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 --quick CI smoke run: up50 and warmup-hard, kaspa and igneum (about a minute)
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.