From c5bfa14dc029f5da325698ddf460eeafd63d4ec1 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:34:52 +0000 Subject: [PATCH] Counter ASIC 3.0 gates (node): the digests re-read on the right network ids (the digest folds the network id in; the fleet's a15db4f0 on suffix 400 confirmed with the Mac binary of the same fork commit; the publish example 65a42ab2 on the devnet id); the 0.3.13 parse refusal as a cut-order fact Co-Authored-By: Claude Fable 5.1 --- docs/plans/counter-asic-3-gate/node-gates.md | 2 +- docs/plans/counter-asic-3-rehearsal.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/plans/counter-asic-3-gate/node-gates.md b/docs/plans/counter-asic-3-gate/node-gates.md index b7c62556d..793c72734 100644 --- a/docs/plans/counter-asic-3-gate/node-gates.md +++ b/docs/plans/counter-asic-3-gate/node-gates.md @@ -13,7 +13,7 @@ | # | 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 | +| 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 on the devnet network id `65a42ab2e63d93ac02acf761b411b31acac6c9413bbd0c6a2f4cced10509efdf` at the worked example N6 = 219,600, fork 0562a7f2), the rehearsal object (every earlier switch at 0, window 3,600, floor 14,400; digest on suffix 400 `aef46983dfd121d5ecbefd056ff02d001b89315bd0547b4e1007b0b0ee7eee2c`) and the re-cut for the hour (600-DAA epochs, window 600, floor 2,400; digest on suffix 400 `a15db4f0d6a5cc891582760ef5593e69014a5133261def84647cb7617528764f`, the value the 16 fleet boxes printed); CORRECTED 18:4xZ: the digest folds the network id in, and the first values (`ac8e60ce`, `bc2142b1`, `d23394e7`) were read on throwaway suffixes; `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 | diff --git a/docs/plans/counter-asic-3-rehearsal.md b/docs/plans/counter-asic-3-rehearsal.md index c652aa14f..03d75158c 100644 --- a/docs/plans/counter-asic-3-rehearsal.md +++ b/docs/plans/counter-asic-3-rehearsal.md @@ -16,7 +16,7 @@ The class v4 activation on a chain of real boxes, in the shape the live devnet w ## 2. The override objects -Both objects below are JSON text to be written verbatim; a `never` height is `18446744073709551615`, which no JSON tool that goes through a double may rewrite (the fast-time harness's rule). The digests are what a node of the signalling commit prints at start (`Consensus params digest`); the fleet agent compares every box's line against them and the stale box's against its own. +Both objects below are JSON text to be written verbatim; a `never` height is `18446744073709551615`, which no JSON tool that goes through a double may rewrite (the fast-time harness's rule). The digests are what a node of the signalling commit (fork 0562a7f2) prints at start (`Consensus params digest`); the fleet agent compares every box's line against them and the stale box's against its own. CORRECTION 18:4xZ (the rehearsal's first reading): the digest folds the NETWORK ID in, so one file prints another digest on another `--devnet-suffix` (the same binary and file: `a15db4f0...` at suffix 400, `d23394e7...` at 996, `45eeea99...` at 401); the first values written here were read on throwaway suffixes and were wrong for the fleet's suffix 400. Every digest below now names its network id; the one the live devnet prints is the one read with no suffix. ### 2a. The live devnet publish object (NOT published by this plan; the shape the cut will use) @@ -26,7 +26,7 @@ The live file today (`/tmp/igneum-devnet/override-v3.json`, 13 fields, read 16:5 {"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000,"finality_v3_activation_daa":135200,"program_class_v3_activation_daa":154800,"proving_v1_activation_daa":154800,"proving_v1_segment_blocks":8,"proving_v1_unproven_daa":600,"proving_v1_aggregator_share_bps":1000,"proving_v1_fresh_rule_daa":198000,"exec_restart_number":27276,"exec_restart_hash":"bb45cf0dd2d7cc97ebfa5a2701527c09a8ede5d32de74efead9caa293b15688a","exec_restart_trust_daa":200000,"program_class_v4_activation_daa":N6,"program_class_v4_signal_window_daa":86400} ``` -What the two fields do on the live devnet: every node of the signalling binary stamps object byte 4 into its templates from its first block, so the signal share climbs as the fleet updates; the class flips at the first epoch boundary whose window (the 86,400 DAA, one day, below that epoch's seed block) has 95 percent of its blue blocks signalling, which is about a day after the LAST box of 95 percent of the hash rate has updated; the floor `N6` flips it regardless at the latest. Digest of this object: `ac8e60ce205852bdda6b554f8cbfbd9dbb040187f487cbd8affe8103633dfd56` (read from the signalling node's start line, 18:05Z; the node also prints `Program class v4 from the override file: active from epoch 61 (DAA score 219600 rounded up to the epoch boundary at 219600, epochs of 3600 DAA)` and the window line) (with `N6` = 219,600 as the worked example; any other `N6` moves it). +What the two fields do on the live devnet: every node of the signalling binary stamps object byte 4 into its templates from its first block, so the signal share climbs as the fleet updates; the class flips at the first epoch boundary whose window (the 86,400 DAA, one day, below that epoch's seed block) has 95 percent of its blue blocks signalling, which is about a day after the LAST box of 95 percent of the hash rate has updated; the floor `N6` flips it regardless at the latest. Digest of this object on the DEVNET network id (no suffix), the signalling fork 0562a7f2: `65a42ab2e63d93ac02acf761b411b31acac6c9413bbd0c6a2f4cced10509efdf` (18:4xZ; the earlier `ac8e60ce...` was read at suffix 998 and does not apply); the no-file devnet digest on the same binary is `7f2e49be...`, the fork test's pinned value. The 0.3.15 binary may move both if 0.3.14 added a digest field: the shipper reads the live value from the 0.3.15 node. The node also prints `Program class v4 from the override file: active from epoch 61 (DAA score 219600 rounded up to the epoch boundary at 219600, epochs of 3600 DAA)` and the window line. CUT ORDER (found by the shipper, 18:3xZ): a 0.3.13 node refuses the 15-field file at PARSE (`unknown field program_class_v4_activation_daa`) and exits before any handshake, so the file reaches a node only with or after its 0.3.15 binary (the app applies the manifest's override after the update; the hand nodes and the seeds get the file in the same step as the binary, never before) (with `N6` = 219,600 as the worked example; any other `N6` moves it). ### 2b. The rehearsal object (the fleet chain) @@ -36,11 +36,11 @@ A fresh chain, every earlier switch at 0 (the testnet's shape: the chain is born {"difficulty_v2_activation_daa":0,"proving_v0_activation_daa":0,"fees_v1_activation_daa":0,"finality_v3_activation_daa":0,"program_class_v3_activation_daa":0,"proving_v1_activation_daa":0,"proving_v1_segment_blocks":8,"proving_v1_unproven_daa":600,"proving_v1_aggregator_share_bps":1000,"proving_v1_fresh_rule_daa":0,"exec_restart_number":18446744073709551615,"exec_restart_hash":"","exec_restart_trust_daa":18446744073709551615,"program_class_v4_activation_daa":14400,"program_class_v4_signal_window_daa":3600} ``` -The arithmetic: epochs of 3,600 DAA, lead 600. Epoch `e`'s seed block is the last chain block below `3600 e - 600`; its window is full when that block's DAA is at least 3,600: epoch 1's seed block sits at DAA 2,999 (not full), epoch 2's at 6,599 (full). With every mining box signalling 4, the tally at epoch 2's seed block is 100 percent of the blue blocks in DAA 2,999 to 6,599, so the class flips at epoch 2, DAA 7,200, about 2 hours after genesis; the floor (epoch 4, DAA 14,400) is 2 hours later and is not reached by the run. Digest: `bc2142b178ff367ae84ff0699ff523760d8878f883375da21864ed8d3ad39237` (the signalling node's start line on this object, 18:05Z, with `Program class v4 from the override file: active from epoch 4 (DAA score 14400 ...)` and `Program class v4 signal window from the override file: 3600 DAA ...`); the devnet digest with no file at all is `7f2e49beabc253f327c5ac6bb457a674ea7f527af2971c95d3bdf65ef8bcf977` on this binary (the fork's pinned test), `c562d70e...` on 0.3.11 to 0.3.13. +The arithmetic: epochs of 3,600 DAA, lead 600. Epoch `e`'s seed block is the last chain block below `3600 e - 600`; its window is full when that block's DAA is at least 3,600: epoch 1's seed block sits at DAA 2,999 (not full), epoch 2's at 6,599 (full). With every mining box signalling 4, the tally at epoch 2's seed block is 100 percent of the blue blocks in DAA 2,999 to 6,599, so the class flips at epoch 2, DAA 7,200, about 2 hours after genesis; the floor (epoch 4, DAA 14,400) is 2 hours later and is not reached by the run. Digest on `igneum-devnet-400` (suffix 400): `aef46983dfd121d5ecbefd056ff02d001b89315bd0547b4e1007b0b0ee7eee2c` (the signalling node's start line, 18:4xZ; the earlier `bc2142b1...` was read at suffix 997); the node also prints `Program class v4 from the override file: active from epoch 4 (DAA score 14400 ...)` and `Program class v4 signal window from the override file: 3600 DAA ...`. ### 2c. The re-cut for the hour (18:1x UTC, the coordinator's "run it now") -If the fleet chain runs the devnet's 1 block/s, object 2b flips at 2 hours; this object flips at 20 minutes: epochs of 600 DAA (lead 100), window 600, floor 2,400. Epoch `e`'s seed block sits at DAA `600 e - 100`; the window is full from epoch 2 (seed at 1,100), so the flip is at epoch 2, DAA 1,200, minute 20 from the chain's start; the floor is epoch 4, DAA 2,400, minute 40; the run ends at DAA 1,800 (minute 30, one epoch after the flip; the floor is not reached). If the fleet chain is made to run 10 blocks/s instead, object 2b itself gives 6 / 12 / 24 minutes (window / flip / floor) and this one 1 / 2 / 4 minutes, too fast for a 15-minute sample cadence: use 2b. File `docs/plans/counter-asic-3-gate/override-v4-rehearsal-1bps.json`, digest `d23394e796fb542274207f1d281bc40126040e04f86882faa0b49ea3c3f1f91b` (the signalling node's start line, with `PoW schedule from the override file: epoch 600 DAA, lead 100 DAA, day 86400000 ms`, `Program class v4 from the override file: active from epoch 4 (DAA score 2400 ...)`, `Program class v4 signal window from the override file: 600 DAA ...`). +If the fleet chain runs the devnet's 1 block/s, object 2b flips at 2 hours; this object flips at 20 minutes: epochs of 600 DAA (lead 100), window 600, floor 2,400. Epoch `e`'s seed block sits at DAA `600 e - 100`; the window is full from epoch 2 (seed at 1,100), so the flip is at epoch 2, DAA 1,200, minute 20 from the chain's start; the floor is epoch 4, DAA 2,400, minute 40; the run ends at DAA 1,800 (minute 30, one epoch after the flip; the floor is not reached). If the fleet chain is made to run 10 blocks/s instead, object 2b itself gives 6 / 12 / 24 minutes (window / flip / floor) and this one 1 / 2 / 4 minutes, too fast for a 15-minute sample cadence: use 2b. File `docs/plans/counter-asic-3-gate/override-v4-rehearsal-1bps.json`, digest on `igneum-devnet-400` (suffix 400): `a15db4f0d6a5cc891582760ef5593e69014a5133261def84647cb7617528764f`, the value all 16 fleet boxes printed on the Linux build of the same fork commit 0562a7f2 (PC 2 job build-20261006-174823; the earlier `d23394e7...` was this file at suffix 996), with `PoW schedule from the override file: epoch 600 DAA, lead 100 DAA, day 86400000 ms`, `Program class v4 from the override file: active from epoch 4 (DAA score 2400 ...)`, `Program class v4 signal window from the override file: 600 DAA ...`). ``` {"difficulty_v2_activation_daa":0,"proving_v0_activation_daa":0,"fees_v1_activation_daa":0,"finality_v3_activation_daa":0,"program_class_v3_activation_daa":0,"proving_v1_activation_daa":0,"proving_v1_segment_blocks":8,"proving_v1_unproven_daa":600,"proving_v1_aggregator_share_bps":1000,"proving_v1_fresh_rule_daa":0,"exec_restart_number":18446744073709551615,"exec_restart_hash":"","exec_restart_trust_daa":18446744073709551615,"pow_epoch_blocks":600,"pow_epoch_lead":100,"program_class_v4_activation_daa":2400,"program_class_v4_signal_window_daa":600} @@ -71,7 +71,7 @@ Never: no live-devnet port, no live override file, no manifest, no `update-now`; | Field | From | Pass rule | |---|---|---| -| `digest` per box | the node's first lines | one value on every signalling box, equal to 2b's; the stale box prints 0.3.13's digest of the same file (a different value, since its binary lacks the two fields) | +| `digest` per box | the node's first lines | one value on every signalling box, equal to the object's suffix-400 value (2b `aef46983...`, 2c `a15db4f0...`); the stale box prints 0.3.13's digest of the same file (a different value, since its binary lacks the two fields) | | `switch_lines` per box | the node's first lines | the floor line names epoch 4 and the window line names 3,600 DAA, on every signalling box | | `signal_line` per box | step 7 | present on every signalling box, epoch 2, the same seed block hash, share 10,000 bps (at least 9,500) | | `blocks_before`, `blocks_after` | `getBlocks` from any box, split at DAA 7,200 | both over 0 |