From 8dae48b1c97ca98d16ba9bc16127416a2aeb8518 Mon Sep 17 00:00:00 2001 From: igneum-josh <337424239+igneum-josh@users.noreply.github.com> Date: Sun, 4 Oct 2026 01:23:42 +0000 Subject: [PATCH] Docs: devnet-v4 integration section (merge order, devnet v4 rules, compatibility, cut-over commands) and bench-log entry Co-Authored-By: Claude Fable 5.1 --- docs/bench-log.md | 23 +++++++++++ docs/fork-divergence.md | 84 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/docs/bench-log.md b/docs/bench-log.md index 81671601c..dc750ff73 100644 --- a/docs/bench-log.md +++ b/docs/bench-log.md @@ -500,3 +500,26 @@ Simulator, seeds 7 to 9 (`attacks.py --scenario ts --ts-rules tight`), forger at Base-profile regression, 3-seed means, 3 October against 4 October: record 102.8 against 91.0 s settled (first within 10% 70.3 against 68.5 s); up50 154.4 against 154.4; down50 782.3 against 762.2 (worst gap 78.3 against 73.9 s); epoch30 87.6 against 87.6; hop10 239.4 against 245.1; polluted 70.1 against 74.9 (seed 9: 78.9 against 92.0), peak 8.0x against 11.4x; steady std unchanged. All means within 10%; the two profiles with an idle gap move, because a gap over 60 T is paid back as three 20 T steps instead of one clamped step. Test network (3 `igneumd` nodes from the fix plus the `diff-attacks` template hook on a scratch branch, ports 28500 to 28521, appdir `/tmp/igneum-diff-fix`, genesis bits `0x1f010000`, honest 4-thread miner A on node 1 for 15 min, forger F 4 threads honest on node 2 for 5 min then on node 3 with the offset, two runs): earliest allowed stamp (offset -1e9 ms, floored by the rules; 986 blocks, 823 chain, 0 rejected): chain rate 0.82 blocks/s honest (60 to 300 s) at difficulty 102,226, 0.88 during forging (300 to 900 s) at 100,134, 0.83 in the last 300 s at 106,141, all-blocks rate 1.00 / 1.02 / 0.95, forger offsets -10 to -90 s (mean -23), hash A 0.110 MH/s, F 0.109. Latest allowed stamp (+9,000 ms; 1,028 blocks, 829 chain, 0 rejected): 0.78 honest at 102,382, 0.89 forging at 96,717, 0.89 last 300 s at 102,754, all-blocks 0.95 / 1.09 / 1.11, offsets +9 to +26 s, hash A 0.112, F 0.111. Flat within the CPU miners' noise; the 3 October rule on the same schedule fell to 0.24 blocks/s at 275,135 and 0.59 at 170,222 (bench-log entry above). Records in `/tmp/igneum-diff-fix/ts-past-igneum/record.csv` and `ts-future-igneum/record.csv` (not archived into the repo). Not done: the DAG effect of forged stamps on red and merged blocks (one chain in the simulator); the clock of a header whose parent arrived through a pruning proof starts from the raw stamp (one window of exposure after a sync, unmeasured); upstream's timestamp integration tests assume the 132 s bounds and were not re-run; the hopper's 0.7-point excess over Kaspa's rule stays open. + +## 4 October 2026, devnet-v4 integration: nine branches merged, 3-node test network on the merged node, Windows cross-build (release engineer) + +Machine: Apple M5 Max, shared (load 8 to 16, another agent's build and the live devnet running throughout), rustc stable, every build and test at nice 19 with 6 jobs into `vendor/igneum-node/target-integration`. Branch `devnet-v4` of `vendor/igneum-node`, head `dc749905`; merge order, conflicts and the cut-over commands in `docs/fork-divergence.md`, "Integration 4 Oct 2026". The hot swap was not in master (no `pow_epoch` in `2a00ff55`); it was captured from the uncommitted hotswap worktree as `a4224689` and merged first. Build times: first release build 3 min 37 s, the execution layer's crates 6 min more, the Windows cross-build 4 min 49 s from a warm dependency cache (`proto-cuda/windows-node/cross-build.sh vendor/igneum-node-v4 6`). +Tests: 628 passed, 0 failed, 24 ignored across the 21 touched crates (`--no-fail-fast`), then kaspa-p2p-flows 30 of 30 after the `estimated_header_size` fix (the header's `voteKeyHash` field was not counted since `815cd00f`). Three Kaspa UTXO-body tests are ignored with the reason (the execution layer retires UTXO transactions from bodies); two p2p-lib test modules were brought to the pair-shaped `BlockBody`. +Test network, 02:02:27 to 02:18:53 BST: 3 `igneumd` on `igneum-devnet-880` (gRPC 28800/28810/28820, p2p 28801/28811/28821, wRPC JSON 28802/28812/28822, eth RPC 28803/28813/28823; node 2 and 3 `--addpeer` node 1, node 3 also node 2), override file `genesis_bits` 0x1f010000 (2^16) and finality interval 30, depth 20, window 300 DAA, dust 5, presence 20, aggregators 8, ban 300, `min_daa` 300, fallback 15; `IGNEUM_POW_EPOCH_BLOCKS=300`, `IGNEUM_POW_EPOCH_LEAD=60` (a short epoch so the hourly swap crosses boundaries inside the run; the devnet values are 3,600 and 600). Miners m1, m2, m3 (`igneum-miner mine ... 3 960 --engine igneum-pow --payout-label mN --evm-address 0x7099...79C8`), 0.078 MH/s each (3 threads on the loaded machine), 375 / 342 / 338 blocks found, 0 rejected. + +| Measure | Value | +|---|---| +| Blocks accepted per node (PoW accepted lines) | 1,055 / 1,055 / 1,055, 0 rejected, 0 invalid | +| Block rate | 95 to 1,026 blocks between the 0-s and 900-s samples: 1.03 blocks/s; 1,055 in 960 s | +| Sink identical on all 3 nodes | 31 of 31 samples; peers 2 on every node at every sample; max tips 2 | +| Difficulty (dual-lane rule) | 56,268 at 20 s, 155,835 peak at 90 s, 110,533 at 900 s | +| Epoch boundaries (DAA 300, 600, 900) | first block of the new epoch accepted 2.23 / 0.50 / 1.47 s after the last of the old; inter-accept gap over the run median 0.59 s, p90 2.21 s, max 7.27 s | +| Caches built per node | 4 (genesis day plus the three epoch seeds); miners' CPU program and cache for a new seed ready in 191 to 212 ms | +| Finality | window filling to DAA 300, paused one sample, active from 270 s (DAA 363); first lock checkpoint 11 (blue 331) by 3 of 3 voters at 100%; 24 locks to checkpoint 34, same index on all 3 nodes at every sample; checkpoint 12 locked at 2 of 3 votes (68.1% of active and of total) | +| Lock latency (miner, proposed to locked over RPC) | median 1,011 / 1,012 / 1,010 ms, max 1,988 / 2,716 / 1,965 ms; 34 of 34 votes accepted per miner | +| EVM smoke (`tools/evm-smoke`, copy outside the repo, `IGNEUM_RPCS` on 28803/28813/28823) | 84 of 85 checks in 118 s: chain id 4463, miner balance 428.5 IGN at chain block 113 (the `IGNA` payout address), three accounts funded, 59 transfers executed in 10 chain blocks (max 17 per block, 33 to 91 us execution per block), deploy, call, receipts, logs, revert, developer share, state roots identical across nodes; the failing check is "duplicates landed in parallel blocks within 6 attempts" (identical copies to two nodes landed once in 2 of 6 attempts, the conflicting pair never both), which needs parallel blocks the PoW network did not produce in that 36 s (tips 1 at most samples) | +| `igneum-exec-diff` on the smoke export | segments 0 to 198, 59 transactions compared, 8 accounts, 0 mismatches | +| Harness scenario 5 (ports 28900+, copy of `tools/harness`) | 63 cases (46 RPC, 17 p2p): node up on every case, 0 cache builds (RSS flat, node log 1 build = the honest day), the M15 p2p cases disconnected by the strike guard: PASS | +| Harness scenario 2 (copy adapted to the merged rules; the repo copy probes 132 s and `pmt+1`) | live: floor-2 and floor-1 rejected, floor and floor+1 accepted where floor = max(pmt + 1, parent - 10 s); future flip between +10.00 and +10.02 s; sim: honest 0.908 b/s, ahead +0.2%, oscillate -0.7% over 1,200 virtual s: PASS | + +Binaries: `target-integration/release/{igneumd 40,463,680 B, igneum-miner 7,916,096 B, igneum-exec-diff, igneum-inject, igneum-p2p-probe, igneum-harness-sim}`; `target-integration/x86_64-pc-windows-gnu/release/{igneumd.exe 50,169,344 B, igneum-miner.exe 10,045,440 B}`; package `/tmp/igneum-integration/igneum-node-windows-v4.zip` (32,946,104 B). Not done: the GPU `prepare` hot-swap path on the merged miner (CPU miners only here), the cut-over itself, v4 builds for the Mac seed relay and igneum-seed-1, the repo harness's scenario 2 rules and its scenario 5 summary text (stale "built a cache on HEAD" wording while the per-case data says 0 builds). diff --git a/docs/fork-divergence.md b/docs/fork-divergence.md index 34ab5fa78..a2cd9584c 100644 --- a/docs/fork-divergence.md +++ b/docs/fork-divergence.md @@ -135,7 +135,7 @@ Implements `docs/design/execution-layer.md` D1 to D10 and section 8.2 on a 3-nod | Decision | v0 choice | Why it is open | |---|---|---| | 8 or 18 decimals | Kaspa's 8 (`SOMPI_PER_KASPA`), so one coin is 100,000,000 units and the cap is 4e17 units, inside u64 | The zkEVM side expects 18 decimals (wei). 18 decimals put the cap at 4e27, which does not fit u64, so the UTXO amount type, mass rules and every RPC amount would change. Decide with the execution engineer before the EVM bridge; a fixed 1e10 scaling at the bridge is the alternative. | -| Epoch seed | Devnet seed rule with a lead (hot swap, 3 Oct 2026): the seed of epoch `k` is the hash of the last selected-chain block whose DAA score is below `k x EPOCH - LEAD` (`EPOCH` 3,600, `LEAD` 600 DAA score, about 10 minutes at 1 block/s; `kaspa_consensus_core::igneum::{POW_EPOCH_BLOCKS, POW_EPOCH_LEAD, pow_epoch_seed_score}`); genesis for epoch 0. Every block template carries `pow_epoch` (`RpcPowEpochInfo`: epoch length and lead, the template's epoch index and seed, the boundary DAA score, the next epoch's seed once the sink has reached `boundary - LEAD`, the day index and the next one), so a miner sends `prepare` to its GPU worker one lead ahead and the worker swaps programs at the boundary with no pause and no process exit. Before 3 Oct 2026 evening: the last selected-chain block below the epoch's start score (no lead). `IGNEUM_POW_EPOCH_BLOCKS` and `IGNEUM_POW_EPOCH_LEAD` override both for private test networks (the lead is clamped below the epoch length); `IGNEUM_DEVNET_GENESIS_BITS` overrides the devnet genesis difficulty for such a network (the genesis hash moves, so it never peers with the real devnet). | This is the devnet stand-in for the 20-minute VDF lead of spec 04 (section 4.3: `C(e)` is the checkpoint at least 1,200 DAA s before the epoch, the VDF takes 600 s, so the program is knowable 10 minutes early). The design uses a 10-minute class-group VDF over a certified checkpoint (bench-log, proto-vdf); the devnet rule keeps the lead and drops the delay, so it is grindable in principle (a miner choosing which block sits at the seed score) and needs the VDF and checkpoints to close. The hash binding (`igneum-pow/src/bind.rs`) is unchanged. | +| Epoch seed | Devnet seed rule with a lead (hot swap, 3 Oct 2026): the seed of epoch `k` is the hash of the last selected-chain block whose DAA score is below `k x EPOCH - LEAD` (`EPOCH` 3,600, `LEAD` 600 DAA score, about 10 minutes at 1 block/s; `kaspa_consensus_core::igneum::{POW_EPOCH_BLOCKS, POW_EPOCH_LEAD, pow_epoch_seed_score}`); genesis for epoch 0. Every block template carries `pow_epoch` (`RpcPowEpochInfo`: epoch length and lead, the template's epoch index and seed, the boundary DAA score, the next epoch's seed once the sink is a quarter of the lead past `boundary - LEAD` (the selected chain still flips between sibling tips right at the seed score; the quarter leaves three quarters of the lead for the prepare), the day index and the next one), so a miner sends `prepare` to its GPU worker one lead ahead and the worker swaps programs at the boundary with no pause and no process exit. Before 3 Oct 2026 evening: the last selected-chain block below the epoch's start score (no lead). `IGNEUM_POW_EPOCH_BLOCKS` and `IGNEUM_POW_EPOCH_LEAD` override both for private test networks (the lead is clamped below the epoch length); `IGNEUM_DEVNET_GENESIS_BITS` overrides the devnet genesis difficulty for such a network (the genesis hash moves, so it never peers with the real devnet). | This is the devnet stand-in for the 20-minute VDF lead of spec 04 (section 4.3: `C(e)` is the checkpoint at least 1,200 DAA s before the epoch, the VDF takes 600 s, so the program is knowable 10 minutes early). The design uses a 10-minute class-group VDF over a certified checkpoint (bench-log, proto-vdf); the devnet rule keeps the lead and drops the delay, so it is grindable in principle (a miner choosing which block sits at the seed score) and needs the VDF and checkpoints to close. The hash binding (`igneum-pow/src/bind.rs`) is unchanged. | | Day seed for the 256 MiB cache | `"igneum-day/" \|\| day_le64` with `day = header.timestamp / 86,400,000` | Timestamps are miner-chosen inside the two timestamp rules, so a day boundary can be straddled by a few blocks; harmless for a cache seed. On branch `r3-fixes` the day seed is computed only after the future and past-median checks pass (M15 below), so an arbitrary past day no longer reaches the engine. Spec 01 O-1.10 proposes the first epoch seed of the day instead, which waits for the VDF schedule. | | Lane hash to 256-bit target | Lane hash (64 bits) in the top 64 bits, low 192 bits zero; `pow <= target` is exactly `lane <= target >> 192` | Closed for the binding (3 Oct 2026, `igneum-pow/src/bind.rs`: the init words commit to the nonce-zeroed header hash and the high nonce word). Still open: the block level for pruning proofs reads `calc_level_from_pow` on a value whose low 192 bits are zero (`leading_zeros(lane)` shifted), and pruning-proof validation itself still uses the stub. | | GPU workers and the hourly program | Hot swap (3 Oct 2026): the serve protocol has `prepare []`; the worker compiles the next program (and builds the next day's dataset) in the background, keeps at most two programs and two datasets resident, answers `prepared ...`, switches instantly on the first job with the prepared pair and drops the old pair after it. Metal compiles from the seed; OpenCL builds `/kernel_bound.cl` at runtime; CUDA runs nvcc to two cubins in the background and loads them through the driver API (`cudaGetDriverEntryPoint`). The miner (`igneum-miner --worker`) writes the pack for the prepared seeds under `--prepare-packs` and sends `prepare` as soon as the template reports the next seed; `--exit-on-seed-change` (exit 42, launcher rebuild) is the fallback for a worker whose ready line says `prepare 0`. A worker crash is restarted by the miner after a random 5 to 60 s. | Measured on the Metal worker across a short-epoch test network: see `docs/bench-log.md`, hot-swap entry. CUDA and OpenCL prepare paths are written and compile-checked (OpenCL ran on the M5 Max through Apple's OpenCL); the CUDA path has not run on NVIDIA hardware yet. | @@ -160,3 +160,85 @@ Implements `docs/design/execution-layer.md` D1 to D10 and section 8.2 on a 3-nod | 32 and after | 64 on | 0 | 0 | 0 | Split of 3,168,808,781: producer 2,535,047,025 (80%, plus the rounding remainder), proving pool 633,761,756 (20%). Total over the schedule: under the 4,000,000,000-coin cap by less than 100 coins (test `total_emission_stays_under_the_cap`). + +## Integration 4 Oct 2026: branch `devnet-v4` (release engineer) + +One branch, `devnet-v4` in `vendor/igneum-node` (worktree `vendor/igneum-node-v4`, head `dc749905`), merges every branch of 3 and 4 October in the order below. Every merge was built (`cargo build --release -p kaspad -p igneum-miner -p igneum-exec --features kaspad/igneum-pow`, `CARGO_TARGET_DIR=vendor/igneum-node/target-integration`, nice 19, 6 jobs) and its branch tests passed before the next merge. Commit messages carry the conflict notes; this section is the summary and the cut-over guide. Nothing of the live devnet (node 1 on 26610/26611, the observer peer on 26640/26641/28640, the seed relay on 26680) was touched; the test network ran on ports 28800 to 28923 under `/tmp/igneum-integration`. + +| # | Merged | Commit | Conflicts | Resolution | +|---|---|---|---|---| +| 0 | master | `2a00ff55` | | Finality v2 and the BLS miner. The hot swap was NOT in master: `git grep` finds no `pow_epoch`, `POW_EPOCH_LEAD` or `RpcPowEpochInfo` anywhere in `2a00ff55`, so the fin-fixes merge note above ("master already contains the hot-swap branch") was wrong. The hot swap lived only as the uncommitted working tree of `vendor/igneum-node-hotswap` (13 files, 832 insertions on top of the rename commit). It was captured as commit `a4224689` on branch `hotswap-wip` (a new worktree; the hotswap worktree was not touched). | +| 1 | hotswap-wip | `a4224689` | `igneum/miner/src/main.rs` (14 hunks) | The BLS `Identity` and the `Voter` are kept and threaded through the hot swap's pipelined worker: one BLS identity and one voter per `--identities` label (`