igneum/docs/plans/counter-asic-3-gate/node-gates.md

16 KiB

Counter ASIC 3.0: the node-side gates for class v4 (mx8+sh256x27)

6 October 2026, worker "ca3-v4-node". The rows in the shape of docs/plans/counter-asic-2-rollout.md section 7. Trees: main ca3-v4-node a522d04 (igneum-pow, the workers, the harness, on ca3-coord 3213ee9), fork ca3-v4-node 5f7e0543 (on release-0.3.13-node bb43e9a8, the current release tip, which contains release-0.3.12-node). Builds: the Mac built igneumd and igneum-miner (target-ca3v4/release, --features kaspad/igneum-pow, warm from an APFS clone of the 0.3.13 target dir, under with-lock.sh build, nice 19, 4 jobs) and igneum-bench (the Metal worker, swiftc -O); the suites went to PC 2. The Mac's installed app was not touched (its miner stays paused); nothing was published; the live devnet was not touched. The Mac's load average during the runs: 5 to 12 (other agents' builds); the gates here count blocks, lines and ids, not rates, so the load does not move them.

# Gate Evidence required State
G4 the fast-time 3-node network mining across a v4 activation 0 rejected blocks, 0 forks, every node's first lines show the switch, blocks on both sides of the boundary; the gate fires on one finished and one failed case GREEN. Run 1 (15:54:32 to 15:59:21Z, node infra/fast-time/class-v4.mjs --secs 420 --activation 150 --v3-activation 60 --epochs-after 2 under with-lock.sh run; three nodes, one real CPU miner each with --engine igneum-pow, every node verifying the other two): 3 of 3 nodes print both switch lines (Program class v4 from the override file: active from epoch 3 (DAA score 150 rounded up to the epoch boundary at 180, epochs of 60 DAA) and the v3 line for epoch 1 at DAA 60); templates class 2 for epoch 0, class 3 for epochs 1 and 2, class 4 for epochs 3 to 5; the switch seen at DAA 180, 163.9 s wall; 181 blocks before and 128 after DAA 180 (309 in all, selected chain 177 / 127); program ids agree on all three miners (e0 v2 8f8806638d59850f, the same v2 id as 2.0's three runs; e1 v3 29ced0d031cc121b, e2 v3 341fd4076256cd7b, e3 v4 070ca0f94e7f8f88, e4 v4 b8cbe1ef7ab1d748, e5 v4 9321cbd9c54c0b83; no v2 or v3 id reappears under v4); rejected 0/0/0 on the miners and 0/0/0 on the nodes (103, 103, 102 accepted); one sink 4da9ac669effdfab on all three at 308/308/308 blocks, one tip each; digest 59a3eb5383bfbf23... on all three; program and cache ready on one core: v2 epoch 0 199 ms, the first v3 epoch 187 ms (its own day cache), the first v4 epoch 2 ms (the v3 day cache reused across the N5 boundary, no rebuild). Summary class-v4-20261006-1553Z-cpu.json. Run 2, the known-failed case (15:59:46 to 16:02:17Z, --activation never --v3-activation 60 --secs 150): every node prints Program class v4 from the override file: never; the harness reports SUMMARY FAIL: NO v4 epoch seen with five checks down (v4_switch_line_names_the_rounded_epoch, template_switched_at_the_first_v4_epoch, blocks_after_the_boundary, v3_and_v4_programs_seen, program_ids_differ_across_the_switch), exit 1; the v3 side of that run was clean (epochs 0 v2, 1 and 2 v3; 0 rejected; one sink 166/166/166). Summary class-v4-20261006-never-failed-case.json. Re-run on the program-id fix 7c22d0d (16:32:39 to 16:38:08Z, igneumd and igneum-miner rebuilt on the fixed igneum-pow, the harness with the id assertion; load average about 90 from other agents' builds, which moves the wall times, not the counts): PASS, every check true; 3 of 3 v4 and v3 switch lines; 181 / 125 blocks across DAA 180 (305, selected chain 168 / 120); rejected 0/0/0 and 0/0/0; one sink b7881306c83b1206 at 305/305/305; the PROGRAM ID rows, one per v4 epoch, the three miners' id against the CLI's same-seed, same-era class v4 and class v3 ids (`igneum-pow show --epoch-hex --program-class v3
G4b the Mac mines v4: a real Metal miner across a v4 boundary through the miner's --prepare-packs flow, and the app passes that flag to the Metal worker the prepare lines on both sides, the worker's prepared line for the v4 pack, found or accepted blocks on v4, no need or mismatch line, no exit 42 or 44; the app's miner_args pushes --prepare-packs for every worker GREEN. Run 3 (16:02:37 to 16:07:58Z, --metal proto-metal/igneum-bench --genesis-bits 0x1e010000 --secs 480 --activation 150 --v3-activation 60; node 0's miner is igneum-miner --worker igneum-bench --prepare-packs <dir> --exit-on-seed-change, the app's own shape; igneum-bench built from this tree at a522d04's main.swift, sha256 30c70754...; CPU miners on nodes 1 and 2): 5 PREPARE lines, each 5 to 6 DAA before its boundary, two class v3 (DAA 60, 120) and three class v4 with the pack directory and class=v4 era=<hex> (DAA 180, 240, 300); the worker's prepared lines for the three v4 packs: prepared ca4245b5... 430.2 program 193.9 dataset 236.2 race 0.0 variant base class v4 loads/hash 128 cache-fill 1.4 build 70.1 (the first, the v4 day built from the pack's memhard.metal on the GPU: 1.4 ms cache fill, 70.1 ms build), then 138.6 and 175.3 ms with the day resident (program compile alone, the 256-instruction shadow block in the kernel text; a v3 prepare was 61.7 ms); every swap swapped with no pause at DAA 60, 120, 180, 240, 300 (prepared 2 to 5 s earlier); 301 blocks accepted by the Metal miner, 123 after the switch, every one re-checked on the CPU: mismatched=0; need 0; no class or era mismatch line, no PACK OUT OF DATE, no prepare-failed, no exit 42 or 44 (0 such lines in the miner's log); the chain 182 / 122 blocks across DAA 180 (304), rejected 0/0/0 and 0/0/0, one sink 4e1aa3fbf1f4a54b on all three at 303/303/303, 3 of 3 v4 switch lines; program ids e3 v4 2bcecca6f867c3b5, e4 21b78e63fc0e9251, e5 3855570a5ba12fc9 agreed by the Metal miner and the CPU miners; the Metal miner's STATUS at 309 s: 18.58 MH/s wall, 293 accepted, 0 rejected (a rate under a load average of 5 to 12 with the CPU miners and other agents' builds beside it: an order of magnitude, not a measurement). The app side: app/igneum-app/src/engine.rs miner_args pushes --prepare-packs for every worker (line 1478, the 0.3.11 fix; unit test every_worker_gets_the_prepare_directory_in_the_platform_form), confirmed unchanged on ca3-coord 3213ee9. Summary class-v4-20261006-metal.json
G5 the PC-built Windows workers and the Mac workers from the same commit every sha256 listed; the two Windows workers carry the resource block; no packaging, no DMG, no manifest GREEN on the program-id fix 7c22d0d (packfile.h and main.swift moved, so the workers were rebuilt from it; the earlier pair from a522d04 is superseded): igneum-worker-cuda.exe 3bc8ad8f69ad97d6a9491a734ef16e3cf10b3884d442fb1e5a490c751ae578c5 (1,536,512 bytes), igneum-worker-opencl.exe 16ef015470d7a45c5af5488dcc68a29c5e95f94487eb05e26f1bf418e6dd511f (478,208), verify-exe.py: both carry the coin icon and the version block; the Mac worker igneum-bench f9ca4b075a9a9c25afd8feeccd1339fbb6bb4c3728ffeddab9f549cd3c1725a4 (665,128, the binary of the G4 re-run); the node and app binaries of job build-20261006-155958 stand (the fork did not change). The a522d04 row for the record: the build job builds the node and the app only (push-build-inputs.sh writes two build units, jobbuild.rs has no worker unit), so the Windows workers were cross-built on the Mac from the committed tree a522d04 with proto-cuda/nvrtc/build-windows.sh under the build lock (mingw-w64, static, windres resource block), as 0.3.11's G5 row was: igneum-worker-cuda.exe e563126ed1d8ab8f6803ead89acca5b6fcb03203e6b87b70e0aec85e8e1046e4 (1,536,512 bytes), igneum-worker-opencl.exe 7fce1249d443aaf73a29b7474c1ef4084f3529b5bec3a2dc6bb97e624561a5e8 (478,208), verify-exe.py: both carry the coin icon and the version block (a first build of the same sources before the commit gave 26400edf... and 438e608a...: mingw stamps a link time, so the pair is not bit-reproducible; the sizes match the 0.3.11 pair, 1,536,512 and 478,208, and the sha256s differ from 0.3.11's 2b3b8c92... and edc4a75d...: the generator-4 rule is in them). The Mac worker from the same tree: igneum-bench 30c70754097dafbc3144a0c0f192526a0638089e5dde49ce46abb7a948dceade (665,128 bytes, built 16:47Z from main.swift as committed in a522d04, the binary G4b mined with). The same build job's (build-20261006-155958) node and app outputs from fork 5f7e0543, every sha256 verified against the PC's lines on fetch: igneumd.exe 140be25e486fe1634500b6e66eedfaca9fa6561d652f3e219b5a7a2bc377e766 (51,752,448), igneum-miner.exe ceb1e691ad57f58d09d5a0ff4cb5658aea0604d23ceb90b6a847a2c36a0bf81c (11,118,080), igneum-app.exe bfa3b871f17b69fd0c0c01a6f9fcac8964efb54dc10fd25db13422ba8f96d51f (3,065,344, PE and resource block ok); Linux igneumd d44b735869b129401d68f18786b4a5f16c22d00b682bd41a8e5022a01f7d7527 (49,603,112), igneum-miner a7985111d4972f4b67a9409b831a8c7af746508ebb3b19fc927aaddcfa2e2413, igneum-app 222f30c00bb9725f3127452f3d52403b380e25abaf9fba5c925839574cf1dabc; kept under the job's --out dir with --no-place. No packaging, no DMG, no manifest
G6 the node change on a fork branch from the current release tip with suites green on PC 2, with the igneum-pow feature the build job id and its SUMMARY line; the v4 engine test named in the output GREEN. PC 2 job build-20261006-155958 (fork ca3-v4-node 5f7e0543, main a522d04; published 15:59:58Z after the clear file and under the mkdir lock, taken 15:58:50Z, released 16:08:06Z after the closing report; the installed app untouched, the prover left on), node tools/build-job.mjs run --target 1ccfe586 --node vendor/igneum-node-ca3v4 --node-tests "kaspa-consensus kaspa-consensus-core igneum-exec kaspa-pow igneum-miner kaspa-p2p-flows" --app-tests igneum-app --no-place: done exit 0 after 392 s: node ca3-v4-node 5f7e0543 app 0.3.11: every stage ok; 9 files uploaded (46 MB); 6 min of 40; the test stage 50 s, exit 0 on both units: kaspa-consensus 98 passed (3 ignored; ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list ... ok, so 2.0's flake did not recur and no re-run was needed), kaspa-consensus-core 109 + 7 (override_params_carry_the_program_class_v4_activation ... ok), igneum-exec (its per-crate line is not in the relay's upload of the report, which keeps the stage's tail; the unit exited 0, so it passed), kaspa-pow 15 (program_class_v3_seeds_hash_their_own_program_over_their_own_cache ... ok and program_class_v4_seeds_hash_the_shadow_program_over_the_v3_day_cache ... ok, both #[cfg(feature = "igneum-pow")]), igneum-miner (the same: not in the upload, in the exit-0 unit), kaspa-p2p-flows 33, igneum-app 112 + 26 + 8. The feature: build-job.mjs and push-build-inputs.sh carry no --features for the test units (the manifest's tests entries are dir and packages only; the build units have kaspad/igneum-pow), and the PC's jobbuild.rs runs cargo test --release -p ... in ONE invocation per unit, where igneum-miner depends on kaspa-pow with features = ["igneum-pow"], so cargo's feature unification turns the feature on for kaspa-pow's test target in that invocation: the two engine tests above ran on PC 2 with the feature, named in the report, which is the evidence main asked for. The same two suites also pass on the Mac with the flag explicit (cargo test --release -p kaspa-pow --features igneum-pow: 15; -p kaspa-consensus-core: 109 + 7). What the tool lacks: a features key on a test unit; not added here (a change to the PC's installed app would be needed to honour it)

