Counter ASIC 3.0 gates (node): the seven-window signal gate re-run on fork 0760b844 (four cases, section 6.5), the controller harness for difficulty rule v3, the getRecentBlocks API row
class-v4-signal.mjs now runs the 0.3.16 rule (95 percent in each of 7 consecutive windows ending at the seed block; the flip at epoch 4 with the 30-DAA window), requires a floor for a signalling case (the canary rule: no floor, no signal; the floor-less first pass read every chain byte 0), reads programClassV4SignalWeakestBps and checks that the signal line names seven windows. The four cases on 6 October 2026, 20:57 to 21:25Z: two of three signal, no flip (weakest 5,666 to 6,333 bps); all three, flip at epoch 4 (DAA 241 seen, boundary 240; 3 of 3 signal lines; the id assertion on epochs 4 to 6); nobody, the floor at 360, flip at epoch 6 and not before; the known-failed case FAILS on nine checks. Summaries in docs/plans/counter-asic-3-gate/class-v4-signal7-*.json. infra/fast-time/difficulty-v3.mjs (Horizon lane 5 proposal 2's harness case): three nodes in a star through a TCP delay proxy (the document's propagation delay d over Kaspa's three relay legs, inv, request, block, so d / 3 per leg; the handshake's first 5 s undelayed, the version exchange times out at 4 s), override-60x.json re-rated to 10 bps (the override-params.md example's k 124 and limits, depths x10, PoW epoch 600 DAA so an epoch stays 60 s), one CPU miner per node, pass = DAG rate within 10 percent of target and the sink's expected hashes per block within 10 percent of the miners' summed hash x T after 600 of 900 s; the red share and chain step spacing reported. Results follow in their own commit (the runs are in progress at 21:30Z). docs/design/execution-layer.md 8.2: the igneum_getRecentBlocks row (fork eec34ac3). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
a06c708bf6
commit
20a4841030
8 changed files with 2578 additions and 16 deletions
|
|
@ -367,6 +367,7 @@ Standard namespace, unchanged semantics where the table says so; RPC "blocks" ar
|
|||
| `igneum_getSegment(number)` | New | Mergeset in order, executed set, shard plan, proof record if any |
|
||||
| `igneum_getTransactionStatus(hash)` | New | `{included_in: [hashes], executing_copy, executed, proven, locked, skip_reason}` |
|
||||
| `igneum_getProvingFee`, `igneum_getBudgets` | New | `f_p`, `B_e`, `B_p`, backlog depth |
|
||||
| `igneum_getRecentBlocks(seconds)` | New (0.3.16) | Every block the executed chain saw in the last `seconds` (default and cap 600) by chain-block header time, newest chain block first, its merged blocks after it in mergeset order: `{hash, blue_score, daa_score, timestamp_ms, vote_key_hash, is_chain_block, color, timestamp_source}`; `color` blue or red; a merged row's time and blue score come from the header store (`timestamp_source` "header") or, without consensus, from its chain block ("chain_block"). The app's live view derives its 10 minute miner count and per minute buckets from one reply |
|
||||
|
||||
### 8.3 Hardhat and Foundry
|
||||
|
||||
|
|
|
|||
559
docs/plans/counter-asic-3-gate/class-v4-signal7-failed-case.json
Normal file
559
docs/plans/counter-asic-3-gate/class-v4-signal7-failed-case.json
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
{
|
||||
"pass": false,
|
||||
"expect": "flip",
|
||||
"signals": [
|
||||
4,
|
||||
4,
|
||||
3
|
||||
],
|
||||
"checks": {
|
||||
"zero_rejected_by_miners": true,
|
||||
"zero_rejected_by_nodes": true,
|
||||
"sinks_agree": true,
|
||||
"block_counts_agree": true,
|
||||
"miners_agree_on_every_program": true,
|
||||
"window_line_on_every_node": true,
|
||||
"every_node_signals_its_byte": true,
|
||||
"chain_carries_the_bytes": true,
|
||||
"template_switched_to_v4": false,
|
||||
"switched_at_the_first_full_window_epoch": false,
|
||||
"switched_before_the_floor": false,
|
||||
"signal_line_on_every_node_same_epoch": false,
|
||||
"signal_share_at_or_above_threshold": false,
|
||||
"signal_line_names_seven_windows": false,
|
||||
"blocks_on_both_sides": false,
|
||||
"v4_ids_equal_the_cli_v4_id": false,
|
||||
"v4_ids_differ_from_the_same_seed_v3_id": false
|
||||
},
|
||||
"window": 30,
|
||||
"windows": 7,
|
||||
"floor": 100000,
|
||||
"v3_activation": 60,
|
||||
"epoch_blocks": 60,
|
||||
"lead": 10,
|
||||
"first_full_window_epoch": 4,
|
||||
"floor_epoch": 1667,
|
||||
"node": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneumd",
|
||||
"miner": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneum-miner",
|
||||
"template_switch": null,
|
||||
"run_ended_at_s": 410.2,
|
||||
"final_daa": 421,
|
||||
"max_epoch_seen": 7,
|
||||
"epochs": {
|
||||
"0": {
|
||||
"class": 2,
|
||||
"firstSeenDaa": 0,
|
||||
"at": 4.6,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"1": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 60,
|
||||
"at": 27.7,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"2": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 120,
|
||||
"at": 91.8,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"3": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 180,
|
||||
"at": 160.9,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"4": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 240,
|
||||
"at": 233,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 5333,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"5": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 300,
|
||||
"at": 293.1,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 5333,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"6": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 360,
|
||||
"at": 350.2,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 5333,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"7": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 421,
|
||||
"at": 410.2,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 6333,
|
||||
"signal_epoch": null
|
||||
}
|
||||
},
|
||||
"blocks": {
|
||||
"total": 424,
|
||||
"before_boundary": 424,
|
||||
"after_boundary": 0,
|
||||
"version_bytes": {
|
||||
"0": 1,
|
||||
"3": 135,
|
||||
"4": 288
|
||||
},
|
||||
"signal_share_bps_on_chain": 6792
|
||||
},
|
||||
"programs": [
|
||||
{
|
||||
"epoch": 0,
|
||||
"class": "v2",
|
||||
"program_id": "8f8806638d59850f",
|
||||
"seed": "234e082d653dc69d",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 1,
|
||||
"class": "v3",
|
||||
"program_id": "7e2f9a15ca615321",
|
||||
"seed": "ae6cdc46ffc6ac68",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 2,
|
||||
"class": "v3",
|
||||
"program_id": "2c2a98fae78f74b8",
|
||||
"seed": "7d44b28f7a9c7f0a",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 3,
|
||||
"class": "v3",
|
||||
"program_id": "89ae54d5b5eae763",
|
||||
"seed": "6aea4563d3d935b3",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 4,
|
||||
"class": "v3",
|
||||
"program_id": "5a0ca4f1ff74e70c",
|
||||
"seed": "c37cf6f9e8cd33b5",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 5,
|
||||
"class": "v3",
|
||||
"program_id": "e4af5e0c4d9b93c2",
|
||||
"seed": "f8c304d64d5f8225",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 6,
|
||||
"class": "v3",
|
||||
"program_id": "b5ca5848f6f0413b",
|
||||
"seed": "1eb6aa4c17a2eed4",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 7,
|
||||
"class": "v3",
|
||||
"program_id": "ab61dbf422b32bc5",
|
||||
"seed": "9532201279474928",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
}
|
||||
],
|
||||
"program_id_rows": [],
|
||||
"accepted_per_miner": [
|
||||
131,
|
||||
157,
|
||||
135
|
||||
],
|
||||
"rejected_by_miners": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rejected_by_nodes": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"sinks": [
|
||||
"1c1eae6d5c82de1c",
|
||||
"1c1eae6d5c82de1c",
|
||||
"1c1eae6d5c82de1c"
|
||||
],
|
||||
"block_counts": [
|
||||
423,
|
||||
423,
|
||||
423
|
||||
],
|
||||
"signal_lines": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"floor_lines": [
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)"
|
||||
],
|
||||
"samples": [
|
||||
{
|
||||
"t": 4.6,
|
||||
"daa": 0,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"0/234e082d",
|
||||
"0/234e082d",
|
||||
"0/234e082d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 19.7,
|
||||
"daa": 47,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"47/9003a9d9",
|
||||
"47/9003a9d9",
|
||||
"47/9003a9d9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 34.7,
|
||||
"daa": 64,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"64/b4c1d83f",
|
||||
"64/b4c1d83f",
|
||||
"64/b4c1d83f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 49.7,
|
||||
"daa": 69,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"69/3dda5305",
|
||||
"69/3dda5305",
|
||||
"69/3dda5305"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 64.8,
|
||||
"daa": 88,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"88/84d103be",
|
||||
"88/84d103be",
|
||||
"88/84d103be"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 79.8,
|
||||
"daa": 107,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"107/95682fc8",
|
||||
"107/95682fc8",
|
||||
"107/95682fc8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 94.8,
|
||||
"daa": 120,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"120/bb25b3af",
|
||||
"120/bb25b3af",
|
||||
"120/bb25b3af"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 109.8,
|
||||
"daa": 138,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"138/82254c76",
|
||||
"138/82254c76",
|
||||
"138/82254c76"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 124.9,
|
||||
"daa": 154,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"154/ab3e9744",
|
||||
"154/ab3e9744",
|
||||
"154/ab3e9744"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 139.9,
|
||||
"daa": 167,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"167/381fdc27",
|
||||
"167/381fdc27",
|
||||
"167/381fdc27"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 154.9,
|
||||
"daa": 174,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"174/b6930be6",
|
||||
"174/b6930be6",
|
||||
"174/b6930be6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 169.9,
|
||||
"daa": 190,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 4285,
|
||||
"nodes": [
|
||||
"190/3473bc22",
|
||||
"190/3473bc22",
|
||||
"190/3473bc22"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 184.9,
|
||||
"daa": 207,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5000,
|
||||
"nodes": [
|
||||
"207/01637a3f",
|
||||
"207/01637a3f",
|
||||
"207/01637a3f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 200,
|
||||
"daa": 219,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"219/0fda8440",
|
||||
"219/0fda8440",
|
||||
"219/0fda8440"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 215,
|
||||
"daa": 226,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"226/8ed13229",
|
||||
"226/8ed13229",
|
||||
"226/8ed13229"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 230,
|
||||
"daa": 236,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5000,
|
||||
"nodes": [
|
||||
"236/b0be941e",
|
||||
"236/b0be941e",
|
||||
"236/b0be941e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 245,
|
||||
"daa": 252,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"252/a93709a4",
|
||||
"252/a93709a4",
|
||||
"252/a93709a4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 260,
|
||||
"daa": 274,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"274/099337fa",
|
||||
"274/099337fa",
|
||||
"274/099337fa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 275.1,
|
||||
"daa": 282,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"282/6bd5d923",
|
||||
"282/6bd5d923",
|
||||
"282/6bd5d923"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 290.1,
|
||||
"daa": 296,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 5000,
|
||||
"nodes": [
|
||||
"296/94f37746",
|
||||
"296/94f37746",
|
||||
"296/94f37746"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 305.1,
|
||||
"daa": 313,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 5333,
|
||||
"nodes": [
|
||||
"313/b76f2f75",
|
||||
"313/b76f2f75",
|
||||
"313/b76f2f75"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 320.1,
|
||||
"daa": 326,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 5000,
|
||||
"nodes": [
|
||||
"326/9a5dee69",
|
||||
"326/9a5dee69",
|
||||
"326/9a5dee69"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 335.1,
|
||||
"daa": 341,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"341/058c9422",
|
||||
"341/058c9422",
|
||||
"341/058c9422"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 350.2,
|
||||
"daa": 360,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 5333,
|
||||
"nodes": [
|
||||
"360/901edc84",
|
||||
"360/901edc84",
|
||||
"360/901edc84"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 365.2,
|
||||
"daa": 377,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 6000,
|
||||
"nodes": [
|
||||
"377/e681d3ba",
|
||||
"377/e681d3ba",
|
||||
"377/e681d3ba"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 380.2,
|
||||
"daa": 388,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 6333,
|
||||
"nodes": [
|
||||
"388/05c84f63",
|
||||
"388/05c84f63",
|
||||
"388/05c84f63"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 395.2,
|
||||
"daa": 406,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"406/4bc6b31c",
|
||||
"406/4bc6b31c",
|
||||
"406/4bc6b31c"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 410.2,
|
||||
"daa": 421,
|
||||
"epoch": 7,
|
||||
"class": 3,
|
||||
"bps": 6333,
|
||||
"nodes": [
|
||||
"421/6b95e961",
|
||||
"421/6b95e961",
|
||||
"421/6b95e961"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
511
docs/plans/counter-asic-3-gate/class-v4-signal7-flip.json
Normal file
511
docs/plans/counter-asic-3-gate/class-v4-signal7-flip.json
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
{
|
||||
"pass": true,
|
||||
"expect": "flip",
|
||||
"signals": [
|
||||
4,
|
||||
4,
|
||||
4
|
||||
],
|
||||
"checks": {
|
||||
"zero_rejected_by_miners": true,
|
||||
"zero_rejected_by_nodes": true,
|
||||
"sinks_agree": true,
|
||||
"block_counts_agree": true,
|
||||
"miners_agree_on_every_program": true,
|
||||
"window_line_on_every_node": true,
|
||||
"every_node_signals_its_byte": true,
|
||||
"chain_carries_the_bytes": true,
|
||||
"template_switched_to_v4": true,
|
||||
"switched_at_the_first_full_window_epoch": true,
|
||||
"switched_before_the_floor": true,
|
||||
"signal_line_on_every_node_same_epoch": true,
|
||||
"signal_share_at_or_above_threshold": true,
|
||||
"signal_line_names_seven_windows": true,
|
||||
"blocks_on_both_sides": true,
|
||||
"v4_ids_equal_the_cli_v4_id": true,
|
||||
"v4_ids_differ_from_the_same_seed_v3_id": true
|
||||
},
|
||||
"window": 30,
|
||||
"windows": 7,
|
||||
"floor": 100000,
|
||||
"v3_activation": 60,
|
||||
"epoch_blocks": 60,
|
||||
"lead": 10,
|
||||
"first_full_window_epoch": 4,
|
||||
"floor_epoch": 1667,
|
||||
"node": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneumd",
|
||||
"miner": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneum-miner",
|
||||
"template_switch": {
|
||||
"epoch": 4,
|
||||
"daa": 241,
|
||||
"at": 228.1
|
||||
},
|
||||
"run_ended_at_s": 339.4,
|
||||
"final_daa": 360,
|
||||
"max_epoch_seen": 6,
|
||||
"epochs": {
|
||||
"0": {
|
||||
"class": 2,
|
||||
"firstSeenDaa": 0,
|
||||
"at": 4.6,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"1": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 60,
|
||||
"at": 29.7,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"2": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 120,
|
||||
"at": 106.8,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"3": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 180,
|
||||
"at": 166,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"4": {
|
||||
"class": 4,
|
||||
"firstSeenDaa": 241,
|
||||
"at": 228.1,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 10000,
|
||||
"signal_epoch": 4
|
||||
},
|
||||
"5": {
|
||||
"class": 4,
|
||||
"firstSeenDaa": 301,
|
||||
"at": 284.2,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 10000,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"6": {
|
||||
"class": 4,
|
||||
"firstSeenDaa": 360,
|
||||
"at": 339.4,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 10000,
|
||||
"signal_epoch": null
|
||||
}
|
||||
},
|
||||
"blocks": {
|
||||
"total": 365,
|
||||
"before_boundary": 241,
|
||||
"after_boundary": 124,
|
||||
"version_bytes": {
|
||||
"0": 1,
|
||||
"4": 364
|
||||
},
|
||||
"signal_share_bps_on_chain": 9973
|
||||
},
|
||||
"programs": [
|
||||
{
|
||||
"epoch": 0,
|
||||
"class": "v2",
|
||||
"program_id": "8f8806638d59850f",
|
||||
"seed": "234e082d653dc69d",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 1,
|
||||
"class": "v3",
|
||||
"program_id": "8b03d07a1875fe62",
|
||||
"seed": "08625fc57bb161d4",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 2,
|
||||
"class": "v3",
|
||||
"program_id": "6896042b76dabe5a",
|
||||
"seed": "f74f60ade435880a",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 3,
|
||||
"class": "v3",
|
||||
"program_id": "26f4071960d8aeef",
|
||||
"seed": "ed4e93635f53f4e2",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 4,
|
||||
"class": "v4",
|
||||
"program_id": "513bbe423698ac46",
|
||||
"seed": "a5adea6f1fecb370",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 5,
|
||||
"class": "v4",
|
||||
"program_id": "ee00d3fe4a0b811c",
|
||||
"seed": "706cc2b5ddd6ea3c",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 6,
|
||||
"class": "v4",
|
||||
"program_id": "50cbbceb1587bd20",
|
||||
"seed": "cee479e6601625a5",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
}
|
||||
],
|
||||
"program_id_rows": [
|
||||
{
|
||||
"epoch": 4,
|
||||
"seed": "a5adea6f1fecb370",
|
||||
"miners_id": "513bbe423698ac46",
|
||||
"miners": 3,
|
||||
"cli_v3": "11695bdfc66258c9",
|
||||
"cli_v4": "513bbe423698ac46"
|
||||
},
|
||||
{
|
||||
"epoch": 5,
|
||||
"seed": "706cc2b5ddd6ea3c",
|
||||
"miners_id": "ee00d3fe4a0b811c",
|
||||
"miners": 3,
|
||||
"cli_v3": "05a7e8fbadcb906f",
|
||||
"cli_v4": "ee00d3fe4a0b811c"
|
||||
},
|
||||
{
|
||||
"epoch": 6,
|
||||
"seed": "cee479e6601625a5",
|
||||
"miners_id": "50cbbceb1587bd20",
|
||||
"miners": 3,
|
||||
"cli_v3": "2f96368ac5c87ad3",
|
||||
"cli_v4": "50cbbceb1587bd20"
|
||||
}
|
||||
],
|
||||
"accepted_per_miner": [
|
||||
117,
|
||||
133,
|
||||
114
|
||||
],
|
||||
"rejected_by_miners": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rejected_by_nodes": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"sinks": [
|
||||
"786d8071368913fa",
|
||||
"786d8071368913fa",
|
||||
"786d8071368913fa"
|
||||
],
|
||||
"block_counts": [
|
||||
364,
|
||||
364,
|
||||
364
|
||||
],
|
||||
"signal_lines": [
|
||||
"Program class v4 by miner signal: epoch 4 (share 10000 bps over 30 DAA ending at seed block a5adea6f1fecb370a5a77b2c7cfd586dcb601eba8664c364c519830185159143, threshold 9500 bps in each of 7 consecutive windows, weakest 10000 bps, shares oldest first [10000, 10000, 10000, 10000, 10000, 10000, 10000], 210 of 210 blue blocks)",
|
||||
"Program class v4 by miner signal: epoch 4 (share 10000 bps over 30 DAA ending at seed block a5adea6f1fecb370a5a77b2c7cfd586dcb601eba8664c364c519830185159143, threshold 9500 bps in each of 7 consecutive windows, weakest 10000 bps, shares oldest first [10000, 10000, 10000, 10000, 10000, 10000, 10000], 210 of 210 blue blocks)",
|
||||
"Program class v4 by miner signal: epoch 4 (share 10000 bps over 30 DAA ending at seed block a5adea6f1fecb370a5a77b2c7cfd586dcb601eba8664c364c519830185159143, threshold 9500 bps in each of 7 consecutive windows, weakest 10000 bps, shares oldest first [10000, 10000, 10000, 10000, 10000, 10000, 10000], 210 of 210 blue blocks)"
|
||||
],
|
||||
"floor_lines": [
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)"
|
||||
],
|
||||
"samples": [
|
||||
{
|
||||
"t": 4.6,
|
||||
"daa": 0,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"0/234e082d",
|
||||
"0/234e082d",
|
||||
"0/234e082d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 19.7,
|
||||
"daa": 45,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"45/ed680eb3",
|
||||
"45/ed680eb3",
|
||||
"45/ed680eb3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 34.7,
|
||||
"daa": 61,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"61/b2ac0c02",
|
||||
"61/b2ac0c02",
|
||||
"61/b2ac0c02"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 49.7,
|
||||
"daa": 67,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"67/cbd5a35e",
|
||||
"67/cbd5a35e",
|
||||
"67/cbd5a35e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 64.7,
|
||||
"daa": 80,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"80/d88cad13",
|
||||
"80/d88cad13",
|
||||
"80/d88cad13"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 79.8,
|
||||
"daa": 88,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"88/83050ad0",
|
||||
"88/83050ad0",
|
||||
"88/83050ad0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 94.8,
|
||||
"daa": 106,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"106/d230c5bc",
|
||||
"106/d230c5bc",
|
||||
"106/d230c5bc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 109.8,
|
||||
"daa": 124,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"124/9c5750a4",
|
||||
"124/9c5750a4",
|
||||
"124/9c5750a4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 124.9,
|
||||
"daa": 145,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"145/a5200bc7",
|
||||
"145/a5200bc7",
|
||||
"145/a5200bc7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 139.9,
|
||||
"daa": 157,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"157/407eca8c",
|
||||
"157/407eca8c",
|
||||
"157/407eca8c"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 154.9,
|
||||
"daa": 172,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"172/71c56601",
|
||||
"172/71c56601",
|
||||
"172/71c56601"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 170,
|
||||
"daa": 181,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"181/bdfe2032",
|
||||
"181/bdfe2032",
|
||||
"181/bdfe2032"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 185,
|
||||
"daa": 189,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"189/826a9db3",
|
||||
"189/826a9db3",
|
||||
"189/826a9db3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 200,
|
||||
"daa": 207,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"207/216fd0dc",
|
||||
"207/216fd0dc",
|
||||
"207/216fd0dc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 215.1,
|
||||
"daa": 221,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"221/b2e187ad",
|
||||
"221/b2e187ad",
|
||||
"221/b2e187ad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 230.1,
|
||||
"daa": 241,
|
||||
"epoch": 4,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"241/97e1a942",
|
||||
"241/97e1a942",
|
||||
"241/97e1a942"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 245.1,
|
||||
"daa": 254,
|
||||
"epoch": 4,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"254/15744959",
|
||||
"254/15744959",
|
||||
"254/15744959"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 260.2,
|
||||
"daa": 270,
|
||||
"epoch": 4,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"270/bf72bf67",
|
||||
"270/bf72bf67",
|
||||
"270/bf72bf67"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 275.2,
|
||||
"daa": 287,
|
||||
"epoch": 4,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"287/53fb6153",
|
||||
"287/53fb6153",
|
||||
"287/53fb6153"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 290.2,
|
||||
"daa": 308,
|
||||
"epoch": 5,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"308/947c64f4",
|
||||
"308/947c64f4",
|
||||
"308/947c64f4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 305.3,
|
||||
"daa": 325,
|
||||
"epoch": 5,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"325/526aa176",
|
||||
"325/526aa176",
|
||||
"325/526aa176"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 320.3,
|
||||
"daa": 336,
|
||||
"epoch": 5,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"336/4fcf7134",
|
||||
"336/4fcf7134",
|
||||
"336/4fcf7134"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 335.3,
|
||||
"daa": 354,
|
||||
"epoch": 5,
|
||||
"class": 4,
|
||||
"bps": 10000,
|
||||
"nodes": [
|
||||
"354/ed96e77e",
|
||||
"354/ed96e77e",
|
||||
"354/ed96e77e"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
636
docs/plans/counter-asic-3-gate/class-v4-signal7-floor.json
Normal file
636
docs/plans/counter-asic-3-gate/class-v4-signal7-floor.json
Normal file
|
|
@ -0,0 +1,636 @@
|
|||
{
|
||||
"pass": true,
|
||||
"expect": "floor",
|
||||
"signals": [
|
||||
3,
|
||||
3,
|
||||
3
|
||||
],
|
||||
"checks": {
|
||||
"zero_rejected_by_miners": true,
|
||||
"zero_rejected_by_nodes": true,
|
||||
"sinks_agree": true,
|
||||
"block_counts_agree": true,
|
||||
"miners_agree_on_every_program": true,
|
||||
"window_line_on_every_node": true,
|
||||
"every_node_signals_its_byte": true,
|
||||
"chain_carries_the_bytes": true,
|
||||
"template_switched_to_v4": true,
|
||||
"switched_at_the_floor_epoch": true,
|
||||
"no_signal_line_on_any_node": true,
|
||||
"floor_line_names_the_floor_epoch": true,
|
||||
"blocks_on_both_sides": true,
|
||||
"v4_ids_equal_the_cli_v4_id": true
|
||||
},
|
||||
"window": 30,
|
||||
"windows": 7,
|
||||
"floor": 360,
|
||||
"v3_activation": 60,
|
||||
"epoch_blocks": 60,
|
||||
"lead": 10,
|
||||
"first_full_window_epoch": 4,
|
||||
"floor_epoch": 6,
|
||||
"node": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneumd",
|
||||
"miner": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneum-miner",
|
||||
"template_switch": {
|
||||
"epoch": 6,
|
||||
"daa": 362,
|
||||
"at": 345.4
|
||||
},
|
||||
"run_ended_at_s": 461.7,
|
||||
"final_daa": 480,
|
||||
"max_epoch_seen": 8,
|
||||
"epochs": {
|
||||
"0": {
|
||||
"class": 2,
|
||||
"firstSeenDaa": 0,
|
||||
"at": 4.6,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"1": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 60,
|
||||
"at": 30.7,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"2": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 120,
|
||||
"at": 95.9,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"3": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 180,
|
||||
"at": 162,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"4": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 240,
|
||||
"at": 223.1,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"5": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 300,
|
||||
"at": 286.3,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"6": {
|
||||
"class": 4,
|
||||
"firstSeenDaa": 362,
|
||||
"at": 345.4,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"7": {
|
||||
"class": 4,
|
||||
"firstSeenDaa": 420,
|
||||
"at": 396.5,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"8": {
|
||||
"class": 4,
|
||||
"firstSeenDaa": 480,
|
||||
"at": 461.7,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
}
|
||||
},
|
||||
"blocks": {
|
||||
"total": 486,
|
||||
"before_boundary": 361,
|
||||
"after_boundary": 125,
|
||||
"version_bytes": {
|
||||
"0": 1,
|
||||
"3": 485
|
||||
},
|
||||
"signal_share_bps_on_chain": 0
|
||||
},
|
||||
"programs": [
|
||||
{
|
||||
"epoch": 0,
|
||||
"class": "v2",
|
||||
"program_id": "8f8806638d59850f",
|
||||
"seed": "234e082d653dc69d",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 1,
|
||||
"class": "v3",
|
||||
"program_id": "0e47ecc08def3b3c",
|
||||
"seed": "87f4edf6d5390261",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 2,
|
||||
"class": "v3",
|
||||
"program_id": "e01d3d013e9d0fd0",
|
||||
"seed": "6aa531dd57a2343a",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 3,
|
||||
"class": "v3",
|
||||
"program_id": "34ddb6eacf5ca8d5",
|
||||
"seed": "c053141073ce26a3",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 4,
|
||||
"class": "v3",
|
||||
"program_id": "b03aefe32cca46b5",
|
||||
"seed": "51e40d5dc38d9823",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 5,
|
||||
"class": "v3",
|
||||
"program_id": "3dd9cb5971851a52",
|
||||
"seed": "b4adb9c80f091964",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 6,
|
||||
"class": "v4",
|
||||
"program_id": "aa0283cc2b5e5b0f",
|
||||
"seed": "536c8ac2706c23be",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 7,
|
||||
"class": "v4",
|
||||
"program_id": "1d4f6d8c21386868",
|
||||
"seed": "116706d2320aad69",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 8,
|
||||
"class": "v4",
|
||||
"program_id": "4bee3fb48487db58",
|
||||
"seed": "556c3dacee5edf64",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
}
|
||||
],
|
||||
"program_id_rows": [
|
||||
{
|
||||
"epoch": 6,
|
||||
"seed": "536c8ac2706c23be",
|
||||
"miners_id": "aa0283cc2b5e5b0f",
|
||||
"miners": 3,
|
||||
"cli_v3": "25d2f5499f1c6060",
|
||||
"cli_v4": "aa0283cc2b5e5b0f"
|
||||
},
|
||||
{
|
||||
"epoch": 7,
|
||||
"seed": "116706d2320aad69",
|
||||
"miners_id": "1d4f6d8c21386868",
|
||||
"miners": 3,
|
||||
"cli_v3": "239d20744ba996ff",
|
||||
"cli_v4": "1d4f6d8c21386868"
|
||||
},
|
||||
{
|
||||
"epoch": 8,
|
||||
"seed": "556c3dacee5edf64",
|
||||
"miners_id": "4bee3fb48487db58",
|
||||
"miners": 3,
|
||||
"cli_v3": "a5f5e0f57f30aca7",
|
||||
"cli_v4": "4bee3fb48487db58"
|
||||
}
|
||||
],
|
||||
"accepted_per_miner": [
|
||||
170,
|
||||
162,
|
||||
153
|
||||
],
|
||||
"rejected_by_miners": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rejected_by_nodes": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"sinks": [
|
||||
"0db7f95ee7c2d6ec",
|
||||
"0db7f95ee7c2d6ec",
|
||||
"0db7f95ee7c2d6ec"
|
||||
],
|
||||
"block_counts": [
|
||||
485,
|
||||
485,
|
||||
485
|
||||
],
|
||||
"signal_lines": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"floor_lines": [
|
||||
"Program class v4 from the override file: active from epoch 6 (DAA score 360 rounded up to the epoch boundary at 360, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 6 (DAA score 360 rounded up to the epoch boundary at 360, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 6 (DAA score 360 rounded up to the epoch boundary at 360, epochs of 60 DAA)"
|
||||
],
|
||||
"samples": [
|
||||
{
|
||||
"t": 4.7,
|
||||
"daa": 0,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"0/234e082d",
|
||||
"0/234e082d",
|
||||
"0/234e082d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 19.7,
|
||||
"daa": 42,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"42/d1f90c89",
|
||||
"42/d1f90c89",
|
||||
"42/d1f90c89"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 34.7,
|
||||
"daa": 62,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"62/ecdf7c47",
|
||||
"62/ecdf7c47",
|
||||
"62/ecdf7c47"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 49.8,
|
||||
"daa": 69,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"69/04b8880d",
|
||||
"69/04b8880d",
|
||||
"69/04b8880d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 64.8,
|
||||
"daa": 86,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"86/98eb299b",
|
||||
"86/98eb299b",
|
||||
"86/98eb299b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 79.8,
|
||||
"daa": 108,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"108/dacf3726",
|
||||
"108/dacf3726",
|
||||
"108/dacf3726"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 94.9,
|
||||
"daa": 119,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"119/3522f373",
|
||||
"119/3522f373",
|
||||
"119/3522f373"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 109.9,
|
||||
"daa": 130,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"130/1cdfcc43",
|
||||
"130/1cdfcc43",
|
||||
"130/1cdfcc43"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 124.9,
|
||||
"daa": 150,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"150/2ed00203",
|
||||
"150/2ed00203",
|
||||
"150/2ed00203"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 140,
|
||||
"daa": 163,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"163/fdb35c12",
|
||||
"163/fdb35c12",
|
||||
"163/fdb35c12"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 155,
|
||||
"daa": 173,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"173/02d85439",
|
||||
"173/02d85439",
|
||||
"173/02d85439"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 170,
|
||||
"daa": 186,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"186/d7afd264",
|
||||
"186/d7afd264",
|
||||
"186/d7afd264"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 185,
|
||||
"daa": 200,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"200/3b87d7fc",
|
||||
"200/3b87d7fc",
|
||||
"200/3b87d7fc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 200.1,
|
||||
"daa": 218,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"218/e79e78a2",
|
||||
"218/e79e78a2",
|
||||
"218/e79e78a2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 215.1,
|
||||
"daa": 236,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"236/74b74819",
|
||||
"236/74b74819",
|
||||
"236/74b74819"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 230.2,
|
||||
"daa": 252,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"252/f44062e7",
|
||||
"252/f44062e7",
|
||||
"252/f44062e7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 245.2,
|
||||
"daa": 264,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"264/b7f42006",
|
||||
"264/b7f42006",
|
||||
"264/b7f42006"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 260.2,
|
||||
"daa": 279,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"279/988cb551",
|
||||
"279/988cb551",
|
||||
"279/988cb551"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 275.2,
|
||||
"daa": 289,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"289/f38c1458",
|
||||
"289/f38c1458",
|
||||
"289/f38c1458"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 290.3,
|
||||
"daa": 305,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"305/9125bec4",
|
||||
"305/9125bec4",
|
||||
"305/9125bec4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 305.3,
|
||||
"daa": 317,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"317/9dc60b29",
|
||||
"317/9dc60b29",
|
||||
"317/9dc60b29"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 320.3,
|
||||
"daa": 330,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"330/28eaf8e8",
|
||||
"330/28eaf8e8",
|
||||
"330/28eaf8e8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 335.4,
|
||||
"daa": 346,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"346/2c358b1f",
|
||||
"346/2c358b1f",
|
||||
"346/2c358b1f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 350.4,
|
||||
"daa": 367,
|
||||
"epoch": 6,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"367/b420706f",
|
||||
"367/b420706f",
|
||||
"367/b420706f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 365.4,
|
||||
"daa": 381,
|
||||
"epoch": 6,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"381/9363f9bd",
|
||||
"381/9363f9bd",
|
||||
"381/9363f9bd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 380.5,
|
||||
"daa": 397,
|
||||
"epoch": 6,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"397/49b6c6a3",
|
||||
"397/49b6c6a3",
|
||||
"397/49b6c6a3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 395.5,
|
||||
"daa": 417,
|
||||
"epoch": 6,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"417/cbc74290",
|
||||
"417/cbc74290",
|
||||
"417/cbc74290"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 410.5,
|
||||
"daa": 430,
|
||||
"epoch": 7,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"430/08e73746",
|
||||
"430/08e73746",
|
||||
"430/08e73746"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 425.6,
|
||||
"daa": 449,
|
||||
"epoch": 7,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"449/6067e6b4",
|
||||
"449/6067e6b4",
|
||||
"449/6067e6b4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 440.6,
|
||||
"daa": 460,
|
||||
"epoch": 7,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"460/1ae21462",
|
||||
"460/1ae21462",
|
||||
"460/1ae21462"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 455.6,
|
||||
"daa": 468,
|
||||
"epoch": 7,
|
||||
"class": 4,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"468/f9f3ca09",
|
||||
"468/f9f3ca09",
|
||||
"468/f9f3ca09"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
555
docs/plans/counter-asic-3-gate/class-v4-signal7-no-flip.json
Normal file
555
docs/plans/counter-asic-3-gate/class-v4-signal7-no-flip.json
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
{
|
||||
"pass": true,
|
||||
"expect": "no-flip",
|
||||
"signals": [
|
||||
4,
|
||||
4,
|
||||
3
|
||||
],
|
||||
"checks": {
|
||||
"zero_rejected_by_miners": true,
|
||||
"zero_rejected_by_nodes": true,
|
||||
"sinks_agree": true,
|
||||
"block_counts_agree": true,
|
||||
"miners_agree_on_every_program": true,
|
||||
"window_line_on_every_node": true,
|
||||
"every_node_signals_its_byte": true,
|
||||
"chain_carries_the_bytes": true,
|
||||
"template_never_v4": true,
|
||||
"no_signal_line_on_any_node": true,
|
||||
"ran_the_epochs": true,
|
||||
"v3_programs_seen": true,
|
||||
"signal_share_under_threshold_on_chain": true
|
||||
},
|
||||
"window": 30,
|
||||
"windows": 7,
|
||||
"floor": 100000,
|
||||
"v3_activation": 60,
|
||||
"epoch_blocks": 60,
|
||||
"lead": 10,
|
||||
"first_full_window_epoch": 4,
|
||||
"floor_epoch": 1667,
|
||||
"node": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneumd",
|
||||
"miner": "/Users/joshm/Projects/igneum-wt-ca3-v4-node/vendor/igneum-node-ca3v4/target-ca3v4/release/igneum-miner",
|
||||
"template_switch": null,
|
||||
"run_ended_at_s": 414.3,
|
||||
"final_daa": 420,
|
||||
"max_epoch_seen": 7,
|
||||
"epochs": {
|
||||
"0": {
|
||||
"class": 2,
|
||||
"firstSeenDaa": 0,
|
||||
"at": 4.6,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"1": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 60,
|
||||
"at": 27.7,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"2": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 120,
|
||||
"at": 107.8,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"3": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 182,
|
||||
"at": 159.9,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 0,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"4": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 240,
|
||||
"at": 226,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 6333,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"5": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 300,
|
||||
"at": 286.1,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 6000,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"6": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 361,
|
||||
"at": 350.2,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 5666,
|
||||
"signal_epoch": null
|
||||
},
|
||||
"7": {
|
||||
"class": 3,
|
||||
"firstSeenDaa": 420,
|
||||
"at": 414.3,
|
||||
"eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062",
|
||||
"bps": 6000,
|
||||
"signal_epoch": null
|
||||
}
|
||||
},
|
||||
"blocks": {
|
||||
"total": 426,
|
||||
"before_boundary": 426,
|
||||
"after_boundary": 0,
|
||||
"version_bytes": {
|
||||
"0": 1,
|
||||
"3": 129,
|
||||
"4": 296
|
||||
},
|
||||
"signal_share_bps_on_chain": 6948
|
||||
},
|
||||
"programs": [
|
||||
{
|
||||
"epoch": 0,
|
||||
"class": "v2",
|
||||
"program_id": "8f8806638d59850f",
|
||||
"seed": "234e082d653dc69d",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 1,
|
||||
"class": "v3",
|
||||
"program_id": "769b4dd980c7f126",
|
||||
"seed": "fba8aa7ae82c47e9",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 2,
|
||||
"class": "v3",
|
||||
"program_id": "56335da09deca248",
|
||||
"seed": "64b63eff660aaeec",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 3,
|
||||
"class": "v3",
|
||||
"program_id": "f2f883996849c0e5",
|
||||
"seed": "b0f742cf4d197b15",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 4,
|
||||
"class": "v3",
|
||||
"program_id": "c59d7d33e4749671",
|
||||
"seed": "4bec73e616207ebc",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 5,
|
||||
"class": "v3",
|
||||
"program_id": "8bab4d2320643cc8",
|
||||
"seed": "bf8b384490f61b1a",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 6,
|
||||
"class": "v3",
|
||||
"program_id": "42a5cc579d9dc917",
|
||||
"seed": "9399732456e83970",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
},
|
||||
{
|
||||
"epoch": 7,
|
||||
"class": "v3",
|
||||
"program_id": "7d7f6dfb6df1b584",
|
||||
"seed": "c47f438d5f83e60e",
|
||||
"miners": 3,
|
||||
"disagree": false
|
||||
}
|
||||
],
|
||||
"program_id_rows": [],
|
||||
"accepted_per_miner": [
|
||||
155,
|
||||
141,
|
||||
129
|
||||
],
|
||||
"rejected_by_miners": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rejected_by_nodes": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"sinks": [
|
||||
"5d0d7f21de33c29b",
|
||||
"5d0d7f21de33c29b",
|
||||
"5d0d7f21de33c29b"
|
||||
],
|
||||
"block_counts": [
|
||||
425,
|
||||
425,
|
||||
425
|
||||
],
|
||||
"signal_lines": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"floor_lines": [
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)",
|
||||
"Program class v4 from the override file: active from epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020, epochs of 60 DAA)"
|
||||
],
|
||||
"samples": [
|
||||
{
|
||||
"t": 4.6,
|
||||
"daa": 0,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"0/234e082d",
|
||||
"0/234e082d",
|
||||
"0/234e082d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 19.7,
|
||||
"daa": 42,
|
||||
"epoch": 0,
|
||||
"class": 2,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"42/b78cd510",
|
||||
"42/b78cd510",
|
||||
"42/b78cd510"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 34.7,
|
||||
"daa": 66,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"66/e6e0e6b6",
|
||||
"66/e6e0e6b6",
|
||||
"66/e6e0e6b6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 49.7,
|
||||
"daa": 69,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"69/3e334b41",
|
||||
"69/3e334b41",
|
||||
"69/3e334b41"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 64.7,
|
||||
"daa": 74,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"74/f6732168",
|
||||
"74/f6732168",
|
||||
"74/f6732168"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 79.8,
|
||||
"daa": 91,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"91/4c5172a4",
|
||||
"91/4c5172a4",
|
||||
"91/4c5172a4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 94.8,
|
||||
"daa": 104,
|
||||
"epoch": 1,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"104/8bed6da0",
|
||||
"104/8bed6da0",
|
||||
"104/8bed6da0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 109.8,
|
||||
"daa": 123,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"123/7c7f2a35",
|
||||
"123/7c7f2a35",
|
||||
"123/7c7f2a35"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 124.8,
|
||||
"daa": 134,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"134/11ee9640",
|
||||
"134/11ee9640",
|
||||
"134/11ee9640"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 139.9,
|
||||
"daa": 161,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"161/615ad11d",
|
||||
"161/615ad11d",
|
||||
"161/615ad11d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 154.9,
|
||||
"daa": 172,
|
||||
"epoch": 2,
|
||||
"class": 3,
|
||||
"bps": 0,
|
||||
"nodes": [
|
||||
"172/52e6efa7",
|
||||
"172/52e6efa7",
|
||||
"172/52e6efa7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 169.9,
|
||||
"daa": 195,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"195/d5003862",
|
||||
"195/d5003862",
|
||||
"195/d5003862"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 184.9,
|
||||
"daa": 204,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"204/f43a9613",
|
||||
"204/f43a9613",
|
||||
"204/f43a9613"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 199.9,
|
||||
"daa": 217,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 6333,
|
||||
"nodes": [
|
||||
"217/f2899339",
|
||||
"217/f2899339",
|
||||
"217/f2899339"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 215,
|
||||
"daa": 229,
|
||||
"epoch": 3,
|
||||
"class": 3,
|
||||
"bps": 5333,
|
||||
"nodes": [
|
||||
"229/aa39dc5b",
|
||||
"229/aa39dc5b",
|
||||
"229/aa39dc5b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 230,
|
||||
"daa": 243,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 6333,
|
||||
"nodes": [
|
||||
"243/84160223",
|
||||
"243/84160223",
|
||||
"243/84160223"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 245,
|
||||
"daa": 256,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 5333,
|
||||
"nodes": [
|
||||
"256/95be3208",
|
||||
"256/95be3208",
|
||||
"256/95be3208"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 260,
|
||||
"daa": 274,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 6000,
|
||||
"nodes": [
|
||||
"274/17786bd2",
|
||||
"274/17786bd2",
|
||||
"274/17786bd2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 275.1,
|
||||
"daa": 287,
|
||||
"epoch": 4,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"287/5f1d09c0",
|
||||
"287/5f1d09c0",
|
||||
"287/5f1d09c0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 290.1,
|
||||
"daa": 304,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 6000,
|
||||
"nodes": [
|
||||
"304/b3b30ae6",
|
||||
"304/b3b30ae6",
|
||||
"304/b3b30ae6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 305.1,
|
||||
"daa": 318,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"318/f040c6e4",
|
||||
"318/f040c6e4",
|
||||
"318/f040c6e4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 320.1,
|
||||
"daa": 341,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 6333,
|
||||
"nodes": [
|
||||
"341/34fddad1",
|
||||
"341/34fddad1",
|
||||
"341/34fddad1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 335.2,
|
||||
"daa": 350,
|
||||
"epoch": 5,
|
||||
"class": 3,
|
||||
"bps": 5333,
|
||||
"nodes": [
|
||||
"350/93997324",
|
||||
"350/93997324",
|
||||
"350/93997324"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 350.2,
|
||||
"daa": 361,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"361/a6f64b19",
|
||||
"361/a6f64b19",
|
||||
"361/a6f64b19"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 365.2,
|
||||
"daa": 381,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"381/c5f7f5e5",
|
||||
"381/c5f7f5e5",
|
||||
"381/c5f7f5e5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 380.2,
|
||||
"daa": 395,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 6000,
|
||||
"nodes": [
|
||||
"395/671be986",
|
||||
"395/671be986",
|
||||
"395/671be986"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 395.3,
|
||||
"daa": 404,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 5666,
|
||||
"nodes": [
|
||||
"404/e5f584eb",
|
||||
"404/e5f584eb",
|
||||
"404/e5f584eb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": 410.3,
|
||||
"daa": 417,
|
||||
"epoch": 6,
|
||||
"class": 3,
|
||||
"bps": 6000,
|
||||
"nodes": [
|
||||
"417/ccbc9572",
|
||||
"417/ccbc9572",
|
||||
"417/ccbc9572"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ Status: PROPOSED spec text for spec 01 (a new section 1.12.2 beside the epoch ru
|
|||
1. **The carrier: the block header's `version` field, 2 bytes little-endian.** The low byte is the block version as before (2 on every Igneum network; `block_version_of`). The high byte is the producer's OBJECT VERSION, the highest program class the node that built the template runs: 4 for this binary (`CLASS_SIGNAL_V4`), 0 on every block made before it (`signalled_version(2, 4) = 0x0402`; `class_signal_of`). Why the header and not the coinbase extra data: the tally is read in header validation and by a node that holds headers only (a pruning-proof sync, a headers-first IBD), the header is what GHOSTDAG orders and what the finality rule already reads for its weight (the vote key hash is a header field, `finality.rs`), and the bytes are already there: no new field, no new hash preimage, no proto change for the header. A node before this binary rejects any header whose version is not exactly 2 (`check_header_version`), which is why the signalling binary ships in the same one-sweep rollout as the digest flip it already needs (section 2); from this binary on, only the low byte is checked, so a later object (5, 6) can be signalled to it without another header rule.
|
||||
2. **The weight: blue blocks, the finality rule's convention.** For epoch `e` the anchor is its seed block `S_e`, the last selected-chain block whose DAA score is below `L e - lead` (the block the epoch seed is already taken from, `HeaderProcessor::epoch_seed`; so an epoch's seed and its class are decided at the same block of the same chain). The window is the `W` DAA below and including `S_e`: the selected chain is walked down from `S_e`, every chain block's mergeset blues counted once (the `compute_weights` walk of `finality.rs`, bounded by the merge depth), a blue block counted when its DAA score lies in `(daa(S_e) - W, daa(S_e)]`, and signalling when its object byte is at least 4. Share = signalling / total, in basis points.
|
||||
3. **The decision, per epoch, monotone.** Epoch `e` is class v4 when (a) `L e >= N6`, the floor (the fixed height, rounded up to the epoch boundary exactly as the v3 switch is: `program_class_for_epoch_at`), or (b) epoch `e - 1` was v4, or (c) the window ending at `S_e` is FULL (`daa(S_e) >= W`) and its share is at least 9,500 bps. A signal moves the class one step: the rule answers v4 only where the floor rule answers v3 (below the v3 switch the answer is v2 whatever is signalled). The decision is memoised per seed block, so a fork of the chain has its own entries and one tally is paid per epoch per process. The epoch-boundary rounding of the v2 to v3 switch is unchanged: a class never changes inside an epoch, every block's class is its epoch's.
|
||||
4. **The window `W`: 86,400 DAA (one day of blocks at 1 block/s), `program_class_v4_signal_window_daa` in the override file, in the digest right after the floor; 0 = signalling off, the floor alone (2.0's rule, byte for byte).** Why a day: the share must mean "the fleet that mines, not the fleet that happens to be up this hour", and a day covers every box's daily pattern (the rented boxes come and go by the hour); it is long enough that 95 percent cannot be reached by a burst and short enough that the flip lands within a day of the last upgrade; the finality rule's 30-day window answers a different question (who may vote) and would hold the class for a month after the fleet was ready. On the fast-time profile `W` is 120 (two epochs of 60).
|
||||
4. **The window `W`: 86,400 DAA (one day of blocks at 1 block/s), `program_class_v4_signal_window_daa` in the override file, in the digest once set (the 0.3.15 rule), right after the floor; 0 = signalling off, the floor alone (2.0's rule, byte for byte). REVISED 0.3.16 (Horizon consensus-security): the threshold must hold in EACH of `CLASS_SIGNAL_WINDOWS` = 7 CONSECUTIVE windows ending at the epoch's seed block (a week of days), because one day of 95 percent can be bought for a day (about 19 N of hash for 24 hours) and would force a flip onto a fleet not yet on the object, and seven consecutive days cannot be bought unnoticed; the floor is then set a week past the publish (DAA + 604,800 rounded up), not 14,400. The tally is one walk of `7 W` DAA bucketed per window; the decision rests on the weakest of the seven (`programClassV4SignalWeakestBps`), the console shows the newest (`programClassV4SignalBps`).** Why a day: the share must mean "the fleet that mines, not the fleet that happens to be up this hour", and a day covers every box's daily pattern (the rented boxes come and go by the hour); it is long enough that 95 percent cannot be reached by a burst and short enough that the flip lands within a day of the last upgrade; the finality rule's 30-day window answers a different question (who may vote) and would hold the class for a month after the fleet was ready. On the fast-time profile `W` is 120 (two epochs of 60).
|
||||
5. **The threshold: 9,500 bps (95 percent), a constant (`CLASS_SIGNAL_THRESHOLD_BPS`), not a file field**, so no file can lower it; 95 percent of the blue blocks of a day is 95 percent of the hash rate of that day, the coordinator's figure; a box that cannot mine v4 (an old worker, section 2's wire note) is at most 5 percent of the hash rate at the flip, and the floor catches the rest.
|
||||
6. **The floor `N6`: `program_class_v4_activation_daa`, set at the publish as DAA + 14,400 rounded up to the epoch boundary (the 2.0 rule for N4), checked `N6 - DAA >= 10,800`.** A stalled signal (a fleet that never reaches 95 percent) cannot hold the class forever: at `N6` v4 holds regardless. `never` is allowed in the file and means no floor (the signal alone decides; not for the devnet publish).
|
||||
7. **What a node reports.** `PowEpochInfo` and the template's `powEpoch` carry `programClassV4SignalWindowDaa`, `programClassV4SignalBps` (the share of the window ending at the SINK, the live tally the next decision is heading for), `programClassSignal` (this node's byte) and `programClassV4SignalEpoch` (the epoch v4 was decided by signal on this chain, when it has been); gRPC fields 20 to 23. The daemon prints `Program class v4 signal window from the override file: W DAA ending at each epoch's seed block, threshold 9500 bps of blue blocks; the fixed height is the floor` beside the floor line, and `Program class v4 by miner signal: epoch E (share X bps over W DAA ending at seed block S, threshold 9500 bps, N of M blue blocks)` once per flip.
|
||||
|
|
@ -129,4 +129,15 @@ Two fields join the live object: `program_class_v4_activation_daa` is now the FL
|
|||
|
||||
The first pass of the three good cases (17:01 to 17:20Z) had the same chain behaviour and failed on one harness check of its own (`chain_carries_the_bytes` demanded every byte on the chain be a node's and genesis carries byte 0); the check was corrected to allow the one genesis block and the three cases re-run above. Every number here is a count, a line or an id; the Mac's load average (about 9, other agents' builds) moves the wall times only.
|
||||
|
||||
### 6.5 Seven windows (0.3.16, fork 0760b844): the fast-time gate re-run
|
||||
|
||||
The rule changed on the 0.3.16 branch (Horizon consensus-security): 95 percent in EACH of `CLASS_SIGNAL_WINDOWS = 7` consecutive windows ending at the epoch's seed block, decided on the weakest of the seven; one day of 95 percent can be bought for a day, seven cannot unnoticed. With the harness's 30-DAA window (two per 60-DAA epoch) the seven windows are 210 DAA and the first epoch whose seed block (at 60 e - 10) has 210 DAA below it is epoch 4 (seed at DAA 230), so a flip lands at DAA 240. A floor is REQUIRED for a signalling case since the 0.3.15 canary rule (a node stamps and reads the signal only with both v4 fields set); the first 0.3.16 pass of this harness (20:56Z) ran with the floor at never and every chain byte read 0. The four cases below ran with `--floor 100000` (27 hours of fast-time chain away) or the floor under test, binaries from the fork at 0760b844 (`target-ca3v4`), 6 October 2026, load average 7 to 10 (other agents' builds on the box; counts and ids only here).
|
||||
|
||||
| Case | Run (UTC) | SUMMARY | Summary file |
|
||||
|---|---|---|---|
|
||||
| Two of three signal (`--signal 4,4,3 --floor 100000 --expect no-flip --epochs 7`) | 20:57:5x to 21:04:45 | PASS: no v4 epoch over epochs 0 to 7; the weakest-window share at the sink 5,666 to 6,333 bps from epoch 4 (0 before: fewer than seven windows exist); on the chain 296 blocks byte 4, 129 byte 3, genesis byte 0 (6,948 bps); no signal line on any node; 0 rejected; one sink `5d0d7f21` at 425/425/425 | `counter-asic-3-gate/class-v4-signal7-no-flip.json` |
|
||||
| All three signal (`--signal 4,4,4 --floor 100000 --expect flip`) | 21:04:5x to 21:10:29 | PASS: the share 10,000 bps in every window; the template flipped at epoch 4 (DAA 241 seen, boundary 240), the first epoch with seven full windows, before the floor; 3 of 3 nodes printed `Program class v4 by miner signal: epoch 4 (share 10000 bps over 30 DAA ending at seed block a5adea6f..., threshold 9500 bps in each of 7 consecutive windows, weakest 10000 bps, shares oldest first [10000 x 7], 210 of 210 blue blocks)`; 241 / 124 blocks either side; 0 rejected; one sink `786d8071` at 364/364/364; the id assertion on epochs 4, 5, 6 (miners' id = CLI v4 id, differs from CLI v3 id) | `class-v4-signal7-flip.json` |
|
||||
| Nobody signals, the floor at 360 (`--signal 3,3,3 --floor 360 --expect floor`) | 21:10:3x to 21:18:15 | PASS: share 0 bps in every window (485 blocks byte 3); no signal line; the class flipped at epoch 6 (DAA 362 seen, the floor's boundary 360) and not before; `active from epoch 6` on 3 of 3; 361 / 125 blocks; 0 rejected; one sink `0db7f95e` at 485/485/485; the id assertion on epochs 6, 7, 8 | `class-v4-signal7-floor.json` |
|
||||
| The known-failed case (`--signal 4,4,3 --floor 100000 --expect flip --epochs 7`) | 21:18:17 to 21:25:10 | FAIL as it must: no flip at a weakest-window share of 5,333 to 6,333 bps (two CPU miners of three signalling; 288 blocks byte 4, 135 byte 3 on the chain, 6,792 bps); the harness reports `FAILED CHECK` on nine checks (`template_switched_to_v4`, `switched_at_the_first_full_window_epoch`, `switched_before_the_floor`, `signal_line_on_every_node_same_epoch`, `signal_share_at_or_above_threshold`, `signal_line_names_seven_windows`, `blocks_on_both_sides`, `v4_ids_equal_the_cli_v4_id`, `v4_ids_differ_from_the_same_seed_v3_id`) and exits 1; one sink `1c1eae6d` at 423/423/423 | `class-v4-signal7-failed-case.json` |
|
||||
|
||||
Fork suites on the signalling change (0562a7f2): kaspa-consensus-core 110 + 7 (the signal-rule test, the window in the params, digest and fast-time file tests; the pinned devnet digest re-pinned from `3c505021...` to `7f2e49beabc253f327c5ac6bb457a674ea7f527af2971c95d3bdf65ef8bcf977`), kaspa-consensus lib 98 (the template test now reads the low byte and the signal byte), kaspa-pow with the feature 15; PC 2: section G6 of `node-gates.md`.
|
||||
|
|
|
|||
|
|
@ -4,17 +4,24 @@
|
|||
// so the class v4 decision is made by the miners' blue-block share over the signal window, not by a fixed height.
|
||||
// Ports 29690 and up, network igneum-devnet-969, data /tmp/igneum-fast-time-v4s; the class-v4.mjs shape otherwise:
|
||||
// override-60x.json with CPU genesis bits, v3 from --v3-activation (default 60, epoch 1), the v4 floor at --floor
|
||||
// (default never), the window at --window (default 120 DAA, two epochs; the first epoch whose seed block has DAA >= 120
|
||||
// is epoch 3, seed at DAA 169), one real CPU miner per node.
|
||||
// (default never), the window at --window (default 30 DAA), one real CPU miner per node.
|
||||
//
|
||||
// The rule (0.3.16, Horizon consensus-security): 95 percent in EACH of CLASS_SIGNAL_WINDOWS = 7 consecutive windows
|
||||
// of --window DAA ending at the epoch's seed block (one day of 95 percent can be bought for a day; seven cannot
|
||||
// unnoticed). With the default 30-DAA window (two per 60-DAA epoch) the seven windows are 210 DAA, and the first
|
||||
// epoch whose seed block (at 60 e - 10) has 210 DAA below it is epoch 4 (seed at DAA 230), so the flip is at DAA 240.
|
||||
//
|
||||
// The three cases and the known-failed case:
|
||||
// --signal 4,4,3 --expect no-flip two of three miners signal: 67 percent, the class must stay v3 (run 7 epochs)
|
||||
// --signal 4,4,4 --expect flip all three: it flips at epoch 3, the first boundary with a full window
|
||||
// --signal 3,3,3 --floor 300 --expect floor nobody signals: it flips at the floor (epoch 5, DAA 300) and not before
|
||||
// --signal 4,4,3 --expect flip the known-failed case: the harness must report FAIL (no flip happened)
|
||||
// --signal 4,4,3 --floor 100000 --expect no-flip two of three miners signal: 67 percent, the class must stay v3 (run 7 epochs)
|
||||
// --signal 4,4,4 --floor 100000 --expect flip all three: it flips at epoch 4, the first boundary with seven full windows
|
||||
// --signal 3,3,3 --floor 360 --expect floor nobody signals: it flips at the floor (epoch 6, DAA 360) and not before
|
||||
// --signal 4,4,3 --floor 100000 --expect flip the known-failed case: the harness must report FAIL (no flip happened)
|
||||
// The floor is REQUIRED for a signalling case: since the 0.3.15 canary rule a node stamps and reads the signal only with
|
||||
// both v4 fields set (the window and a floor), so a floor at never means nobody signals (the first 0.3.16 run of this
|
||||
// harness, 20:56Z: chain bytes all 0); a far floor (100,000 DAA, 27 hours of fast-time chain) keeps it out of the run.
|
||||
//
|
||||
// node infra/fast-time/class-v4-signal.mjs --signal a,b,c --expect flip|no-flip|floor [--floor <daa>|never]
|
||||
// [--window 120] [--v3-activation 60] [--secs 480] [--epochs 7]
|
||||
// [--window 30] [--v3-activation 60] [--secs 480] [--epochs 7]
|
||||
// IGNEUMD, IGNEUM_MINER, IGNEUM_POW name the binaries (defaults: the ca3 fork worktree's target-ca3v4/release and
|
||||
// igneum-pow/target/release/igneum-pow).
|
||||
|
||||
|
|
@ -41,7 +48,8 @@ const SECS = flag('secs', 480);
|
|||
const EPOCHS = flag('epochs', 7);
|
||||
const FLOOR = actflag('floor', null);
|
||||
const V3_ACTIVATION = actflag('v3-activation', 60);
|
||||
const WINDOW = flag('window', 120);
|
||||
const WINDOW = flag('window', 30);
|
||||
const WINDOWS = 7; // CLASS_SIGNAL_WINDOWS in the node
|
||||
const SIGNAL = (sflag('signal') || '4,4,4').split(',').map(Number);
|
||||
const EXPECT = sflag('expect') || 'flip';
|
||||
if (!['flip', 'no-flip', 'floor'].includes(EXPECT) || SIGNAL.length !== 3) { console.error('usage: --signal a,b,c --expect flip|no-flip|floor'); process.exit(2); }
|
||||
|
|
@ -58,9 +66,9 @@ const LEAD = field('pow_epoch_lead');
|
|||
const DAY_MS = field('pow_day_ms');
|
||||
const FIRST_V3_EPOCH = V3_ACTIVATION == null ? null : Math.ceil(V3_ACTIVATION / EPOCH);
|
||||
const FLOOR_EPOCH = FLOOR == null ? null : Math.ceil(FLOOR / EPOCH);
|
||||
// the first epoch whose seed block (the last chain block below L*e - lead) can have DAA >= WINDOW: L*e - lead - 1 >= WINDOW
|
||||
// the first epoch whose seed block (the last chain block below L*e - lead) has WINDOWS x WINDOW DAA below it
|
||||
let FIRST_FULL_EPOCH = 0;
|
||||
while (FIRST_FULL_EPOCH * EPOCH - LEAD - 1 < WINDOW) FIRST_FULL_EPOCH++;
|
||||
while (FIRST_FULL_EPOCH * EPOCH - LEAD - 1 < WINDOWS * WINDOW) FIRST_FULL_EPOCH++;
|
||||
export function mergeOverrideText(text, fields) {
|
||||
let out = text;
|
||||
for (const k of Object.keys(fields)) out = out.replace(new RegExp(`\\s*"${k}":\\s*[^,}\\n]+,?`), '');
|
||||
|
|
@ -70,7 +78,7 @@ export function mergeOverrideText(text, fields) {
|
|||
const asText = (v) => v == null ? NEVER : String(v);
|
||||
const override = `${TMP}/override.json`;
|
||||
writeFileSync(override, mergeOverrideText(baseText, { genesis_bits: GENESIS_BITS, skip_proof_of_work: false, program_class_v3_activation_daa: asText(V3_ACTIVATION), program_class_v4_activation_daa: asText(FLOOR), program_class_v4_signal_window_daa: String(WINDOW) }));
|
||||
log(`signals ${SIGNAL.join('/')}, expect ${EXPECT}; v3 from ${V3_ACTIVATION ?? 'never'} (epoch ${FIRST_V3_EPOCH ?? 'none'}), v4 floor ${FLOOR ?? 'never'} (epoch ${FLOOR_EPOCH ?? 'none'}), window ${WINDOW} DAA (the first epoch with a full window is ${FIRST_FULL_EPOCH}); ${EPOCH} DAA per epoch, lead ${LEAD}; run ${SECS} s or ${EPOCHS} epochs`);
|
||||
log(`signals ${SIGNAL.join('/')}, expect ${EXPECT}; v3 from ${V3_ACTIVATION ?? 'never'} (epoch ${FIRST_V3_EPOCH ?? 'none'}), v4 floor ${FLOOR ?? 'never'} (epoch ${FLOOR_EPOCH ?? 'none'}), window ${WINDOW} DAA x ${WINDOWS} consecutive (the first epoch with seven full windows is ${FIRST_FULL_EPOCH}); ${EPOCH} DAA per epoch, lead ${LEAD}; run ${SECS} s or ${EPOCHS} epochs`);
|
||||
|
||||
class Node {
|
||||
constructor(i, connect = []) {
|
||||
|
|
@ -109,7 +117,7 @@ async function stopAll() {
|
|||
process.on('SIGINT', async () => { await stopAll(); process.exit(130); });
|
||||
process.on('unhandledRejection', async (e) => { log(`FAILED: ${e?.stack || e}`); await stopAll(); process.exit(3); });
|
||||
const minerLog = (i) => { try { return readFileSync(`${TMP}/cpu${i}.log`, 'utf8').split('\n'); } catch { return []; } };
|
||||
const SIGNAL_LINE = /Program class v4 by miner signal: epoch (\d+) \(share (\d+) bps/;
|
||||
const SIGNAL_LINE = /Program class v4 by miner signal: epoch (\d+) \(share (\d+) bps over \d+ DAA ending at seed block \S+, threshold \d+ bps in each of (\d+) consecutive windows, weakest (\d+) bps/;
|
||||
const FLOOR_LINE = /Program class v4 from the override file/;
|
||||
const WINDOW_LINE = /Program class v4 signal window from the override file/;
|
||||
const OWN_LINE = /Program class signal from IGNEUM_CLASS_SIGNAL: this node signals object version (\d+)/;
|
||||
|
|
@ -135,7 +143,7 @@ while (Date.now() - t0 < SECS * 1000) {
|
|||
const t = await n0.rpc.call('getBlockTemplate', { payAddress: pay, extraData: [] });
|
||||
const pe = t.powEpoch || t.pow_epoch || {};
|
||||
daa = pe.virtualDaaScore ?? t.block?.header?.daaScore; epoch = pe.epochIndex; cls = pe.programClass; nextCls = pe.nextProgramClass;
|
||||
eraSeed = pe.eraSeed; bps = pe.programClassV4SignalBps; win = pe.programClassV4SignalWindowDaa; sig = pe.programClassSignal; sigEpoch = pe.programClassV4SignalEpoch;
|
||||
eraSeed = pe.eraSeed; bps = pe.programClassV4SignalWeakestBps ?? pe.programClassV4SignalBps; win = pe.programClassV4SignalWindowDaa; sig = pe.programClassSignal; sigEpoch = pe.programClassV4SignalEpoch;
|
||||
} catch (e) { log(`template: ${e.message}`); }
|
||||
if (epoch != null && epoch !== lastEpoch) {
|
||||
epochs.set(epoch, { class: cls, firstSeenDaa: daa, at: +since(), eraSeed: eraSeed == null ? null : String(eraSeed), bps, signal_epoch: sigEpoch ?? null });
|
||||
|
|
@ -204,7 +212,8 @@ const rejectedMiner = [0, 1, 2].map(i => minerLog(i).filter(l => /rejected nonce
|
|||
const rejectedNode = nodes.map(n => n.grepLog(/PoW rejected|Rejected block|rejected block/i));
|
||||
const signalLines = nodes.map(n => n.grepLog(SIGNAL_LINE).map(l => l.replace(/^.*?(Program class v4 by miner signal)/, '$1'))[0] || null);
|
||||
const signalEpochs = signalLines.map(l => { const m = l && SIGNAL_LINE.exec(l); return m ? +m[1] : null; });
|
||||
const signalShares = signalLines.map(l => { const m = l && SIGNAL_LINE.exec(l); return m ? +m[2] : null; });
|
||||
const signalShares = signalLines.map(l => { const m = l && SIGNAL_LINE.exec(l); return m ? +m[4] : null; }); // the weakest of the seven
|
||||
const signalWindows = signalLines.map(l => { const m = l && SIGNAL_LINE.exec(l); return m ? +m[3] : null; });
|
||||
const floorLines = nodes.map(n => n.grepLog(FLOOR_LINE).map(l => l.replace(/^.*?(Program class v4 from)/, '$1'))[0] || null);
|
||||
const sinks = dag.map(d => String(d.sink || '?').slice(0, 16));
|
||||
const counts = dag.map(d => d.blockCount ?? '?');
|
||||
|
|
@ -231,6 +240,7 @@ if (EXPECT === 'flip') {
|
|||
switched_before_the_floor: firstV4 != null && (FLOOR_EPOCH == null || firstV4.epoch < FLOOR_EPOCH),
|
||||
signal_line_on_every_node_same_epoch: signalEpochs.every(e => e != null) && new Set(signalEpochs).size === 1 && signalEpochs[0] === (firstV4 && firstV4.epoch),
|
||||
signal_share_at_or_above_threshold: signalShares.every(s => s != null && s >= 9500),
|
||||
signal_line_names_seven_windows: signalWindows.every(w => w === WINDOWS),
|
||||
blocks_on_both_sides: before.length > 0 && after.length > 0,
|
||||
v4_ids_equal_the_cli_v4_id: idRows.length > 0 && idRows.every(r => r.cli_v4 != null && r.cli_v4 === r.miners_id && r.miners === 3),
|
||||
v4_ids_differ_from_the_same_seed_v3_id: idRows.length > 0 && idRows.every(r => r.cli_v3 != null && r.cli_v3 !== r.miners_id),
|
||||
|
|
@ -257,7 +267,7 @@ if (EXPECT === 'flip') {
|
|||
}
|
||||
const pass = Object.values(checks).every(Boolean);
|
||||
const summary = {
|
||||
pass, expect: EXPECT, signals: SIGNAL, checks, window: WINDOW, floor: FLOOR ?? 'never', v3_activation: V3_ACTIVATION ?? 'never', epoch_blocks: EPOCH, lead: LEAD, first_full_window_epoch: FIRST_FULL_EPOCH, floor_epoch: FLOOR_EPOCH,
|
||||
pass, expect: EXPECT, signals: SIGNAL, checks, window: WINDOW, windows: WINDOWS, floor: FLOOR ?? 'never', v3_activation: V3_ACTIVATION ?? 'never', epoch_blocks: EPOCH, lead: LEAD, first_full_window_epoch: FIRST_FULL_EPOCH, floor_epoch: FLOOR_EPOCH,
|
||||
node: IGNEUMD, miner: CPU_MINER, template_switch: firstV4, run_ended_at_s: endAt, final_daa: lastDaa, max_epoch_seen: maxEpochSeen,
|
||||
epochs: Object.fromEntries([...epochs.entries()].map(([k, v]) => [k, v])),
|
||||
blocks: { total: blocks.length, before_boundary: before.length, after_boundary: after.length, version_bytes: versionBytes, signal_share_bps_on_chain: signalShareOnChain },
|
||||
|
|
|
|||
279
infra/fast-time/difficulty-v3.mjs
Normal file
279
infra/fast-time/difficulty-v3.mjs
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
#!/usr/bin/env node
|
||||
// Horizon lane 5, proposal 2 (docs/analysis/horizon/network.md 5.4 and 6): the difficulty controller against a
|
||||
// relay-delayed DAG. Three nodes in a star, the two spokes reaching the hub through a TCP proxy that holds every byte
|
||||
// for --delay-ms in each direction (the handshake's first --handshake-ms pass undelayed: the p2p version exchange
|
||||
// times out at 4 s, protocol/p2p/src/handshake.rs), one real CPU miner per node, override-60x.json re-rated to --bps.
|
||||
// A block crosses a link in three legs (inv, request, block: Kaspa's relay flow), so the document's propagation
|
||||
// delay d (--propagation-ms, 3,000 or 30,000) is one third per leg: --delay-ms defaults to --propagation-ms / 3.
|
||||
//
|
||||
// The claim under test: under rule v3 (difficulty_v3_activation_daa 0: every chain step counts every merged block's
|
||||
// work over the real span, the clock cap and lag bound in DAA seconds, m x 20 s per merging step) the DAG rate holds
|
||||
// the target and the difficulty tracks the miners' hash within 10 percent after --measure-from seconds; under the
|
||||
// live rule (v2: blue work over a 20 T capped step) a 3-s delay at 10 bps settles near 6.67 blocks/s with the
|
||||
// difficulty 1.5x the hash-implied value (controller.py), which is this harness's known-failed case.
|
||||
//
|
||||
// The cases (each --secs 900, measured from --measure-from 600):
|
||||
// --bps 10 --propagation-ms 3000 --rule v3 --expect pass the proposal's first case
|
||||
// --bps 1 --propagation-ms 30000 --rule v3 --expect pass the proposal's second case
|
||||
// --bps 10 --propagation-ms 3000 --rule v2 --expect fail the known-failed case: the harness must report FAIL
|
||||
//
|
||||
// Pass = |DAG rate / target - 1| <= 0.10 over the measured window AND |expected hashes per block / (hash x T) - 1|
|
||||
// <= 0.10 averaged over the window, where expected hashes per block come from the sink's bits (2^256 / (target + 1))
|
||||
// and hash is the sum of the three miners' own `hash=... MH/s` status lines (every 30 s). The red share, the chain
|
||||
// step spacing and the three nodes' block counts are reported, not judged.
|
||||
//
|
||||
// node infra/fast-time/difficulty-v3.mjs --bps 10 --propagation-ms 3000 --rule v3 --expect pass [--secs 900] [--delay-ms <per leg>]
|
||||
// [--measure-from 600] [--genesis-bits 0x1f080000] [--handshake-ms 5000] [--out docs/plans/counter-asic-3-gate/difficulty-v3-<case>.json]
|
||||
// IGNEUMD, IGNEUM_MINER name the binaries (defaults: vendor/igneum-node-0316/target-0316/release).
|
||||
|
||||
import { spawn } from 'node:child_process';
|
||||
import { createServer, connect as netConnect } from 'node:net';
|
||||
import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync } from 'node:fs';
|
||||
import { connectRpc } from '../../tools/finality-attacks/lib/rpc.mjs';
|
||||
import { devAddress } from '../../tools/harness/lib/address.mjs';
|
||||
|
||||
const ROOT = new URL('../../', import.meta.url).pathname;
|
||||
const FILE = `${ROOT}infra/fast-time/override-60x.json`;
|
||||
const BIN = process.env.IGNEUM_0316_BIN || `${ROOT}vendor/igneum-node-0316/target-0316/release`;
|
||||
const IGNEUMD = process.env.IGNEUMD || `${BIN}/igneumd`;
|
||||
const CPU_MINER = process.env.IGNEUM_MINER || `${BIN}/igneum-miner`;
|
||||
const TMP = '/tmp/igneum-fast-time-dv3';
|
||||
const BASE = 29790, SUFFIX = 979;
|
||||
const NEVER = '18446744073709551615';
|
||||
const args = process.argv.slice(2);
|
||||
const flag = (name, dflt) => { const i = args.indexOf(`--${name}`); return i >= 0 ? Number(args[i + 1]) : dflt; };
|
||||
const sflag = (name) => { const i = args.indexOf(`--${name}`); return i >= 0 ? args[i + 1] : null; };
|
||||
const BPS = flag('bps', 10);
|
||||
const PROPAGATION_MS = flag('propagation-ms', 3000);
|
||||
const DELAY_MS = flag('delay-ms', Math.round(PROPAGATION_MS / 3));
|
||||
const RULE = sflag('rule') || 'v3';
|
||||
const EXPECT = sflag('expect') || 'pass';
|
||||
const SECS = flag('secs', 900);
|
||||
const MEASURE_FROM = flag('measure-from', 600);
|
||||
const HANDSHAKE_MS = flag('handshake-ms', 5000);
|
||||
const GENESIS_BITS = flag('genesis-bits', BPS >= 10 ? 0x1f080000 : 0x1f010000); // 2^13 hashes per block at 10 bps, 2^16 at 1 bps (mantissa x 2^224)
|
||||
const CASE = sflag('case') || `${BPS}bps-d${PROPAGATION_MS}ms-${RULE}`;
|
||||
const OUT = sflag('out') || `${ROOT}docs/plans/counter-asic-3-gate/difficulty-v3-${CASE}.json`;
|
||||
if (!['v2', 'v3'].includes(RULE) || !['pass', 'fail'].includes(EXPECT) || ![1, 10].includes(BPS)) { console.error('usage: --bps 1|10 --delay-ms <ms> --rule v2|v3 --expect pass|fail'); process.exit(2); }
|
||||
const T_MS = 1000 / BPS;
|
||||
const started = [];
|
||||
const log = (...a) => console.log(new Date().toISOString().slice(11, 23), ...a);
|
||||
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||
for (const b of [IGNEUMD, CPU_MINER]) if (!existsSync(b)) { console.error(`missing ${b}`); process.exit(2); }
|
||||
|
||||
rmSync(TMP, { recursive: true, force: true }); mkdirSync(TMP, { recursive: true });
|
||||
|
||||
// The override file is merged as TEXT (a never height is beyond a JavaScript number; class-v4.mjs has the history).
|
||||
const baseText = readFileSync(FILE, 'utf8');
|
||||
const field = (name) => { const m = new RegExp(`"${name}":\\s*([0-9]+)`).exec(baseText); return m ? +m[1] : undefined; };
|
||||
export function mergeOverrideText(text, fields) {
|
||||
let out = text;
|
||||
for (const k of Object.keys(fields)) out = out.replace(new RegExp(`\\s*"${k}":\\s*[^,}\\n]+,?`), '');
|
||||
const extra = Object.entries(fields).map(([k, v]) => `"${k}": ${typeof v === 'string' && !/^\d+$/.test(v) ? JSON.stringify(v) : v}`).join(', ');
|
||||
return out.replace(/,?\s*}\s*$/, `,\n ${extra}\n}\n`);
|
||||
}
|
||||
// The block-rate block (the file's is 1 bps). At 10 bps: docs/override-params.md's 10 bps example for k, parents,
|
||||
// mergeset limit and the sample rates; the depths are the file's x10 (merge 600, finality 7,200, pruning 138,380,
|
||||
// above the Prunality bound 2F + 4 M k + 2k + 2 = 137,658); the PoW epoch 600 DAA with lead 100 so an epoch stays
|
||||
// 60 s of wall time and the CPU miners regenerate their program as often as at 1 bps.
|
||||
export function rerateBlockrate(text, bps) {
|
||||
if (bps === 1) return text;
|
||||
const block = `"blockrate": {
|
||||
"target_time_per_block": 100,
|
||||
"ghostdag_k": 124,
|
||||
"past_median_time_sample_rate": 10,
|
||||
"difficulty_sample_rate": 2,
|
||||
"max_block_parents": 16,
|
||||
"mergeset_size_limit": 248,
|
||||
"merge_depth": 600,
|
||||
"finality_depth": 7200,
|
||||
"pruning_depth": 138380,
|
||||
"coinbase_maturity": 20
|
||||
}`;
|
||||
return text.replace(/"blockrate":\s*\{[^}]*\}/, block);
|
||||
}
|
||||
const EPOCH = BPS === 1 ? field('pow_epoch_blocks') : 600;
|
||||
const LEAD = BPS === 1 ? field('pow_epoch_lead') : 100;
|
||||
const DAY_MS = field('pow_day_ms');
|
||||
const override = `${TMP}/override.json`;
|
||||
writeFileSync(override, mergeOverrideText(rerateBlockrate(baseText, BPS), {
|
||||
genesis_bits: GENESIS_BITS, skip_proof_of_work: false, pow_epoch_blocks: EPOCH, pow_epoch_lead: LEAD,
|
||||
difficulty_v2_activation_daa: '0', difficulty_v3_activation_daa: RULE === 'v3' ? '0' : NEVER,
|
||||
program_class_v3_activation_daa: NEVER, program_class_v4_activation_daa: NEVER,
|
||||
}));
|
||||
log(`case ${CASE}: ${BPS} bps (T ${T_MS} ms), propagation ${PROPAGATION_MS} ms as a proxy delay of ${DELAY_MS} ms per leg each way (handshake ${HANDSHAKE_MS} ms undelayed), rule ${RULE}, genesis bits 0x${GENESIS_BITS.toString(16)} (${expectedHashes(GENESIS_BITS).toExponential(3)} hashes per block), ${SECS} s measured from ${MEASURE_FROM} s, expect ${EXPECT}`);
|
||||
|
||||
// ---- the delay proxy ----
|
||||
// Every chunk in each direction is written to the other side DELAY_MS after it arrived (timers of one delay fire in
|
||||
// order, so the byte order holds); the first HANDSHAKE_MS of a connection pass undelayed. Kaspa's flows wait up to
|
||||
// 120 s (protocol/p2p/src/common.rs DEFAULT_TIMEOUT), so a 30-s delay (60-s round trip) fits inside them.
|
||||
class DelayProxy {
|
||||
constructor(listenPort, targetPort) { this.listenPort = listenPort; this.targetPort = targetPort; this.conns = 0; this.bytes = 0; }
|
||||
start() {
|
||||
return new Promise((resolve) => {
|
||||
this.server = createServer((client) => {
|
||||
this.conns++;
|
||||
const opened = Date.now();
|
||||
const upstream = netConnect(this.targetPort, '127.0.0.1');
|
||||
const pipeDelayed = (from, to) => {
|
||||
from.on('data', (chunk) => {
|
||||
this.bytes += chunk.length;
|
||||
const wait = Date.now() - opened < HANDSHAKE_MS ? 0 : DELAY_MS;
|
||||
setTimeout(() => { if (!to.destroyed) to.write(chunk); }, wait);
|
||||
});
|
||||
from.on('end', () => setTimeout(() => { if (!to.destroyed) to.end(); }, DELAY_MS));
|
||||
from.on('error', () => { if (!to.destroyed) to.destroy(); });
|
||||
from.on('close', () => setTimeout(() => { if (!to.destroyed) to.destroy(); }, DELAY_MS + 1000));
|
||||
};
|
||||
pipeDelayed(client, upstream);
|
||||
pipeDelayed(upstream, client);
|
||||
});
|
||||
this.server.listen(this.listenPort, '127.0.0.1', () => resolve(this));
|
||||
});
|
||||
}
|
||||
stop() { try { this.server?.close(); } catch { } }
|
||||
}
|
||||
|
||||
class Node {
|
||||
constructor(i, connect = []) {
|
||||
this.i = i; this.grpcPort = BASE + i * 10; this.p2pPort = BASE + i * 10 + 1; this.jsonPort = BASE + i * 10 + 2;
|
||||
this.connect = connect; this.dir = `${TMP}/n${i}`; this.logFile = `${this.dir}/node.log`;
|
||||
}
|
||||
get grpc() { return `grpc://127.0.0.1:${this.grpcPort}`; }
|
||||
async start() {
|
||||
mkdirSync(this.dir, { recursive: true });
|
||||
const a = ['--devnet', `--devnet-suffix=${SUFFIX}`, '--nodnsseed', '--disable-upnp', '--nologfiles', '--enable-unsynced-mining', '--utxoindex',
|
||||
`--appdir=${this.dir}`, `--rpclisten=127.0.0.1:${this.grpcPort}`, `--rpclisten-json=127.0.0.1:${this.jsonPort}`,
|
||||
`--listen=127.0.0.1:${this.p2pPort}`, `--override-params-file=${override}`, '--loglevel=info', '--yes'];
|
||||
if (this.connect.length) a.push(`--connect=${this.connect.join(',')}`); else a.push('--outpeers=0');
|
||||
const out = openSync(this.logFile, 'a');
|
||||
this.proc = spawn(IGNEUMD, a, { stdio: ['ignore', out, out] });
|
||||
started.push(this.proc);
|
||||
await sleep(1500);
|
||||
if (this.proc.exitCode != null) throw new Error(`n${this.i} exited ${this.proc.exitCode}: ${this.grepLog(/ERROR|Error|error|refused|invalid/).slice(-3).join(' | ')}`);
|
||||
this.rpc = await connectRpc(`ws://127.0.0.1:${this.jsonPort}`);
|
||||
log(`n${this.i} up pid ${this.proc.pid} json ${this.jsonPort} p2p ${this.p2pPort}${this.connect.length ? ` via proxy ${this.connect.join(',')}` : ''}`);
|
||||
return this;
|
||||
}
|
||||
grepLog(re) { try { return readFileSync(this.logFile, 'utf8').split('\n').filter(l => re.test(l)); } catch { return []; } }
|
||||
}
|
||||
function miner(bin, argv, name, env = {}) {
|
||||
const out = openSync(`${TMP}/${name}.log`, 'a');
|
||||
const p = spawn(bin, argv, { stdio: ['ignore', out, out], env: { ...process.env, ...env } });
|
||||
started.push(p);
|
||||
return p;
|
||||
}
|
||||
const proxies = [];
|
||||
async function stopAll() {
|
||||
for (const p of started.reverse()) { try { p.kill('SIGINT'); } catch { } }
|
||||
await sleep(1500);
|
||||
for (const p of started) { try { p.kill('SIGKILL'); } catch { } }
|
||||
for (const x of proxies) x.stop();
|
||||
}
|
||||
process.on('SIGINT', async () => { await stopAll(); process.exit(130); });
|
||||
process.on('unhandledRejection', async (e) => { log(`FAILED: ${e?.stack || e}`); await stopAll(); process.exit(3); });
|
||||
|
||||
// bits -> expected hashes per block: target = mantissa x 2^(8 (exponent - 3)); hashes = 2^256 / (target + 1)
|
||||
export function expectedHashes(bits) {
|
||||
const exp = BigInt(bits >>> 24), mant = BigInt(bits & 0xffffff);
|
||||
const target = exp <= 3n ? mant >> (8n * (3n - exp)) : mant << (8n * (exp - 3n));
|
||||
const ratio = (1n << 256n) / (target + 1n);
|
||||
return Number(ratio);
|
||||
}
|
||||
const minerHash = (i) => { // the newest `hash=<x> MH/s` status line of miner i, in hashes per second
|
||||
let v = null;
|
||||
try { for (const l of readFileSync(`${TMP}/cpu${i}.log`, 'utf8').split('\n')) { const m = /hash=([\d.]+) MH\/s/.exec(l); if (m) v = +m[1] * 1e6; } } catch { }
|
||||
return v;
|
||||
};
|
||||
|
||||
const n0 = await new Node(0).start();
|
||||
const p1 = await new DelayProxy(BASE + 101, n0.p2pPort).start(); proxies.push(p1);
|
||||
const p2 = await new DelayProxy(BASE + 102, n0.p2pPort).start(); proxies.push(p2);
|
||||
const n1 = await new Node(1, [`127.0.0.1:${p1.listenPort}`]).start();
|
||||
const n2 = await new Node(2, [`127.0.0.1:${p2.listenPort}`]).start();
|
||||
const nodes = [n0, n1, n2];
|
||||
await sleep(3000);
|
||||
for (const n of nodes) { const d = await n.rpc.call('getBlockDagInfo'); log(`n${n.i} network ${d.network ?? d.networkName} blocks ${d.blockCount} difficulty ${d.difficulty} (bits ${d.difficulty * 2} hashes per block)`); }
|
||||
const peers = await Promise.all(nodes.map(async n => { try { const r = await n.rpc.call('getConnectedPeerInfo'); const arr = Object.values(r).find(Array.isArray); return arr ? arr.length : '?'; } catch { return '?'; } }));
|
||||
log(`peers per node ${peers.join(' ')} (hub 2, spokes 1)`);
|
||||
nodes.forEach((n, i) => miner(CPU_MINER, ['mine', n.grpc, '1', String(SECS + 30), `cpu${i}`, '--engine', 'igneum-pow', '--payout-label', `cpu${i}`, '--status-secs', '30', '--no-vote'], `cpu${i}`, { IGNEUM_POW_DAY_MS: String(DAY_MS) }));
|
||||
void devAddress('fast-time-dv3');
|
||||
|
||||
const t0 = Date.now();
|
||||
const since = () => ((Date.now() - t0) / 1000).toFixed(1);
|
||||
const samples = [];
|
||||
let lastReport = 0, measureStart = null;
|
||||
while (Date.now() - t0 < SECS * 1000) {
|
||||
await sleep(5000);
|
||||
const dag = await Promise.all(nodes.map(async n => { try { return await n.rpc.call('getBlockDagInfo'); } catch (e) { return null; } }));
|
||||
let bits = null;
|
||||
try { const b = await n0.rpc.call('getBlock', { hash: dag[0].sink, includeTransactions: false }); bits = +b.block.header.bits; } catch { }
|
||||
const hashes = [0, 1, 2].map(minerHash);
|
||||
const hashSum = hashes.every(h => h != null) ? hashes.reduce((a, b) => a + b, 0) : null;
|
||||
const expected = bits == null ? null : expectedHashes(bits);
|
||||
const implied = hashSum == null ? null : hashSum * T_MS / 1000;
|
||||
const s = { t: +since(), blocks: dag.map(d => d?.blockCount ?? null), daa: dag[0]?.virtualDaaScore ?? null, difficulty: dag[0]?.difficulty ?? null, bits, expected_hashes: expected, miner_hash: hashSum, hash_implied: implied, ratio: expected != null && implied ? expected / implied : null };
|
||||
samples.push(s);
|
||||
if (measureStart == null && s.t >= MEASURE_FROM && s.blocks[0] != null) measureStart = s;
|
||||
if (Date.now() - lastReport > 30000) {
|
||||
lastReport = Date.now();
|
||||
const rate = samples.length > 6 ? ((s.blocks[0] - samples.at(-7).blocks[0]) / (s.t - samples.at(-7).t)).toFixed(2) : '?';
|
||||
log(`t=${since()} s blocks ${s.blocks.join('/')} daa ${s.daa} rate(30s) ${rate}/s bits 0x${(bits ?? 0).toString(16)} expected ${expected?.toExponential(3)} hashes/block, miners ${hashSum == null ? '?' : (hashSum / 1e3).toFixed(1) + ' kH/s'} implied ${implied?.toExponential(3)} ratio ${s.ratio?.toFixed(3)}`);
|
||||
}
|
||||
}
|
||||
await sleep(2000);
|
||||
|
||||
// ---- the reading ----
|
||||
const end = samples.at(-1);
|
||||
const measured = samples.filter(s => s.t >= MEASURE_FROM && s.ratio != null);
|
||||
const dagRate = measureStart && end.blocks[0] != null ? (end.blocks[0] - measureStart.blocks[0]) / (end.t - measureStart.t) : null;
|
||||
const rateOff = dagRate == null ? null : dagRate / BPS - 1;
|
||||
const ratioMean = measured.length ? measured.reduce((a, s) => a + s.ratio, 0) / measured.length : null;
|
||||
const diffOff = ratioMean == null ? null : ratioMean - 1;
|
||||
// the red share and the chain step spacing from the hub's blocks since the measured window began
|
||||
let reds = 0, chainBlocks = 0, merged = 0, spacings = [];
|
||||
try {
|
||||
const info = await n0.rpc.call('getBlockDagInfo');
|
||||
let low = info.pruningPointHash; const seen = new Set(); let prevChainClock = null;
|
||||
for (let round = 0; round < 400; round++) {
|
||||
const r = await n0.rpc.call('getBlocks', { lowHash: low, includeBlocks: true, includeTransactions: false });
|
||||
const blocks = r.blocks || []; let added = 0;
|
||||
for (const b of blocks) {
|
||||
const h = b.verboseData?.hash || b.header?.hash; if (seen.has(h)) continue; seen.add(h); added++;
|
||||
if (!b.verboseData?.isChainBlock) continue;
|
||||
const tMs = +b.header.timestamp;
|
||||
if (tMs < t0 + MEASURE_FROM * 1000) continue;
|
||||
chainBlocks++; reds += (b.verboseData.mergeSetRedsHashes || []).length; merged += (b.verboseData.mergeSetBluesHashes || []).length + (b.verboseData.mergeSetRedsHashes || []).length;
|
||||
if (prevChainClock != null) spacings.push(tMs - prevChainClock); prevChainClock = tMs;
|
||||
}
|
||||
if (!blocks.length || added === 0) break;
|
||||
low = (r.blockHashes || []).at(-1) || blocks.at(-1).verboseData?.hash; if (!low) break;
|
||||
}
|
||||
} catch (e) { log(`getBlocks: ${e.message}`); }
|
||||
spacings.sort((a, b) => a - b);
|
||||
const median = spacings.length ? spacings[Math.floor(spacings.length / 2)] : null;
|
||||
const checks = {
|
||||
measured_window_present: measured.length >= 10,
|
||||
dag_rate_within_10pct: rateOff != null && Math.abs(rateOff) <= 0.10,
|
||||
difficulty_within_10pct_of_hash: diffOff != null && Math.abs(diffOff) <= 0.10,
|
||||
three_nodes_within_5pct_blocks: end.blocks.every(b => b != null) && Math.max(...end.blocks) - Math.min(...end.blocks) <= 0.05 * Math.max(...end.blocks),
|
||||
};
|
||||
const good = checks.measured_window_present && checks.dag_rate_within_10pct && checks.difficulty_within_10pct_of_hash;
|
||||
const pass = EXPECT === 'pass' ? good : !good;
|
||||
const summary = {
|
||||
pass, expect: EXPECT, case: CASE, bps: BPS, target_time_ms: T_MS, propagation_ms: PROPAGATION_MS, delay_ms_per_leg: DELAY_MS, handshake_ms: HANDSHAKE_MS, rule: RULE, genesis_bits: GENESIS_BITS, secs: SECS, measure_from: MEASURE_FROM,
|
||||
checks, dag_rate_measured: dagRate, dag_rate_off: rateOff, difficulty_over_hash_implied_mean: ratioMean, difficulty_off: diffOff,
|
||||
measured_samples: measured.length, end_blocks: end.blocks, end_daa: end.daa, end_bits: end.bits, end_expected_hashes: end.expected_hashes, end_miner_hash: end.miner_hash,
|
||||
chain_blocks_measured: chainBlocks, merged_blocks_measured: merged, red_blocks_measured: reds, red_share: merged ? reds / merged : null,
|
||||
chain_step_spacing_ms: { median, p90: spacings.length ? spacings[Math.floor(spacings.length * 0.9)] : null, max: spacings.at(-1) ?? null },
|
||||
proxy: { connections: p1.conns + p2.conns, bytes: p1.bytes + p2.bytes },
|
||||
node: IGNEUMD, miner: CPU_MINER, samples,
|
||||
};
|
||||
mkdirSync(OUT.replace(/\/[^/]+$/, ''), { recursive: true });
|
||||
writeFileSync(OUT, JSON.stringify(summary, null, 2));
|
||||
writeFileSync(`${TMP}/summary.json`, JSON.stringify(summary, null, 2));
|
||||
const fails = Object.entries(checks).filter(([, v]) => !v).map(([k]) => k);
|
||||
log(`SUMMARY ${pass ? 'PASS' : 'FAIL'} (expect ${EXPECT}, ${CASE}): DAG rate ${dagRate?.toFixed(3)}/s against ${BPS} (${rateOff == null ? '?' : (100 * rateOff).toFixed(1) + '%'}), difficulty / hash-implied ${ratioMean?.toFixed(3)} (${diffOff == null ? '?' : (100 * diffOff).toFixed(1) + '%'}) over ${measured.length} samples; red share ${summary.red_share == null ? '?' : (100 * summary.red_share).toFixed(1) + '%'} of ${merged} merged over ${chainBlocks} chain blocks, chain step median ${median} ms p90 ${summary.chain_step_spacing_ms.p90} ms; blocks ${end.blocks.join('/')}; proxy ${summary.proxy.connections} conns ${summary.proxy.bytes} bytes${fails.length ? `; FAILED CHECK ${fails.join(', ')}` : ''}`);
|
||||
log(`summary: ${OUT}`);
|
||||
await stopAll();
|
||||
process.exit(pass ? 0 : 1);
|
||||
Loading…
Reference in a new issue