| .. | ||
| lib | ||
| class-v3.mjs | ||
| class-v4-signal.mjs | ||
| class-v4.mjs | ||
| digest-compat.mjs | ||
| fork-gate-gate.mjs | ||
| fork-gate.mjs | ||
| key-succession.mjs | ||
| node-compat.mjs | ||
| override-60x.json | ||
| README.md | ||
| simnet.mjs | ||
Fast time: the devnet at 60x for test networks
override-60x.json is the Igneum devnet with every clock-like consensus parameter divided by 60 and every block
count unchanged. A test network on it reaches its first finality lock in about three minutes instead of two hours and
crosses an hourly program epoch every minute, so a scenario that took hours of wall time takes minutes. 4 October 2026.
Flags
Node (devnet-v4 line, vendor/igneum-node-v4, built in vendor/igneum-node/target-integration):
igneumd --devnet --devnet-suffix=950 --override-params-file=infra/fast-time/override-60x.json ...
The file is complete: every field OverrideParams accepts is present (consensus/core/src/config/params.rs), so a
reader sees the whole profile in one place. Merge it with skip_proof_of_work: true for a network without miners
(the harnesses do this), or lower genesis_bits for CPU miners (the devnet value 0x1d100000 is the GPU difficulty).
Harnesses: node tools/finality-attacks/run.mjs s3 --fast-time, node tools/harness/run.mjs s3 s4 --fast-time
(or IGNEUM_FAST_TIME=1). Both then take the node from vendor/igneum-node/target-integration/release because the
file carries the PoW schedule fields that only the devnet-v4 line knows; IGNEUMD=... overrides. The in-process
simulator takes the same file: igneum-harness-sim --override-params-file infra/fast-time/override-60x.json.
Proof script: node infra/fast-time/simnet.mjs (3 nodes on ports 29500 and up, igneum-devnet-950, data
/tmp/igneum-fast-time; records the first lock and the first program swap; see "Measured" below).
Class switch gate (Counter ASIC 2.0 rollout G4): node infra/fast-time/class-v3.mjs (3 nodes on ports 29600 and up,
igneum-devnet-960, data /tmp/igneum-fast-time-v3, CPU difficulty genesis_bits 0x1f010000, real CPU mining on
every node, program_class_v3_activation_daa a few epochs ahead; reports blocks on both sides of the boundary, the
program id and class before and after, rejected blocks, forks, and every node's switch line; see
docs/plans/counter-asic-2-node.md).
Class v4 switch gate (Counter ASIC 3.0 G4): node infra/fast-time/class-v4.mjs (the same shape on ports 29660 and up,
igneum-devnet-966, data /tmp/igneum-fast-time-v4, program_class_v3_activation_daa at 60 and
program_class_v4_activation_daa at 150 by default, so one run crosses v2, v3 and v4; --activation never is the
known-failed case, which must report FAIL with no v4 epoch; --metal <igneum-bench> puts a real Metal miner on node 0
for G4b; see docs/plans/counter-asic-3-node.md).
Miners: igneum-miner follows the epoch length and lead its node reports in every template (pow_epoch), no flag.
The dataset day is not in the template, so a real-hash miner on a fast-time network takes IGNEUM_POW_DAY_MS=1440000
in its environment (the node reads it from the file). The environment variables IGNEUM_POW_EPOCH_BLOCKS,
IGNEUM_POW_EPOCH_LEAD and IGNEUM_POW_DAY_MS remain the fallback for a node without a params file; the file wins.
What scales and what does not
Time parameters, divided by 60 (devnet value, 60x value):
| Parameter | Devnet | 60x | Note |
|---|---|---|---|
finality.weight_window (W2, DAA s) |
7,200 | 120 | the 2-hour weight window becomes 2 minutes |
finality.min_daa (C5, F1, DAA s) |
7,200 | 120 | equal to the window on every network, so the first lock waits for a full window |
finality.equivocation_ban (3.6, DAA s) |
7,200 | 120 | |
finality.aggregator_fallback (DAA s) |
15 | 1 | 15/60 rounds up to the floor of one second |
finality.presence_window (Q1, checkpoints) |
20 | 1 | a count of checkpoints, but it stands for 20 x 30 = 600 DAA s of presence; 10 s is under one checkpoint, so the floor of one |
pow_epoch_blocks (DAA s) |
3,600 | 60 | the hourly program epoch becomes a minute (new in the node, 4 Oct 2026: a consensus param carried by the override file; before, only an environment variable) |
pow_epoch_lead (DAA s) |
600 | 10 | the seed is knowable one lead before the boundary; the miner confirms it a quarter of the lead later (3 DAA s at 60x, 150 on the devnet) |
pow_day_ms (ms) |
86,400,000 | 1,440,000 | the dataset day of the 256 MiB cache becomes 24 minutes (new consensus param, same change) |
blockrate.merge_depth (DAA s) |
3,600 | 60 | Kaspa's merge-depth bound, one hour of DAA score |
blockrate.finality_depth (DAA s) |
43,200 | 720 | Kaspa's pruning-side finality, 12 hours |
blockrate.pruning_depth (DAA s) |
108,000 | 13,838 | 30 hours / 60 = 1,800 is under Kaspa's anticone finalisation bound (finality + 2 x merge + 4 x mergeset x k + 2k + 2 = 13,838 at k 18, mergeset 180), and Bps::pruning_depth takes the larger, so this does |
blockrate.coinbase_maturity (s) |
100 | 2 | 100 s / 60 rounds up |
deflationary_phase_daa_score |
0 | 0 | the devnet has no deflationary phase |
difficulty_v2_activation_daa |
never (18446744073709551615) |
never | a height, not a clock: difficulty rule v2 (4 Oct 2026, docs/analysis/difficulty-2026-10-04-oscillation.md) switches on at this DAA score; a test network sets it in its merged file (sim/difficulty/testnet_v2.py uses 900) |
proving_v0_activation_daa |
never | never | a height: proving v0 payouts (spec 7.7) switch on at this DAA score; tools/proving-v0/run.mjs sets 60 in its merged file |
finality_v3_activation_daa |
never | never | a height, not a clock: finality rule v3 (the frozen weight table of ledger F21 and the certificate fold of F22, 4 Oct 2026 evening) applies to checkpoints at or above this DAA score; tools/finality-attacks/v3.mjs sets 0 in its merged file |
pow_genesis_dataset_log2 |
28 | 28 | a size, not a clock: the dataset at genesis (2^28 words, 1 GiB); the cache growth rule (ca2-mixer) doubles it with the days since the genesis day |
proving_v1_activation_daa |
never | never | a height: proving v1 (the fork's proving-v1 branch, 5 Oct 2026) switches on at this DAA score |
proving_v1_segment_blocks, proving_v1_aggregator_share_bps |
8, 1,000 | 8, 1,000 | a block count and a share |
proving_v1_unproven_daa |
600 | 10 | a DAA clock (the unproven allowance), divided by 60; the proving agent confirms the value |
program_class_v3_activation_daa |
never | never | a height, not a clock: the lottery hash draws programs from class v3 (Counter ASIC 2.0, 5 Oct 2026) from the first EPOCH whose start is at or above this DAA score (rounded up to an epoch boundary: at 60 DAA per epoch, 150 means epoch 3 at DAA 180); infra/fast-time/class-v3.mjs sets it a few epochs ahead in its merged file |
program_class_v4_activation_daa |
never | never | a height, not a clock: the lottery hash draws programs from class v4 (Counter ASIC 3.0, 6 Oct 2026: class v3 plus the latency-shadow block) from the first EPOCH whose start is at or above this DAA score, rounded up like the v3 switch; infra/fast-time/class-v4.mjs sets it a few epochs ahead in its merged file |
program_class_v4_signal_window_daa |
86,400 | 120 | a DAA window (one day of blocks), divided by 60 and rounded to two epochs: the class v4 signal tally (PROPOSED, docs/plans/counter-asic-3-node.md section 6) over the blue blocks below each epoch's seed block; 0 = off; infra/fast-time/class-v4-signal.mjs is its gate |
proving_v1_fresh_rule_daa, exec_restart_number, exec_restart_trust_daa, exec_restart_hash |
never, never, never, "" | the same | heights and a hash, not clocks (the 0.3.12 and 0.3.13 switches); present so the fork's every-field test (fast_time_60x_file_is_the_devnet_at_60x) holds; added 6 Oct 2026 with the class v4 field |
Unchanged, and why:
| Parameter | Value | Why it stays |
|---|---|---|
blockrate.target_time_per_block |
1,000 ms | the unit: a 60x network still makes one block per second; 60 blocks per second is a different DAG (k, parents, mergeset) and not what is being tested |
blockrate.ghostdag_k, max_block_parents, mergeset_size_limit |
18, 10, 180 | DAG shape at 1 block/s |
finality.checkpoint_interval, checkpoint_depth |
30, 20 | blue-score counts: a checkpoint every 30 blocks, determined 20 blocks later |
finality.dust, aggregators |
5, 8 | a block count and a count of keys |
finality.certificate_fold |
3 | DAA seconds after a checkpoint's determination at which a node holding a certificate rebuilds it from every vote seen (rule v3, F22): a relay-latency allowance measured on the 12-node cloud devnet (the last of 12 votes issued median 1.45 s, p90 2.36 s after the first determination), not a clock of the protocol, so it is not divided; absent from a file, the node takes the devnet value |
difficulty_window_size, min_difficulty_window_size, difficulty_sample_rate |
661, 150, 4 | sample counts of Kaspa's sampled DAA (the reference lane of the dual rule); the controller needs its samples to estimate hash rate, and the 120-block LWMA lane, the 8-block warm-up, the 600-block reference start and the per-block clamps (igneum::difficulty) are block counts by design |
past_median_time_window_size, past_median_time_sample_rate, timestamp_deviation_tolerance |
27, 10, 132 | the past-median rule's window in samples; Igneum's own 10 s future and back bounds are constants of the rule |
genesis_bits |
0x1d100000 | the devnet's GPU difficulty; a CPU test network sets its own (0x1f010000 = 2^16 hashes per block) |
skip_proof_of_work |
false | the harnesses turn it on themselves |
mass, lane, script and payload limits, pruning_proof_m, max_block_level, crescendo_activation, storage_mass_parameter, pre_deflationary_phase_base_subsidy |
devnet | sizes and rule switches, not clocks |
Consequences to remember when reading a fast-time result: the merge depth (60 s) is now far under the difficulty
window (2,641 s), so a low-difficulty side chain older than a minute cannot merge, which the devnet tolerates for an
hour; the presence window of one checkpoint means "finality active" needs a lock within the last checkpoint; the
partition bound of spec 3.3.1 is W / (3R) = 13 s at 1 block/s per side (200 s on the devnet), so a split longer than
that locks on both sides as the arithmetic says (docs/bench-log.md, 4 Oct 2026, 6A long heal).
The node unit test fast_time_60x_file_is_the_devnet_at_60x (consensus/core/src/config/params.rs) reads this
file and checks every rule above against DEVNET_PARAMS; override_params_carry_the_pow_schedule and
pow_schedule_defaults_and_clamps check the new fields and that the devnet defaults are untouched.
Measured (4 October 2026, Apple M5 Max shared with four other agents and the live devnet, load 40 to 60)
node infra/fast-time/simnet.mjs --secs 240: three devnet-v4 nodes (target-integration/release/igneumd, built
from devnet-v4 a5ef8b07), three vmine voters sharing 1 block/s, one real-hash CPU miner thread on node 0.
| Event | Wall time from the first node's start | Chain position |
|---|---|---|
| next epoch seed reported in the template | 56.1 s | DAA 53 (boundary 60, lead 10, quarter-lead confirm 3) |
| first hourly program swap: template epoch index 0 to 1 | 65.1 s | DAA 60 |
| CPU miner's new program and 256 MiB cache ready for the new seed | 66.1 s (397 ms compile) | DAA 60 |
| first finality lock | 185.5 s | checkpoint 5, blue score 150, DAA 149 (checkpoint 4 sat at DAA 119, one under min_daa 120, so it could not certify) |
Sinks agreed on all three nodes at the end (DAA 171). On the devnet the same two events come at DAA 3,600 (one hour) and DAA 7,200 plus a checkpoint (two hours and change).
Harness scenarios, same binaries, before and after:
| Run | Devnet profile | 60x profile |
|---|---|---|
tools/finality-attacks s3 (dishonest aggregators, six voters at 6 blocks/s) |
32 min for the seven-scenario catalogue at SCALE 0.6 on the 3 Oct node (bench log 4 Oct 2026, s3 alone 180 s plus bring-up); on today's rule (min_daa = window) the window fills at DAA 7,200 = 20 min at 6 blocks/s, so s3 at full scale shows no lock inside its 300 s |
113 s wall, 16 locks per node, 0 conflicting certificates, lock hashes agree across nodes, median lock latency 1,018 ms: PASS |
tools/harness s3 (partition and heal in the in-process simulator, igneum-harness-sim of the devnet-v4 line) |
983 s wall for the four cuts (120, 600, 1,800 and 3,700 s virtual: 46, 151, 400 and 831 s wall, two at a time), all PASS | 43 s wall for the three cuts (10, 30 and 62 s virtual: 18, 20 and 26 s wall), all PASS, the 62-s cut beyond the 60-s merge depth converged with a 34-block reorg |
The 3 Oct catalogue run reported 3 to 47 s wall per s3 cut on the ordering-layer-only harness branch; the
devnet-v4 simulator carries the execution layer and costs about 70 ms per block on this loaded machine, hence the
983 s. The before and after above are the same binary on the same day.