The cut preconditions (the coordinator's second brief, 6 October 2026 evening)

# Gate Evidence required State
P1 the rehearsal plan and the v4 override object for the rented fleet docs/plans/counter-asic-3-rehearsal.md; the objects with their digests WRITTEN (not run: the fleet agent runs it): the publish object (the live 13 fields plus the floor N6 and the window 86,400; digest ac8e60ce205852bdda6b554f8cbfbd9dbb040187f487cbd8affe8103633dfd56 at the worked example N6 = 219,600) and the rehearsal object (every earlier switch at 0, window 3,600, floor 14,400; digest bc2142b178ff367ae84ff0699ff523760d8878f883375da21864ed8d3ad39237), both read from the signalling node's start lines on throwaway private networks; override-v4-publish-example.json and override-v4-rehearsal.json in this directory
P2 miner-signalled class activation, implemented behind the override, the fast-time gate with three cases and the failed case docs/plans/counter-asic-3-node.md section 6; infra/fast-time/class-v4-signal.mjs GREEN on the Mac: two of three signalling never flips (7 epochs, 6,166 to 7,583 bps), all three flips at epoch 3 (the first full window, 10,000 bps, the same line on 3 of 3 nodes, the id assertion), nobody signalling flips at the floor epoch 5 and not before; the known-failed case fails on eight checks. Rows and summary files: node doc section 6.4; class-v4-signal-{no-flip,flip,floor,failed-case}.json
G6 (signalling) the fork change on PC 2 with the igneum-pow feature the job ids and their lines GREEN on fork 0562a7f2 (main f39a8eb), three PC 2 jobs under one clearance ("PC 2 open for G6", 17:27Z), the mkdir lock taken 17:28:15Z and released 17:38:58Z, then 17:39:41Z to 17:55:31Z; prover on, app untouched. Job 1 build-20261006-173017 (the six crates and the app): every build stage ok, the app tests 112 + 26 + 8, but kaspa-consensus 97 passed and 1 FAILED on 2.0's known flake ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list (UnexpectedDifficulty(.., 487111630, 487128802) in mine_on_all, the 0.3.10 cut's section 11 case, which also passed on the Mac and in this morning's job 155958), and cargo stopped the unit there. Treated as 2.0 did: job 2 build-20261006-174027 (kaspa-consensus alone, 17:40 to 17:46Z): RESULT test node [kaspa-consensus] exit 0 19 s, done exit 0 after 345 s ... every stage ok. Job 3 build-20261006-174823 (the five crates and the app, 17:48 to 17:55Z): RESULT test node [kaspa-consensus-core igneum-exec kaspa-pow igneum-miner kaspa-p2p-flows] exit 0 35 s and RESULT test app/igneum-app [igneum-app] exit 0 5 s: kaspa-consensus-core 110 + 7 (override_params_carry_the_program_class_v4_activation ... ok, the signal window test inside it), igneum-exec 18, kaspa-pow 15 (program_class_signal_rule ... ok is consensus-core's; kaspa-pow's program_class_v4_seeds_hash_the_shadow_program_over_the_v3_day_cache ... ok, the feature on), igneum-miner 18, kaspa-p2p-flows 33, igneum-app 112 + 26 + 8; the job's own closing line reads failed ... upload incomplete because the relay's blob service refused one of the nine uploads (igneum-app.exe.zst FAILED: blob PUT: no url in the reply: service_unavailable, the shipper's 17:25Z fault) AFTER both test stages had closed with exit 0, so the STAGE and RESULT lines are the evidence, as the shipper's warning said. Where the runs went: these three on PC 2 under the clearance given before the build-server rule arrived (18:0xZ); no further Linux build or suite is needed by this brief; the next one from this lane goes to igneum-build-1 through tools/build-remote.sh

Summary files in this directory: class-v4-20261006-1553Z-cpu.json (G4 run 1), class-v4-20261006-never-failed-case.json (G4 run 2, the failed case), class-v4-20261006-metal.json (G4b), class-v4-20261006-id-rerun.json (G4 on the program-id fix, with the id assertion), class-v4-20261006-id-failed-case.json (the id assertion's failed case).