diff --git a/.github/workflows/ci-red.yml b/.github/workflows/ci-red.yml new file mode 100644 index 00000000..48b3deff --- /dev/null +++ b/.github/workflows/ci-red.yml @@ -0,0 +1,45 @@ +# The red watcher as its own workflow, on workflow_run, so the copy on master watches EVERY branch's ci run whatever +# ci.yml that branch carries: GitHub runs a workflow_run workflow from the default branch only, and the branch's own +# ci.yml never enters it (7 October 2026: the inline `red` job of ci.yml was conditioned on master and release-*, and +# a feature branch would have waited for a merge of master before its reds were posted at all). +# +# One line per failed run (tools/ci/red-watch.mjs record, idempotent per run attempt) to /srv/ci-red/red.jsonl on the +# box; the box's igneum-ci-red.timer posts each new line once to the hidden updates channel, naming the branch, the +# commit, the red check and the pushing author. Runs on the box's own runner (not a GitHub-hosted machine: the billing +# block of 6 October 2026, 18:37Z to 20:10Z, failed every hosted job at start and nobody was told). Never blocks a +# release: it reads the run, writes one line, and ends. +name: ci-red +on: + workflow_run: + workflows: [ci] + types: [completed] +jobs: + red: + name: red watcher (every branch; one line per failed run, with the branch, commit, red check and pushing author, to the updates channel and the box file) + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + # the label ci-red is on igneum-build-1 only (added through the runners API on 7 October 2026; the default of + # RUNNER_LABELS in provision.sh carries it): the record file and the poster (igneum-ci-red.timer, the webhook file) + # live on that box, and the pool label igneum-build-1 is shared with igneum-build-2 since the same day + runs-on: [self-hosted, linux, x64, ci-red] + timeout-minutes: 5 + permissions: + actions: read # the failed run's jobs API (the first real red run, 21:19Z on 6 October: the default token answered 403 and the line carried no step) + contents: read + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: tools/ci + - name: record the failed run (one line, the branch, the commit, the failed jobs and their first failed step from the run's own API, the pushing author) + env: + GITHUB_TOKEN: ${{ github.token }} + RED_WATCH_RUN_ID: ${{ github.event.workflow_run.id }} + RED_WATCH_ATTEMPT: ${{ github.event.workflow_run.run_attempt }} + RED_WATCH_WORKFLOW: ${{ github.event.workflow_run.name }} + RED_WATCH_BRANCH: ${{ github.event.workflow_run.head_branch }} + RED_WATCH_SHA: ${{ github.event.workflow_run.head_sha }} + RED_WATCH_EVENT: ${{ github.event.workflow_run.event }} + RED_WATCH_URL: ${{ github.event.workflow_run.html_url }} + RED_WATCH_ACTOR: ${{ github.event.workflow_run.actor.login }} + RED_WATCH_TITLE: ${{ github.event.workflow_run.head_commit.message }} + RED_WATCH_AUTHOR: ${{ github.event.workflow_run.head_commit.author.name }} + run: node tools/ci/red-watch.mjs record --file /srv/ci-red/red.jsonl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47d81673..fefdd8b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,13 +8,16 @@ # local gate and CI cannot drift (6 October 2026: 131 red `ci` runs in three days, 92 of them on master, every one a # tree check that would have failed on the pushing machine in under 25 s; docs/analysis/ci-failures-2026-10-06.md). # -# Where it runs: `pow` and `sims` go to the box's runner (igneum-build-1, rustc pinned, sccache read-only, 48 jobs) +# Where it runs: `pow` and `sims` go to the self-hosted pool (label igneum-build-1: the runners on igneum-build-1 and, since +# 7 October 2026, igneum-build-2, which carries that label too; rustc pinned, sccache read-only) and only when the push +# touched code (the `changes` job; a docs-only push skips them) # when the repository variable IGNEUM_CI_RUNNER is `box`, else to ubuntu-latest (docs/plans/ci-self-hosted.md; GitHub -# has no fallback in runs-on, the variable is the switch). The `site` job stays on GitHub's machines. The `red` job -# runs on the box after any failed run on ANY branch and records the failure for the watcher -# (tools/ci/red-watch.mjs; infra/build-server/ci-red): one line per run, naming the branch, the commit, the red check -# and the pushing author, to the hidden updates channel and to /srv/ci-red/red.jsonl, so nobody opens the Actions page -# to learn a branch is red (master and release-* only until 7 October 2026, when eight red runs on ca3-v4-node went unseen). +# has no fallback in runs-on, the variable is the switch). The `site` job stays on GitHub's machines. The red watcher +# is its own workflow, .github/workflows/ci-red.yml (workflow_run, so the copy on master watches every branch's run +# whatever ci.yml that branch carries): one line per failed run, naming the branch, the commit, the red check and the +# pushing author, to the hidden updates channel and to /srv/ci-red/red.jsonl (tools/ci/red-watch.mjs; +# infra/build-server/ci-red), so nobody opens the Actions page to learn a branch is red (the inline `red` job here +# watched master and release-* only until 7 October 2026, when eight red runs on ca3-v4-node went unseen). # # What does not run, on purpose: the node fork (vendor/igneum-node*, a rusty-kaspa fork of about 500 crates with # rocksdb, blst and the execution layer) is gitignored here and too big for the free runners today (a cold build is @@ -25,8 +28,39 @@ on: push: pull_request: jobs: + changes: + # What the push touched (tools/ci/docs-only-check.sh): a push of documents only (docs/, site/, *.md) skips the two + # compile-or-compute jobs below, which read none of those paths, so the self-hosted queue carries only runs that can + # change their result (7 October 2026: 31 runs queued on one runner, most of them status-document pushes). The tree + # gate (the `site` job) runs on ubuntu-latest for every push. A pull request, a new branch or a force push answers + # code=true (no `before` to compare from), as does any error reading the compare API: when in doubt, run. + name: what the push touched (docs-only runs skip the Rust and simulator jobs) + runs-on: ubuntu-latest + outputs: + code: ${{ steps.classify.outputs.code }} + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: tools/ci + - id: classify + env: + GH_TOKEN: ${{ github.token }} + BEFORE: ${{ github.event.before }} + AFTER: ${{ github.sha }} + REPO: ${{ github.repository }} + EVENT: ${{ github.event_name }} + run: | + if [ "$EVENT" != push ] || [ -z "$BEFORE" ] || [ "$BEFORE" = 0000000000000000000000000000000000000000 ]; then + echo "code=true" >> "$GITHUB_OUTPUT"; echo "no base to compare from ($EVENT): the compile jobs run"; exit 0 + fi + files="$(gh api "repos/$REPO/compare/$BEFORE...$AFTER" --paginate --jq '.files[].filename' 2>/dev/null || true)" + line="$(printf '%s\n' "$files" | bash tools/ci/docs-only-check.sh)" + echo "$line" >> "$GITHUB_OUTPUT" + echo "$line: $(printf '%s\n' "$files" | grep -c .) changed path(s) between ${BEFORE:0:8} and ${AFTER:0:8}" pow: name: igneum-pow tests, igneum-census build + needs: changes + if: ${{ needs.changes.outputs.code == 'true' }} runs-on: ${{ vars.IGNEUM_CI_RUNNER == 'box' && fromJSON('["self-hosted", "linux", "x64", "igneum-build-1"]') || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -42,6 +76,10 @@ jobs: run: cargo build --release sims: name: simulators, quick modes + needs: changes + # master and release-* pushes, and pull requests into them, only (main, 7 October 2026: every code push cost two box jobs and the + # queue read 22); a feature-branch code push runs the igneum-pow tests alone. tools/ci/sims-branch-check.sh holds this rule. + if: ${{ needs.changes.outputs.code == 'true' && ((github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release-'))) || (github.event_name == 'pull_request' && (github.base_ref == 'master' || startsWith(github.base_ref, 'release-')))) }} runs-on: ${{ vars.IGNEUM_CI_RUNNER == 'box' && fromJSON('["self-hosted", "linux", "x64", "igneum-build-1"]') || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -71,33 +109,13 @@ jobs: - uses: actions/setup-node@v4 with: node-version: '22' + - name: a headless Chromium for the text-overlap sweep (Playwright outside the tree; the gate finds it through IGNEUM_PLAYWRIGHT_DIR) + run: | + mkdir -p /tmp/pw && cd /tmp/pw && npm init -y >/dev/null && npm i --no-audit --no-fund playwright@1.56 | tail -1 + npx playwright install --with-deps chromium | tail -1 + echo "IGNEUM_PLAYWRIGHT_DIR=/tmp/pw" >> "$GITHUB_ENV" - name: the tree gate, tools/ci/pre-push.sh --ci (the same script the pre-push hook runs; one line per check, a red check prints its output) run: bash tools/ci/pre-push.sh --ci - name: public stats API answers with the documented fields (the live site; master only, the endpoints exist there after the merge) if: github.ref == 'refs/heads/master' run: node tools/ci/public-api-check.mjs https://igneum.network - - red: - # Runs when a run on any branch has a failed job, on the box's own runner (not a GitHub-hosted machine: - # the billing block of 6 October 2026, 18:37Z to 20:10Z, failed every hosted job at start and nobody was told). - # tools/ci/red-watch.mjs record appends ONE line for this run to /srv/ci-red/red.jsonl (idempotent per run attempt); - # the box's igneum-ci-red.timer posts each new line once to the hidden updates channel. Never blocks a release: - # it reads the run, writes one line, and ends. - name: red watcher (every branch; one line per failed run, with the branch, commit, red check and pushing author, to the updates channel and the box file) - needs: [pow, sims, site] - if: ${{ failure() }} - runs-on: [self-hosted, linux, x64, igneum-build-1] - timeout-minutes: 5 - permissions: - actions: read # the run's jobs API (the first real red run, 21:19Z: the default token answered 403 and the line carried no step) - contents: read - steps: - - uses: actions/checkout@v4 - with: - sparse-checkout: tools/ci - - name: record this run (one line, the branch, the commit, the failed jobs and their first failed step from the run's own API, the pushing author) - env: - GITHUB_TOKEN: ${{ github.token }} - RED_WATCH_TITLE: ${{ github.event.head_commit.message }} - RED_WATCH_AUTHOR: ${{ github.event.head_commit.author.name }} - run: node tools/ci/red-watch.mjs record --file /srv/ci-red/red.jsonl diff --git a/brand/marks/vendor-marks.mjs b/brand/marks/vendor-marks.mjs new file mode 100644 index 00000000..08de8b84 --- /dev/null +++ b/brand/marks/vendor-marks.mjs @@ -0,0 +1,65 @@ +// Igneum vendor and OS marks (gpu-logos, 7 October 2026): the strings the miner app ships in app/igneum-app/ui/app.js +// (View.MARKS and View.VENDORS), exported verbatim for the site and anything else that names the hardware. +// view.test.mjs fails when this file and app.js drift apart, so edit app.js first and regenerate this file with +// `node brand/marks/regen.mjs` (or copy the strings by hand; the test says which one moved). +// +// Each glyph: a hand-drawn simplified monochrome mark of the vendor's public geometry (never a copied logo file, +// never a raster), 24 x 24 viewBox at 22 px, under 460 bytes, fill or stroke through currentColor so the element's +// colour tints it. Nominative use that names the hardware; the ember accent is for state and never tints a brand. +// +// The treatment in the app (app.css, the block at the end): a 44 x 44 well, radius 12, background the vendor colour +// at .14 alpha (dark) or .10 (light), a 1 px ring in the vendor colour at .45 alpha, the glyph in the full colour; +// hover and focus-within add a 3 px halo of the well colour; nothing animates. The light hex of every vendor reads at +// 3:1 or better on its well over white (nvidia 3.87, amd 5.01, intel 4.29, apple 7.52, gpu 4.65). +// +// Class names in the app: .badge. (nvidia | amd | intel | apple | gpu), .badge.mini for a 26 px inline mark, +// .gen for the series line under the name. Tokens: --mark-, --mark--well, --mark--ring. + +export const VENDORS = { + "nvidia": { + "label": "NVIDIA", + "dark": "#8BE37A", + "light": "#2F8A22" + }, + "amd": { + "label": "AMD Radeon", + "dark": "#FF5A5A", + "light": "#C41E2A" + }, + "intel": { + "label": "Intel", + "dark": "#7CC4FF", + "light": "#1C6FD6" + }, + "apple": { + "label": "Apple", + "dark": "#E6E3DD", + "light": "#4A4A50" + }, + "gpu": { + "label": "GPU", + "dark": "#9A9A9E", + "light": "#6B6B70" + } +}; +export const WELL_ALPHA = { dark: 0.14, light: 0.1 }; +export const MARKS = { + "nvidia": "", + "amd": "", + "intel": "", + "apple": "", + "gpu": "" +}; +// OS marks in the same treatment: Apple is the vendor glyph; Windows is the four slanted panes +export const OS_MARKS = { + macos: MARKS.apple, + windows: "" +}; +export const OS_COLOURS = { macos: VENDORS.apple, windows: { label: 'Windows', dark: '#7CC4FF', light: '#1C6FD6' } }; +// the CSS tokens for both themes, as the app declares them +export function tokensCss() { + const line = (theme) => Object.entries(VENDORS).map(([v, c]) => { const h = c[theme], r = parseInt(h.slice(1, 3), 16), g = parseInt(h.slice(3, 5), 16), b = parseInt(h.slice(5, 7), 16), a = String(WELL_ALPHA[theme]).replace(/^0/, ''); return `--mark-${v}:${h};--mark-${v}-well:rgba(${r},${g},${b},${a});--mark-${v}-ring:rgba(${r},${g},${b},.45)`; }).join(';'); + return `:root{${line('dark')}}\n@media (prefers-color-scheme:light){:root:not([data-theme="dark"]){${line('light')}}}\n:root[data-theme="light"]{${line('light')}}`; +} +// the well:
+export function markHtml(vendor, size) { const v = MARKS[vendor] ? vendor : 'gpu'; return '
' + MARKS[v] + '
'; } diff --git a/docs/analysis/era-vdf-2026-10-07.md b/docs/analysis/era-vdf-2026-10-07.md new file mode 100644 index 00000000..691b63dd --- /dev/null +++ b/docs/analysis/era-vdf-2026-10-07.md @@ -0,0 +1,86 @@ +# The era VDF: built, measured and gated (7 October 2026) + +Era VDF lane, 7 October 2026, from the attack pass's F7 row (`docs/analysis/attack-pass/f7-era.md`, sub-row a: the node's era seed was a plain chain block hash, grindable with one block of hash at no delay, and the 1-hour VDF of spec 04 section 4.4 did not exist in the node). Repository branch `era-vdf` (this record, the spec text, the harness `tools/era-vdf/`, the fast-time fields); node fork branch `era-vdf-node` on the 0.3.19 line (`release-0.3.19-node` dc141409). Every number below names its log on igneum-build-1 under `/srv/builds/igneum-wt-era-vdf/ev-*/`. + +## 1. What was built + +| Piece | Where | What | +|---|---|---| +| The integer | `consensus/core/src/era_vdf/bigint.rs` | a fixed-width signed integer (40 limbs, 2,560 bits) on the stack: add, sub, mul, shifts, Knuth division with floor, truncated, exact and Euclidean remainders, the extended gcd and the partial extended gcd with Lehmer's word steps (chiavdf `xgcd_partial.c`), modpow, sqrt and the fourth root, Miller-Rabin with the first 30 primes as bases; every operation checked against `num-bigint` on 20,000 random operands of the class group's sizes, the known-failed shapes first | +| The class group | `era_vdf/classgroup.rs` | `proto-vdf/src/classgroup.rs` (3 October 2026) on the fixed-width integer: NUDUPL and NUCOMP ported line by line from chiavdf's `qfb_nudupl` and `qfb_nucomp`, the plain duplication and Cohen 5.4.7 kept as the oracles the tests hold them to on random forms at 256, 512 and 1,024 bits; serialization as sign byte plus fixed width, 258 bytes a form | +| Wesolowski | `era_vdf/wesolowski.rs` | eval with serialized checkpoints (at most 2^16, 17 MB), the 12-bit-digit block prover bucketed per residue class and parallel over them, the naive prover as the oracle, verify; T + 1, another y, another pi and another input refused | +| The hash chain | `era_vdf/hashchain.rs` | scheme 1: T sequential SHA-256 applications from a tagged start; verification by recomputation; one step short refused | +| The scheme byte and the seed | `era_vdf/mod.rs` | `vdf_scheme` 0 and 1, `EraVdfProof` and its wire form, `era_vdf_input` (the chain's BLAKE2b keyed `IgneumEraVdfInput` over `chain_id || n || the day's blue hashes`), `era_seed_of` = SHA-256 of the scheme byte, the input, T and y | +| The switch | `consensus/core/src/config/params.rs`, `igneum.rs` | `pow_era_blocks` and `pow_era_lead` as override fields (the constants everywhere; in the digest when they differ), `era_vdf_activation_daa` (never), `vdf_scheme` (0), `era_vdf_t` (the reference T); the three in the digest once the activation is set (the 0.3.15 rule); installed with the PoW schedule | +| The node side | `consensus/src/processes/era_vdf.rs`, `model/stores/era_vdf.rs` | the cut rule (the chain block below the cut, memoised and re-validated by reachability), the day-of-blues input (memoised per cut block), the evaluator thread started by the virtual processor a quarter of the lead past the cut, the record store (one row per era), the header processor's wait when a header arrives before the record, the template's `era_seed` None while evaluating, `submit` for a record from outside (verified against this chain's input) | +| The template and the miner | `PowEpochInfo`, `RpcPowEpochInfo`, `rpc.proto` fields 37 to 44, `igneum-miner` | the era schedule, the VDF's state, scheme, T and input in every template; the miner holds while the node reports no era seed ("era VDF: the node is still evaluating"); `igneum-miner vdf bench|eval|verify` with the node's own code | +| The harness | `tools/era-vdf/reroll.mjs` | the F7 re-roll harness against the REAL era cut (era 120 DAA, lead 20 on the merged fast-time file; ports 30100 and up, suffix 1010), `--vdf off` the stand-in, `--vdf on` the VDF at a fast T, the adversary running the node's evaluator over its candidate before publishing | + +## 2. The parameters + +Measured 7 October 2026 on igneum-build-2 (AMD EPYC 9454P, 96 threads, Ubuntu 24.04), one core under `/srv/builds/_bin/lease cores 31` at nice 10 while the box ran other lanes' suites (load 25 to 75), with the node's own code (`igneum-miner vdf bench`, logs `ev-vdf-bench3.log`, `ev-vdf-bench5.log` in this lane's scratch) and chiavdf 7e62ce14 built on the box against GMP 6.3.0 (`ev-chiavdf`). + +| Parameter | Value | Label | +|---|---|---| +| Group | class group, 1,024-bit prime discriminant `D = -HashPrime("igneum-era-discriminant" \|\| input)`, `\|D\| = 7 mod 8` | Implemented (spec 4.2) | +| Generator, Fiat-Shamir prime, proof plan | `(2, 1, (1 - D) / 8)`; 256 bits; 12-bit digits, at most 2^16 serialized checkpoints (17 MB) | Implemented | +| Proof on the wire | 529 bytes: scheme (1), T (8), two 258-byte forms with 2-byte lengths; `y` and `pi` 258 bytes each | Measured | +| Scheme byte | `vdf_scheme` 0 = class group, 1 = hash chain; genesis 0 everywhere | Implemented | +| Reference rate, scheme 0 | 30,589 and 40,117 squarings/s in two 10-s runs on the box core (the spread is the box's load); 30,000 is the reference | Measured | +| `T_era`, scheme 0 | 3,600 x 30,000 = 108,000,000 squarings (`ERA_VDF_T_CLASS_GROUP`): 60 min at the reference, 45 at the faster run | Measured, set | +| Prove, scheme 0 | eval + prove 11.6 s at T 401,167 (eval 10.0 s): the single-thread block prover is about 14 percent of the evaluation, parallel over residue classes in the node (up to 8) | Measured | +| Verify, scheme 0 | 21.9 and 22.6 ms with the group held (mean of 20); 184 ms with the discriminant derived, the derivation being 161 to 167 ms, once per era | Measured (section 5 for the gate) | +| Reference rate, scheme 1 | 16.2 and 17.0 million SHA-256/s (SHA-NI); 16,000,000 is the reference; `T_era` = 57,600,000,000 hashes (`ERA_VDF_T_HASH_CHAIN`) | Measured, set | +| Verify, scheme 1 | recomputation: 10.1 s for T 170 million, the full hour at `T_era` | Measured | +| Discriminant search | 161 to 167 ms per era (Miller-Rabin with the first 30 primes on the fixed-width integer) | Measured | +| chiavdf on the same core | 208.8 K squarings/s (`vdf_bench square`, NUDUPL over GMP, 1,000,000 iterations); the AVX-512 IFMA path (`square_asm`) gave 127.3 K at 20,000 iterations and stalled at 300,000 and above in this build (built outside its Makefile's `FAST_MACHINE` flags), so the IFMA number is not established here | Measured; the asm path unestablished | +| Delay on the fastest prover measured | 108,000,000 / 208,800 = 517 s against the 1-s block interval (517x) and the 2-s publish window (259x); a prover 10x chiavdf's GMP path (the ceiling Chia's and the EF's hardware efforts aimed at, approximate, from memory) would still take 52 s, 26x the window | Computed from the measurements | +| The gate "at least 60x one block interval on the fastest known prover" | 517x on chiavdf's GMP path, the fastest evaluator measured on this hardware; PASS as measured, with the IFMA path unestablished (above) and the 10x hardware ceiling still 52x | PASS (measured), caveat recorded | + +The node's own evaluator is 5.2 to 6.8x slower than chiavdf's GMP path on the same core. That ratio only moves the honest side: `T_era` is set from the node's rate, so an honest node finishes in the hour; the attacker's margin is the delay at the fastest prover, above. + +## 3. The gate: the re-roll harness with the VDF off and on + +`tools/era-vdf/reroll.mjs` on igneum-build-2 (the box under other lanes' suites, nice 10; logs and per-cut JSON under `/srv/builds/igneum-wt-era-vdf/ev-harness-out/reroll-vdf-{on,off}-5.json`), three nodes of the fork at this record's commit on the fast-time file with `skip_proof_of_work`, era 120 DAA and lead 20 (cuts at `S = 120 n - 20`, one every two minutes), ports 30100 and up, suffix 1010; two honest virtual miners share 1 block/s on nodes 0 and 1; the adversary on node 2 holds a block A built on the tip at `S - 1` and tries to make it the era's cut block. With the VDF on, the adversary runs the node's own evaluator (`igneum-miner vdf eval`, the network's T) over its candidate before publishing; T is set from a 3-s bench at the start so the delay is about 5 s on one core of this box, five times the block interval. + +| Run | Switch | Cuts | A accepted | A became the cut block | Known-draw re-rolls (the seed the adversary knew before publishing is the era's seed) | Adversary's evaluation | Nodes agree on the era seed | Gate | Harness | +|---|---|---|---|---|---|---|---|---|---| +| vdf-off-5 (the stand-in, 15:08 to 15:22 UTC) | `era_vdf_activation_daa` never | 6 (eras 2 to 7) | 6 of 6 | 6 of 6 | 6 of 6: the seed is `hash(A)` every time | none needed: the draw of hash(A) is known the instant A is built | 3 of 3 on every era | FAIL (the known-pass fires) | SOUND | +| vdf-on-5 (the era VDF, 14:54 to 15:08 UTC) | activation 0, scheme 0, T 189,650 (5 s on this core) | 6 (eras 2 to 7) | 6 of 6 | 0 of 6 | 0 of 6 | 5.38 to 6.64 s, during which the honest chain advanced 3 to 10 blocks; A arrived behind them and never became the cut block | 3 of 3 on every era, the record ready (state 3) at every era start | PASS (silent) | SOUND | + +What the two runs say. Under the stand-in a miner with one block of hash at the right second owns the era draw outright on this network: holding the block at `S - 1` and publishing it the moment the chain reaches `S - 1` makes it the cut block in every one of six cuts (the attack lane's epoch-cut run saw 1 of 6, with the honest block often landing first; here the adversary is faster to the second), and its draw is known the instant the block is built. Under the VDF the same adversary cannot know any candidate's draw before T steps have run; while it ran them the honest chain moved 3 to 10 blocks, so its block arrived behind the cut and the seed came from the delay over the day of blues ending at the honest cut block, the same on all three nodes. The second half of the written argument of F7 (a) holds in the node, not only on paper: the re-roll needs the draw inside the window, and the window is 1 s against a delay of 5 s here and 517 s at the fastest prover measured on the production T (section 2). + +The known-pass and the known-fail ran on the same binaries, file and ports, the VDF switch the only difference. A first VDF-off run with a lookup defect in the harness (the adversary's block not found, so the verdict read "held") was discarded once the node's own log showed the adversary's hash as the cut block in 5 of 5 cuts; the harness now reads A from that log line. Two runs that overlapped on the box through a stale node of an earlier run were discarded as well (their nodes disagreed because they were two networks); the two runs above ran alone. + +## 4. The cut rule and the certified checkpoint (for the finality lane) + +The node names `C_era(n)` as the last selected-chain block below the cut on the header's own chain (the block the stand-in used), which is the checkpoint block the lead rule names under the O-4.3 decision of 3 October 2026 (certified or not). Three facts decide it: + +1. Determinism. A header's validity must be a function of its own past. "The certificate carried by a block in the header's past, for the highest-index checkpoint with DAA score at most the cut" is such a function, but a certificate that lands after the era starts flips the reading between headers of one era (a header before the carrier reads the fallback, a header after it reads the certificate), so the certified binding needs a second rule: the carrier must sit at most half a lead above the cut (3,600 DAA s, the merge depth) and be a chain ancestor of the header; under that rule every honest header of the era reads the same certificate once the network merged the carrier, and a header on a chain that never merged it reads the fallback, consistently with its own past. The chain-block reading needs no second rule. +2. Liveness. A finality pause across the cut (a third of weight leaving in an hour is a 30-day pause under rule v3) leaves the certified binding without a checkpoint for the era; the chain-block reading always has one, which is the reason O-4.3 was decided the way it was for the epoch. +3. The defence. The grinding defence is the delay: no candidate's draw is knowable for T steps, whichever block is the cut. The binding moves which block a withholder would have to be the author of, not whether withholding pays; both readings leave the withholder with a coin flip it cannot see. + +The change, if the finality lane wants the certified binding: `EraVdfManager::cut_block` (one function; the input, the delay and the seed are unchanged), plus the second rule above and a test with a certificate carried late. + +## 5. The verify gate on a 2019-class core + +The gate was "the VDF verifies in under 10 ms on a 2019-class core". Measured: 21.9 and 22.6 ms with the group held on the box core (above), which the F6 row's calibration puts at about 1.19x on an i7-9700K (the O-1.14 run: 6.0 ms on the 2019 core against 5.06 ms on the box proxy), so about 26 ms on a 2019 core, labelled a proxy: no 2019 host was rented this lane (Vast rentals are a purchase; not made without the project lead's word). NOT MET, by 2.2x on the box and about 2.6x on the proxy. + +Where the time goes and what closes it: a verification is two 256-bit exponentiations, about 770 group operations at 28 µs each; the operation is NUDUPL on the fixed-width integer, whose cost is the extended gcd (Lehmer rounds on 8-limb numbers) and the reduction. Three rounds of this lane moved it from 345 µs (a Lehmer convention defect that fell back to plain division every round) to 28 µs (the convention, i64 word division, 34 limbs, the x86-64 128-by-64 division); the next 2.2x is chiavdf's Pulmark reducer (reduce only when `a` exceeds 8 limbs, O-4.6) and a limb-level NUDUPL that keeps the partial gcd's intermediates in words, or GMP through `rug` behind a feature on the x86-64 Linux and Windows builds (chiavdf's 208 K/s is 6x this evaluator, which would put the verification near 4 ms as the prototype measured), with the fixed-width path the fallback for wasm and macOS. Owed, not blocking: the verification runs once per era (180 days) on a node that imports a record rather than evaluating; every mining node evaluates and never verifies. + +## 6. Consequences per tier (the standing rule of 5 October 2026) + +| Tier | What the era VDF costs | What it means | +|---|---|---| +| A home miner, any card (8, 12, 16, 24 or 32 GB), any vendor, Windows, Linux or macOS | one CPU core for about 60 min once per 180 days at the reference rate (a 2019-class desktop core about 72 min by the F6 calibration), 17 MB of host RAM for the prover's checkpoints during it, 0 bytes on the card; the node starts it a quarter of the lead past the cut and holds the record from then | nothing changes on the card or in the hash rate; the 2-hour lead covers a core half the reference speed; a node that was off across the cut evaluates on arrival and its miner holds until the record lands (the miner says so every 10 s) | +| A rig (one node, several cards) | the same one core on the rig's host, once per era | nothing per card | +| A pool user | the pool's node evaluates; the member's miner takes `era_seed` from the template as today | nothing | +| A light client or a syncing node | verifies an imported record in 22 ms (26 ms on a 2019 core, proxy) plus the 165-ms discriminant derivation, once per era; under scheme 1 it recomputes the hour | the 10-ms gate is missed (section 5); operationally one verification per 180 days | +| The protocol | the era draw's input is unknowable for 517 s on the fastest prover measured, against a 1-s block interval: the stand-in's one-block grind is closed (section 3) | the freeze of the draw procedure and the C_era cut rule no longer waits on the VDF's existence; it waits on the two decisions of `ledger-decisions.md` | + +## 7. What is owed + +- The P2P relay of an era record to a syncing peer and the RPC import (spec 4.5, O-4.10), before era 1 of any network with the switch set. +- The external review of the class-group port (O-4.1): the port is a second implementation checked against the textbook algorithms and `num-bigint`, not a review. +- The attack pass's F7 status row (branch `attack-pass`, `docs/analysis/attack-pass-2026-10.md`) reads INCOMPLETE pending this lane; the line for it, from section 3: "F7 (a): the era VDF is in the node (fork `era-vdf-node`); the re-roll harness against the real era cut fires with it off (6 of 6 cuts, the seed the adversary's block) and is silent with it on (0 of 6 across six cuts, the adversary's 5-s evaluation against a 1-s block interval, three nodes agreeing on every era seed); PASS, the delay 517 s on the fastest prover measured at the production T." +- The decisions of `docs/plans/ledger-decisions.md` (the activation per network, the cut's binding). diff --git a/docs/bench-log.md b/docs/bench-log.md index 5d5220b3..0c328e6d 100644 --- a/docs/bench-log.md +++ b/docs/bench-log.md @@ -2652,3 +2652,32 @@ in the same shape and reports a box behind its wanted binary. | Rig | the same, and a rig that leaves is itself a weight removal: at 459 MH/s on tonight's devnet it is about 20 percent of the weight, over the hour's budget by itself | | Pool | a pool node is one voter carrying its members' whole weight; a pool restart is the largest single removal on the network and must be sliced like the fleet's | | The network | finality by miner weight is only as steady as the miners' uptime; until public hash dwarfs the fleet, the fleet's supervisor is a consensus component | + +## 7 October 2026, the first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on PC 2 (branch bench-5060ti) + +Machine: PC 2 (`1ccfe586`, Windows 11), an ASUS Dual GeForce RTX 5060 Ti (16 GB GDDR7, Blackwell sm_120, PnP `PCI\VEN_10DE&DEV_2D04&SUBSYS_8A111043`) in a Razer Core X V2 Thunderbolt enclosure ("USB4 Router (2.0), Razer - Core X V2", bus `0B:00.0`), beside the RTX 5090 on its own supply; NVIDIA driver 610.47 (WDDM 32.0.16.1047, the 5090's driver, nothing installed for the new card); the installed app 0.3.19 and its own `igneum-worker-cuda.exe` (NVRTC 12.8). Jobs `fetch-5060ti-packs-20261007` (the kit: `tools/bench-5060ti/make-kit.sh`, the class v4 pack at sub-version 1 and the v3 control, sha256 `fd8393ed...`, 105,892 bytes) and `run-5060ti-bench-20261007-b` (`tools/bench-5060ti/pc2-5060ti-bench.ps1`, 14:44:19Z, ran 14:45:05 to 14:58:11Z, exit 0; the 5060 Ti alone through the runner's `--cards-off`, the 5090 mining throughout; run `-a` died in 1 s on an argument-binding fault in the nvidia-smi query and is void). PC 2 lost power twice that day, so the job WRITES NO POWER LIMIT: it reads `power.limit` against `power.default_limit` (180 W = 180 W, range 150 to 198 W) and the row says `limit_is_stock=yes`. Read back with `node tools/jobs.mjs run-5060ti-bench-20261007-b`. + +**Detection** (the app's first poll after the restart, run `win-1ccfe586-20261007-143611`, 14:36:16Z): `GPUs: NVIDIA GeForce RTX 5090 (CUDA); NVIDIA GeForce RTX 5060 Ti (CUDA); AMD Radeon(TM) Graphics (OpenCL, gfx1036)` and `cards: NVIDIA GeForce RTX 5090 [discrete, off] | NVIDIA GeForce RTX 5060 Ti [discrete, off] | ...`; the app started a miner on it by itself (`nvidia-1ccfe586-2`, `--device 1`, 8 identities, the default). The kind reads `discrete`, not `external`: the app does not know it is an eGPU. nvidia-smi in the job: index 1, 16,311 MiB, PCIe link gen 4 x4 current against gen 4 x16 maximum (the Thunderbolt link: a quarter of the slot's lanes), 43 C idle. The freeze lane's cause class for the 15:10 UK hang on the first boot with the card: not the card (no TDR, no Thunderbolt or PCIe link event; Kernel-Power 41 + 6008, no bugcheck, the power shape again). + +**G1 and the window** (the installed CUDA worker, `--bench --batch-log2 24 --block-warps 1`, the card alone, `CUDA_VISIBLE_DEVICES` on its UUID so every row names the device; nvidia-smi every 2 s on the card, the loaded samples at utilisation 90 percent and over): + +| Pack | Dispatches of 2^24 | Self-test | Fingerprint 2^24 at base 0 | MH/s | +|---|---|---|---|---| +| mx8-devnet-epoch0 (the class v3 control) | 5 | PASS | 90f794dd556f7a3b (= the control everywhere) | 30.895 | +| v4-devnet-epoch0 (class v4, sub-version 1, program id 1a4230699a6b9c60) | 5 | PASS | 867dbc45cfb36b4d (= Metal, Apple OpenCL, the RTX 5090) | 30.879 | +| v4-devnet-epoch0, the 10-minute window at the stock limit | 1,105 (602 s) | PASS | 867dbc45cfb36b4d | 30.882 | + +| Row | Value | +|---|---| +| NVIDIA RTX 5060 Ti 16 GB, class v4, CUDA (NVRTC), driver 610.47, PCIe 4.0 x4 through the enclosure | 30.9 MH/s over 10 minutes on the card alone | +| Watts at the stock limit (180 W default, unchanged) | 114.8 W mean, 115 W p50 over the window; 0.269 MH/W; SM 2,753 MHz, memory 13,801 MHz, 60 C maximum | +| The class v4 shadow against the control | 0.1 percent (the 5090 paid 0.2, the 9070 XT 3, the B580 0.1) | +| The efficient point | OWED to the app's Ember Tune: nothing set by the job; PC 2's Power Helper refused every request since the restart ("the helper did not run sequence 0 within 15 s", 14:39Z), so no ladder ran on either card | +| Prove beside the miner (16 GB tier) | BLOCKED, not measured: the shipped WSL2 host (sha `71bc2438...`) carries no `IGNEUM_CUDA_DEVICE` selector, so aimed at anything it proves on CUDA device 0 (the 5090) through the app's own socket `/tmp/sp1-cuda-0.sock`; the selector lives in the prover-floor host (`proof_system.rs`, branch prover-floor) and is the owed cut. The job's inventory: the floor server IS on PC 2 (`/opt/igneum-floor/bin/sp1-gpu-server`, 6.8.1 build `e911facb...`, 166,665,880 bytes) beside the stock one (`~/.sp1/bin`, `c2642ad1...`), WSL sees the card as CUDA device 1 | +| Card-picker entry (`site/yourcard.js`) | `['NVIDIA RTX 5060 Ti', 30.9]`, added; the public table row in `site/miner-bench.json` | + +Against the 5090 on the same PC (122 MH/s at 308 W, 0.396 MH/W): 25.3 percent of its hash at 37 percent of its draw, 68 percent of its hash per watt. The dependent-read ceiling was not probed (the memprobe step is not in this job); at 128 loads a hash 30.9 MH/s is 3.95 G dependent reads a second, between the 9070 XT (2.4 to 2.7 G) and the 5090 (16 to 18 G). + +Consequences per tier (the rule of 5 October 2026): a 5060 Ti owner (16 GB, Windows) mines at 30.9 MH/s and 115 W from the box with nothing to set: about 5,100 blocks a day at the 522 MH/s the devnet showed at 14:44Z (one every 17 s, approximate: the network rate moves), about a quarter of a 5090 owner's 20,200, for 2.76 kWh a day (£0.79 at 28.5 p against the 5090's £2.11); through a Thunderbolt enclosure the x4 link costs nothing measurable (the hash is bound by the card's own memory latency, not the link; the 5090's PCIe-slot rows are the comparison), so a laptop with a Thunderbolt 4 port and this enclosure is a 31 MH/s miner. The 8 GB 5060 Ti: the same hash is the expectation (the 1 GiB dataset fits), a line owed. Proving on the 16 GB tier: the fleet's 4060 Ti 16 GB row (9.0 GB peak beside the miner on the patched server) says this card would mine and prove with about 7 GB spare, approximate until the host with the device selector ships; today the app's prover default leaves it off ("a full shard needs a 24 GB card") and the measured read is owed to the prover-floor host cut. Linux and HiveOS take the same CUDA worker (owed a line). What the lane does next: the prover-floor host's selector into the shipped WSL2 bundle, then the prove-beside read on this card; the Power Helper fault on PC 2 to the Ember lane (no efficient point on any PC 2 card until it answers). + +Found on the way: inside a PowerShell `@( ... )` the comma binds before `+`, so `'--query-gpu=' + $f, '--format=csv'` is one argument (run a, void in 1 s; the query string is built first now); a bare string inside a function that also returns a value is swallowed into the caller's variable (the sampler line; `[Console]::Out.WriteLine` now); the app's `kind` for a Thunderbolt card reads `discrete` (a word for the Cards page to earn: `external`, which the state already names). diff --git a/docs/design/genesis-forward-harness/digest-base-dc141409.log b/docs/design/genesis-forward-harness/digest-base-dc141409.log new file mode 100644 index 00000000..d49fb243 --- /dev/null +++ b/docs/design/genesis-forward-harness/digest-base-dc141409.log @@ -0,0 +1,29 @@ +Latency ladder inactive (no activation in the override file): every class v4 program at rung 0, 27 shadow passes; no ladder bits in the header +Program class signal inactive (the window or the floor is absent from the override file): headers carry block version 2 exactly +Fees on igneum-devnet-973: pgas table v0, B_p 30000000 pgas, S_p 7500000 pgas, floors 1000000000 wei per gas and 1000000000 wei per pgas; calibrated v1 from DAA score never +Consensus params digest: 079d8a7e736abbd4b135eb1d652466ca7906ea1b200e22eac97f795e626356e7 (exchanged in the p2p handshake; a peer with another digest is refused) +2026-10-07 15:14:29.331+02:00 [INFO ] igneumd/2.1.0-dc141409 +2026-10-07 15:14:29.331+02:00 [INFO ] Application directory: gf-digest/d-base +2026-10-07 15:14:29.331+02:00 [INFO ] Data directory: gf-digest/d-base/igneum-devnet-973/datadir +2026-10-07 15:14:29.331+02:00 [INFO ] Logs to console only +2026-10-07 15:14:29.350+02:00 [INFO ] Finality v2 (igneum-devnet-973): interval 30 depth 20 window 7200 DAA dust 5 presence 20 aggregators 8 ban 7200 fold 3; rule v3 (frozen table, certificate fold) from checkpoint DAA never; 0 checkpoints known, next index 1, 0 locks, 0 keys; C1 in DAA seconds from DAA never; weight-gated deep fork choice from DAA never; leave rule (W7, delay 3600 DAA) from checkpoint DAA never, 0 leaves +2026-10-07 15:14:29.363+02:00 [INFO ] [igneum-exec] proving v0: payouts from DAA score never, window 7200 DAA, dust 5, verifier Off +2026-10-07 15:14:29.363+02:00 [INFO ] [igneum-exec] proving v1: segment records from DAA score never, 8 blocks a segment, unproven after 600 DAA, aggregator share 1000 bps, shard program id unknown, aggregator id unknown +2026-10-07 15:14:29.364+02:00 [INFO ] [igneum-exec] verifying keys embedded: shard program id 0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a aggregator id 0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896 +2026-10-07 15:14:29.370+02:00 [INFO ] template prewarm: on (the cached block template is rebuilt on every virtual change; IGNEUM_TEMPLATE_PREWARM=0 turns it off) +2026-10-07 15:14:29.371+02:00 [INFO ] GRPC Server starting on: 127.0.0.1:29770 +2026-10-07 15:14:29.372+02:00 [INFO ] P2P Server starting on: 127.0.0.1:29771 +2026-10-07 15:14:29.373+02:00 [INFO ] [igneum-exec] chain follower started +2026-10-07 15:14:29.373+02:00 [INFO ] [igneum-exec] proof verifier: Off (no SP1 verification on this node) +2026-10-07 15:14:29.373+02:00 [INFO ] [igneum-exec] exec sync: sink edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block 0; pruning point edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block Some(0) (DAA 0); retention root edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block Some(0) (DAA 0), its body held +2026-10-07 15:14:29.373+02:00 [INFO ] [igneum-exec] eth_ JSON-RPC listening on 127.0.0.1:26790 +2026-10-07 15:14:29.373+02:00 [INFO ] [igneum-exec] exec sync: no snapshot to resume from (no snapshot file); the follower starts at genesis +2026-10-07 15:14:29.373+02:00 [INFO ] [igneum-exec] exec sync: waiting for consensus to sync before the executor starts (the sink is 393269 s old) +2026-10-07 15:14:29.373+02:00 [WARN ] [igneum-exec] cannot bind the eth_ JSON-RPC server on 127.0.0.1:26790: Address already in use (os error 98) +2026-10-07 15:14:29.374+02:00 [INFO ] WRPC Server starting on: 127.0.0.1:29772 +2026-10-07 15:14:29.474+02:00 [INFO ] [igneum-exec] chain follower stopped +^SIGTERM - shutting down... +2026-10-07 15:14:54.316+02:00 [INFO ] P2P Server stopped: 127.0.0.1:29771 +2026-10-07 15:14:54.316+02:00 [INFO ] WRPC Server stopped on: 127.0.0.1:29772 +2026-10-07 15:14:54.317+02:00 [INFO ] GRPC Server stopped on: 127.0.0.1:29770 +2026-10-07 15:14:54.824+02:00 [INFO ] igneumd has stopped... diff --git a/docs/design/genesis-forward-harness/digest-no-file.log b/docs/design/genesis-forward-harness/digest-no-file.log new file mode 100644 index 00000000..e53e161c --- /dev/null +++ b/docs/design/genesis-forward-harness/digest-no-file.log @@ -0,0 +1,29 @@ +Latency ladder inactive (no activation in the override file): every class v4 program at rung 0, 27 shadow passes; no ladder bits in the header +Program class signal inactive (the window or the floor is absent from the override file): headers carry block version 2 exactly +Fees on igneum-devnet-973: pgas table v0, B_p 30000000 pgas, S_p 7500000 pgas, floors 1000000000 wei per gas and 1000000000 wei per pgas; calibrated v1 from DAA score never +Consensus params digest: 079d8a7e736abbd4b135eb1d652466ca7906ea1b200e22eac97f795e626356e7 (exchanged in the p2p handshake; a peer with another digest is refused) +2026-10-07 15:12:35.092+02:00 [INFO ] igneumd/2.1.0-75810130 +2026-10-07 15:12:35.093+02:00 [INFO ] Application directory: gf-digest/d-none +2026-10-07 15:12:35.093+02:00 [INFO ] Data directory: gf-digest/d-none/igneum-devnet-973/datadir +2026-10-07 15:12:35.093+02:00 [INFO ] Logs to console only +2026-10-07 15:12:35.128+02:00 [INFO ] Finality v2 (igneum-devnet-973): interval 30 depth 20 window 7200 DAA dust 5 presence 20 aggregators 8 ban 7200 fold 3; rule v3 (frozen table, certificate fold) from checkpoint DAA never; 0 checkpoints known, next index 1, 0 locks, 0 keys; C1 in DAA seconds from DAA never; weight-gated deep fork choice from DAA never; leave rule (W7, delay 3600 DAA) from checkpoint DAA never, 0 leaves; key succession (W5) from checkpoint DAA never, 0 successions; signature scheme 0 (0 = BLS12-381), any other refused until a class names it +2026-10-07 15:12:35.136+02:00 [INFO ] [igneum-exec] proving v0: payouts from DAA score never, window 7200 DAA, dust 5, verifier Off +2026-10-07 15:12:35.136+02:00 [INFO ] [igneum-exec] proving v1: segment records from DAA score never, 8 blocks a segment, unproven after 600 DAA, aggregator share 1000 bps, shard program id unknown, aggregator id unknown +2026-10-07 15:12:35.136+02:00 [INFO ] [igneum-exec] proof archive at gf-digest/d-none/igneum-devnet-973/datadir/evm/proofs: 0 proofs +2026-10-07 15:12:35.136+02:00 [INFO ] [igneum-exec] verifying keys embedded: shard program id 0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a aggregator id 0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896 +2026-10-07 15:12:35.141+02:00 [INFO ] template prewarm: on (the cached block template is rebuilt on every virtual change; IGNEUM_TEMPLATE_PREWARM=0 turns it off) +2026-10-07 15:12:35.141+02:00 [INFO ] GRPC Server starting on: 127.0.0.1:29760 +2026-10-07 15:12:35.141+02:00 [INFO ] P2P Server starting on: 127.0.0.1:29761 +2026-10-07 15:12:35.141+02:00 [INFO ] [igneum-exec] eth_ JSON-RPC listening on 127.0.0.1:26790 +2026-10-07 15:12:35.141+02:00 [INFO ] [igneum-exec] proof verifier: Off (no SP1 verification on this node) +2026-10-07 15:12:35.142+02:00 [INFO ] [igneum-exec] chain follower started +2026-10-07 15:12:35.142+02:00 [INFO ] WRPC Server starting on: 127.0.0.1:29762 +2026-10-07 15:12:35.142+02:00 [WARN ] [igneum-exec] cannot bind the eth_ JSON-RPC server on 127.0.0.1:26790: Address already in use (os error 98) +2026-10-07 15:12:35.142+02:00 [INFO ] [igneum-exec] exec sync: sink edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block 0; pruning point edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block Some(0) (DAA 0); retention root edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block Some(0) (DAA 0), its body held +2026-10-07 15:12:35.142+02:00 [INFO ] [igneum-exec] exec sync: no snapshot to resume from (no snapshot file); the follower starts at genesis +2026-10-07 15:12:35.142+02:00 [INFO ] [igneum-exec] chain follower stopped +^SIGTERM - shutting down... +2026-10-07 15:13:00.089+02:00 [INFO ] P2P Server stopped: 127.0.0.1:29761 +2026-10-07 15:13:00.089+02:00 [INFO ] GRPC Server stopped on: 127.0.0.1:29760 +2026-10-07 15:13:00.089+02:00 [INFO ] WRPC Server stopped on: 127.0.0.1:29762 +2026-10-07 15:13:00.597+02:00 [INFO ] igneumd has stopped... diff --git a/docs/design/genesis-forward-harness/digest-testnet-shape.log b/docs/design/genesis-forward-harness/digest-testnet-shape.log new file mode 100644 index 00000000..c8c6590c --- /dev/null +++ b/docs/design/genesis-forward-harness/digest-testnet-shape.log @@ -0,0 +1,32 @@ +Signature scheme byte from the override file: genesis scheme 0 (0 = BLS12-381); every vote item and key reveal carries its scheme byte on the wire from DAA score 0; any other scheme refused until a class the 95 percent signal moves to names it +Key succession (W5) from the override file: a vote key hands its window weight and its forfeit term to a successor key once, from checkpoint DAA score 0; the successor inherits the window +Latency ladder from the override file: rungs 27, 35, 53, [88], [173], [267] shadow passes, cache [512 MiB] beside them (brackets: inadmissible, never entered), active from epoch 0 (DAA score 0 rounded up to the epoch boundary at 0), one rung per decision at 90 percent of blue blocks in each of 7 consecutive windows of 86400 DAA ending at an epoch's seed block +Latency ladder active: rungs 27, 35, 53, [88], [173], [267] shadow passes, cache [512 MiB] beside them, this node signals none (header version bits 15 and 14; both set asks for the cache rung) +Program class signal inactive (the window or the floor is absent from the override file): headers carry block version 2 exactly +Fees on igneum-devnet-973: pgas table v0, B_p 30000000 pgas, S_p 7500000 pgas, floors 1000000000 wei per gas and 1000000000 wei per pgas; calibrated v1 from DAA score never +Consensus params digest: 60e842a738c7dea04543af93e990fb962618ace0b76b38013a63cb29dd45644a (exchanged in the p2p handshake; a peer with another digest is refused) +2026-10-07 15:13:26.156+02:00 [INFO ] igneumd/2.1.0-75810130 +2026-10-07 15:13:26.156+02:00 [INFO ] Application directory: gf-digest/d-testnet-shape +2026-10-07 15:13:26.156+02:00 [INFO ] Data directory: gf-digest/d-testnet-shape/igneum-devnet-973/datadir +2026-10-07 15:13:26.156+02:00 [INFO ] Logs to console only +2026-10-07 15:13:26.172+02:00 [INFO ] Finality v2 (igneum-devnet-973): interval 30 depth 20 window 7200 DAA dust 5 presence 20 aggregators 8 ban 7200 fold 3; rule v3 (frozen table, certificate fold) from checkpoint DAA never; 0 checkpoints known, next index 1, 0 locks, 0 keys; C1 in DAA seconds from DAA never; weight-gated deep fork choice from DAA never; leave rule (W7, delay 3600 DAA) from checkpoint DAA never, 0 leaves; key succession (W5) from checkpoint DAA 0, 0 successions; signature scheme 0 (0 = BLS12-381), any other refused until a class names it +2026-10-07 15:13:26.180+02:00 [INFO ] [igneum-exec] proving v0: payouts from DAA score never, window 7200 DAA, dust 5, verifier Off +2026-10-07 15:13:26.180+02:00 [INFO ] [igneum-exec] proving v1: segment records from DAA score never, 8 blocks a segment, unproven after 600 DAA, aggregator share 1000 bps, shard program id unknown, aggregator id unknown +2026-10-07 15:13:26.180+02:00 [INFO ] [igneum-exec] proof archive at gf-digest/d-testnet-shape/igneum-devnet-973/datadir/evm/proofs: 0 proofs +2026-10-07 15:13:26.181+02:00 [INFO ] [igneum-exec] verifying keys embedded: shard program id 0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a aggregator id 0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896 +2026-10-07 15:13:26.185+02:00 [INFO ] template prewarm: on (the cached block template is rebuilt on every virtual change; IGNEUM_TEMPLATE_PREWARM=0 turns it off) +2026-10-07 15:13:26.186+02:00 [INFO ] GRPC Server starting on: 127.0.0.1:29760 +2026-10-07 15:13:26.186+02:00 [INFO ] P2P Server starting on: 127.0.0.1:29761 +2026-10-07 15:13:26.186+02:00 [INFO ] [igneum-exec] eth_ JSON-RPC listening on 127.0.0.1:26790 +2026-10-07 15:13:26.186+02:00 [INFO ] WRPC Server starting on: 127.0.0.1:29762 +2026-10-07 15:13:26.186+02:00 [INFO ] [igneum-exec] chain follower started +2026-10-07 15:13:26.186+02:00 [INFO ] [igneum-exec] proof verifier: Off (no SP1 verification on this node) +2026-10-07 15:13:26.186+02:00 [WARN ] [igneum-exec] cannot bind the eth_ JSON-RPC server on 127.0.0.1:26790: Address already in use (os error 98) +2026-10-07 15:13:26.186+02:00 [INFO ] [igneum-exec] exec sync: sink edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block 0; pruning point edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block Some(0) (DAA 0); retention root edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 is chain block Some(0) (DAA 0), its body held +2026-10-07 15:13:26.186+02:00 [INFO ] [igneum-exec] exec sync: no snapshot to resume from (no snapshot file); the follower starts at genesis +2026-10-07 15:13:26.186+02:00 [INFO ] [igneum-exec] chain follower stopped +^SIGTERM - shutting down... +2026-10-07 15:13:51.152+02:00 [INFO ] P2P Server stopped: 127.0.0.1:29761 +2026-10-07 15:13:51.152+02:00 [INFO ] WRPC Server stopped on: 127.0.0.1:29762 +2026-10-07 15:13:51.152+02:00 [INFO ] GRPC Server stopped on: 127.0.0.1:29760 +2026-10-07 15:13:51.660+02:00 [INFO ] igneumd has stopped... diff --git a/docs/design/genesis-forward-harness/known-failed-no-succession.json b/docs/design/genesis-forward-harness/known-failed-no-succession.json new file mode 100644 index 00000000..461105de --- /dev/null +++ b/docs/design/genesis-forward-harness/known-failed-no-succession.json @@ -0,0 +1,695 @@ +{ + "expect": "no-succession", + "pass": false, + "checks": { + "window_filled_before_the_succession": true, + "succession_accepted_on_submit": true, + "carried_once_on_every_node": false, + "successor_inherits_on_every_node": false, + "old_key_handed_over_on_every_node": false, + "nodes_agree_on_the_successor_weight": false, + "refused_old_again_on_n2": false, + "refused_old_again_on_n0": false, + "refused_successor_that_handed_over": false, + "scheme_1_refused_by_every_node": true, + "locks_continue_after_the_fold": true, + "zero_rejected_by_nodes": true, + "sinks_agree": true + }, + "old_key": "e4036b1e79c817f2", + "new_key": "2f031ed35a29ced8", + "old_blocks_before": 41, + "succeeded_at_daa": 261, + "carried_seen_at_daa": null, + "new_mined_alone": 112, + "rows": [ + { + "new": { + "blocks": 37, + "keyHash": "2f031ed35a29ced8", + "participation": 1, + "pubkey": "80ab38c523736ad8944c7d3375e7563ba3b0d5a3ab149bec568cf207edcc9e1ab1ee2566e06ff422a5ec4c85a4049976", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "", + "voter": true + }, + "old": { + "blocks": 0, + "keyHash": "e4036b1e79c817f2", + "participation": 0, + "pubkey": "b0fd8eebbbaad96268e5f7b8a86090ca0c723954a0a5cb81c92b633094c1742b2505c4f7cea646c5c96bb52e57400067", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "6543d321fd61aedb", + "voter": false + } + }, + { + "new": { + "blocks": 0, + "keyHash": "2f031ed35a29ced8", + "participation": 0, + "pubkey": "80ab38c523736ad8944c7d3375e7563ba3b0d5a3ab149bec568cf207edcc9e1ab1ee2566e06ff422a5ec4c85a4049976", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "e4036b1e79c817f2", + "voter": false + }, + "old": { + "blocks": 0, + "keyHash": "e4036b1e79c817f2", + "participation": 0, + "pubkey": "b0fd8eebbbaad96268e5f7b8a86090ca0c723954a0a5cb81c92b633094c1742b2505c4f7cea646c5c96bb52e57400067", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "6543d321fd61aedb", + "voter": false + } + }, + { + "new": { + "blocks": 37, + "keyHash": "2f031ed35a29ced8", + "participation": 1, + "pubkey": "80ab38c523736ad8944c7d3375e7563ba3b0d5a3ab149bec568cf207edcc9e1ab1ee2566e06ff422a5ec4c85a4049976", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "", + "voter": true + }, + "old": { + "blocks": 0, + "keyHash": "e4036b1e79c817f2", + "participation": 0, + "pubkey": "b0fd8eebbbaad96268e5f7b8a86090ca0c723954a0a5cb81c92b633094c1742b2505c4f7cea646c5c96bb52e57400067", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "6543d321fd61aedb", + "voter": false + } + } + ], + "locks": [ + 12, + 12, + 12 + ], + "locks_at_fold": 9, + "refusals": [ + { + "what": "w5-old -> w5-third on n2", + "code": 0, + "line": "1791378723.612 SUCCEED old=e4036b1e79c817f2 new=6543d321fd61aedb daa=502 (accepted: carried in this node's next block)" + }, + { + "what": "w5-old -> w5-third on n0", + "code": 0, + "line": "1791378723.629 SUCCEED old=e4036b1e79c817f2 new=6543d321fd61aedb daa=502 (accepted: carried in this node's next block)" + }, + { + "what": "w5-new -> w5-old on n1", + "code": 0, + "line": "1791378723.645 SUCCEED old=2f031ed35a29ced8 new=e4036b1e79c817f2 daa=502 (accepted: carried in this node's next block)" + } + ], + "probes": [ + { + "node": 0, + "code": 0, + "line": "1791378723.659 SCHEME 1 REFUSED key=b875b095c1b5d559 index=16 (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)" + }, + { + "node": 1, + "code": 0, + "line": "1791378723.672 SCHEME 1 REFUSED key=b875b095c1b5d559 index=16 (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)" + }, + { + "node": 2, + "code": 0, + "line": "1791378723.687 SCHEME 1 REFUSED key=b875b095c1b5d559 index=16 (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)" + } + ], + "samples": [ + { + "t": 5.7, + "daa": 0, + "phase": "fill", + "weights": [ + "?", + "?", + "?" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 20.7, + "daa": 7, + "phase": "fill", + "weights": [ + "?", + "?", + "?" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 35.7, + "daa": 17, + "phase": "fill", + "weights": [ + "?", + "?", + "?" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 50.7, + "daa": 36, + "phase": "fill", + "weights": [ + "?", + "?", + "?" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 65.7, + "daa": 57, + "phase": "fill", + "weights": [ + "29/3", + "29/3", + "29/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 80.8, + "daa": 79, + "phase": "fill", + "weights": [ + "29/3", + "29/3", + "29/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 95.8, + "daa": 92, + "phase": "fill", + "weights": [ + "59/3", + "59/3", + "59/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 110.8, + "daa": 104, + "phase": "fill", + "weights": [ + "59/3", + "59/3", + "59/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 125.8, + "daa": 114, + "phase": "fill", + "weights": [ + "89/3", + "89/3", + "89/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 140.8, + "daa": 123, + "phase": "fill", + "weights": [ + "89/3", + "89/3", + "89/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 155.8, + "daa": 135, + "phase": "fill", + "weights": [ + "89/3", + "89/3", + "89/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 170.9, + "daa": 152, + "phase": "fill", + "weights": [ + "119/3", + "119/3", + "119/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 185.9, + "daa": 173, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 1, + 1, + 1 + ] + }, + { + "t": 200.9, + "daa": 187, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 1, + 1, + 1 + ] + }, + { + "t": 215.9, + "daa": 203, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 2, + 2, + 2 + ] + }, + { + "t": 230.9, + "daa": 224, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 2, + 2, + 2 + ] + }, + { + "t": 246, + "daa": 242, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 3, + 3, + 3 + ] + }, + { + "t": 261, + "daa": 258, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 3, + 3, + 3 + ] + }, + { + "t": 276.5, + "daa": 270, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 291.6, + "daa": 285, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 306.6, + "daa": 308, + "phase": "carry", + "weights": [ + "118/3", + "118/3", + "118/3" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 321.7, + "daa": 338, + "phase": "carry", + "weights": [ + "120/4", + "120/4", + "120/4" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 336.7, + "daa": 357, + "phase": "carry", + "weights": [ + "120/4", + "120/4", + "120/4" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 351.8, + "daa": 368, + "phase": "carry", + "weights": [ + "120/4", + "120/4", + "120/4" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 366.9, + "daa": 385, + "phase": "carry", + "weights": [ + "120/4", + "120/4", + "120/4" + ], + "locks": [ + 5, + 5, + 5 + ] + }, + { + "t": 382, + "daa": 406, + "phase": "carry", + "weights": [ + "120/4", + "120/4", + "120/4" + ], + "locks": [ + 5, + 5, + 5 + ] + }, + { + "t": 397, + "daa": 424, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 6, + 6, + 6 + ] + }, + { + "t": 412.1, + "daa": 441, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 7, + 7, + 7 + ] + }, + { + "t": 427.2, + "daa": 454, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 7, + 7, + 7 + ] + }, + { + "t": 442.3, + "daa": 469, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 7, + 7, + 7 + ] + }, + { + "t": 457.3, + "daa": 485, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 8, + 8, + 8 + ] + }, + { + "t": 472.4, + "daa": 494, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 8, + 8, + 8 + ] + }, + { + "t": 487.6, + "daa": 509, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 9, + 9, + 9 + ] + }, + { + "t": 502.6, + "daa": 526, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 9, + 9, + 9 + ] + }, + { + "t": 517.6, + "daa": 545, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 10, + 10, + 10 + ] + }, + { + "t": 532.7, + "daa": 561, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 11, + 11, + 11 + ] + }, + { + "t": 547.7, + "daa": 578, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 11, + 11, + 11 + ] + } + ], + "wall_s": 560.2, + "binaries": { + "igneumd": "/srv/builds/igneum-wt-genesis-forward/vendor/igneum-node-gf/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-genesis-forward/vendor/igneum-node-gf/target/release/igneum-miner" + } +} \ No newline at end of file diff --git a/docs/design/genesis-forward-harness/pass-succession.json b/docs/design/genesis-forward-harness/pass-succession.json new file mode 100644 index 00000000..c3ecc7e7 --- /dev/null +++ b/docs/design/genesis-forward-harness/pass-succession.json @@ -0,0 +1,455 @@ +{ + "expect": "succession", + "pass": true, + "checks": { + "window_filled_before_the_succession": true, + "succession_accepted_on_submit": true, + "carried_once_on_every_node": true, + "successor_inherits_on_every_node": true, + "old_key_handed_over_on_every_node": true, + "nodes_agree_on_the_successor_weight": true, + "refused_old_again_on_n2": true, + "refused_old_again_on_n0": true, + "refused_successor_that_handed_over": true, + "scheme_1_refused_by_every_node": true, + "locks_continue_after_the_fold": true, + "zero_rejected_by_nodes": true, + "sinks_agree": true + }, + "old_key": "e4036b1e79c817f2", + "new_key": "2f031ed35a29ced8", + "old_blocks_before": 42, + "succeeded_at_daa": 260, + "carried_seen_at_daa": 266, + "new_mined_alone": 29, + "rows": [ + { + "new": { + "blocks": 37, + "keyHash": "2f031ed35a29ced8", + "participation": 1, + "pubkey": "80ab38c523736ad8944c7d3375e7563ba3b0d5a3ab149bec568cf207edcc9e1ab1ee2566e06ff422a5ec4c85a4049976", + "strippedUntilDaa": 0, + "succeededFrom": "e4036b1e79c817f2", + "succeededTo": "", + "voter": true + }, + "old": { + "blocks": 0, + "keyHash": "e4036b1e79c817f2", + "participation": 0, + "pubkey": "b0fd8eebbbaad96268e5f7b8a86090ca0c723954a0a5cb81c92b633094c1742b2505c4f7cea646c5c96bb52e57400067", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "2f031ed35a29ced8", + "voter": false + } + }, + { + "new": { + "blocks": 37, + "keyHash": "2f031ed35a29ced8", + "participation": 1, + "pubkey": "80ab38c523736ad8944c7d3375e7563ba3b0d5a3ab149bec568cf207edcc9e1ab1ee2566e06ff422a5ec4c85a4049976", + "strippedUntilDaa": 0, + "succeededFrom": "e4036b1e79c817f2", + "succeededTo": "", + "voter": true + }, + "old": { + "blocks": 0, + "keyHash": "e4036b1e79c817f2", + "participation": 0, + "pubkey": "b0fd8eebbbaad96268e5f7b8a86090ca0c723954a0a5cb81c92b633094c1742b2505c4f7cea646c5c96bb52e57400067", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "2f031ed35a29ced8", + "voter": false + } + }, + { + "new": { + "blocks": 37, + "keyHash": "2f031ed35a29ced8", + "participation": 1, + "pubkey": "80ab38c523736ad8944c7d3375e7563ba3b0d5a3ab149bec568cf207edcc9e1ab1ee2566e06ff422a5ec4c85a4049976", + "strippedUntilDaa": 0, + "succeededFrom": "e4036b1e79c817f2", + "succeededTo": "", + "voter": true + }, + "old": { + "blocks": 0, + "keyHash": "e4036b1e79c817f2", + "participation": 0, + "pubkey": "b0fd8eebbbaad96268e5f7b8a86090ca0c723954a0a5cb81c92b633094c1742b2505c4f7cea646c5c96bb52e57400067", + "strippedUntilDaa": 0, + "succeededFrom": "", + "succeededTo": "2f031ed35a29ced8", + "voter": false + } + } + ], + "locks": [ + 7, + 7, + 7 + ], + "locks_at_fold": 4, + "refusals": [ + { + "what": "w5-old -> w5-third on n2", + "code": 3, + "line": "1791379651.057 SUCCEED REFUSED old=e4036b1e79c817f2 new=6543d321fd61aedb daa=290 (refused: key e4036b1e79c817f2 has already handed its weight to 2f031ed35a29ced8; a key hands over once)" + }, + { + "what": "w5-old -> w5-third on n0", + "code": 3, + "line": "1791379651.072 SUCCEED REFUSED old=e4036b1e79c817f2 new=6543d321fd61aedb daa=290 (refused: key e4036b1e79c817f2 has already handed its weight to 2f031ed35a29ced8; a key hands over once)" + }, + { + "what": "w5-new -> w5-old on n1", + "code": 3, + "line": "1791379651.085 SUCCEED REFUSED old=2f031ed35a29ced8 new=e4036b1e79c817f2 daa=290 (refused: successor e4036b1e79c817f2 has itself handed its weight to 2f031ed35a29ced8; it signs nothing and can inherit nothing)" + } + ], + "probes": [ + { + "node": 0, + "code": 0, + "line": "1791379651.097 SCHEME 1 REFUSED key=b875b095c1b5d559 index=9 (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)" + }, + { + "node": 1, + "code": 0, + "line": "1791379651.110 SCHEME 1 REFUSED key=b875b095c1b5d559 index=9 (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)" + }, + { + "node": 2, + "code": 0, + "line": "1791379651.123 SCHEME 1 REFUSED key=b875b095c1b5d559 index=9 (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)" + } + ], + "samples": [ + { + "t": 5.6, + "daa": 0, + "phase": "fill", + "weights": [ + "?", + "?", + "?" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 20.6, + "daa": 37, + "phase": "fill", + "weights": [ + "?", + "?", + "?" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 35.6, + "daa": 56, + "phase": "fill", + "weights": [ + "28/3", + "28/3", + "28/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 50.6, + "daa": 71, + "phase": "fill", + "weights": [ + "28/3", + "28/3", + "28/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 65.6, + "daa": 85, + "phase": "fill", + "weights": [ + "58/3", + "58/3", + "58/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 80.6, + "daa": 106, + "phase": "fill", + "weights": [ + "58/3", + "58/3", + "58/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 95.6, + "daa": 126, + "phase": "fill", + "weights": [ + "88/3", + "88/3", + "88/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 110.6, + "daa": 141, + "phase": "fill", + "weights": [ + "118/3", + "118/3", + "118/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 125.6, + "daa": 155, + "phase": "fill", + "weights": [ + "118/3", + "118/3", + "118/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 140.6, + "daa": 166, + "phase": "fill", + "weights": [ + "118/3", + "118/3", + "118/3" + ], + "locks": [ + 0, + 0, + 0 + ] + }, + { + "t": 155.7, + "daa": 185, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 1, + 1, + 1 + ] + }, + { + "t": 170.7, + "daa": 202, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 2, + 2, + 2 + ] + }, + { + "t": 185.7, + "daa": 213, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 2, + 2, + 2 + ] + }, + { + "t": 200.7, + "daa": 229, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 2, + 2, + 2 + ] + }, + { + "t": 215.7, + "daa": 244, + "phase": "fill", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 3, + 3, + 3 + ] + }, + { + "t": 233.2, + "daa": 261, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 248.3, + "daa": 280, + "phase": "carry", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 4, + 4, + 4 + ] + }, + { + "t": 263.4, + "daa": 300, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 5, + 5, + 5 + ] + }, + { + "t": 278.4, + "daa": 316, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 5, + 5, + 5 + ] + }, + { + "t": 293.4, + "daa": 328, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 6, + 6, + 6 + ] + }, + { + "t": 308.4, + "daa": 343, + "phase": "after", + "weights": [ + "120/3", + "120/3", + "120/3" + ], + "locks": [ + 6, + 6, + 6 + ] + } + ], + "wall_s": 317, + "binaries": { + "igneumd": "/srv/builds/igneum-wt-genesis-forward/vendor/igneum-node-gf/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-genesis-forward/vendor/igneum-node-gf/target/release/igneum-miner" + } +} \ No newline at end of file diff --git a/docs/design/genesis-forward.md b/docs/design/genesis-forward.md new file mode 100644 index 00000000..e70f32e0 --- /dev/null +++ b/docs/design/genesis-forward.md @@ -0,0 +1,85 @@ +# Genesis forward-compatibility: the scheme byte, key succession, the cache rung + +7 October 2026, 10:1x UK, the project lead's order to build mission item 8 now (`docs/analysis/mission/mission.md` section 2.8; the research in `docs/analysis/mission/future.md` sections 1.3, 7 and 10 and `docs/design/finality-in-proof.md` section 7). Branch `genesis-forward` on the node fork (from release-0.3.19-node dc141409, the merged line that carries the ladder and the W7 leave item, which ca3-v4-0318 alone does not) and `genesis-forward` on the repo. Three genesis fields, every switch never on the devnet (its digest does not move), all three set at the testnet genesis by the testnet lane, which holds the cut and re-pins. The class-group VDF's quantum fallback is flagged in spec 04 section 4.8, not built. + +## 1. The scheme byte + +| Item | Place | Value | +|---|---|---| +| The byte | `finality::Vote::sig_scheme`, `finality::KeyReveal::sig_scheme`, `finality::Succession::successor_scheme` | `SIG_SCHEME_BLS12_381` = 0 everywhere today | +| The genesis value | `Params::sig_scheme` (override key `sig_scheme`) | 0 on every network | +| The switch | `Params::sig_scheme_activation_daa` (override key `sig_scheme_activation_daa`; `u64::MAX` = never) | never on devnet, simnet, mainnet; 0 at the testnet genesis | +| The digest | both fields enter once the switch is set (the 0.3.15 rule) | the devnet's digest unchanged; the testnet's moves at the cut | +| The wire, plain | vote item tag 1 (`Vote::LEN` = 280 bytes), evidence tag 3, reveal `IGNK` + 288 hex: scheme 0 implied | byte for byte what every live network carries | +| The wire, explicit | vote item tag 5 = `scheme \|\| vote`, evidence tag 6 = `scheme \|\| first \|\| second`, reveal `IGNS` + 2 hex of the scheme + 288 hex | written by every template once the switch is active (`encode_section_explicit_within`); a vote of any other scheme is always explicit, so a scheme the node does not run is never mistaken for one it does | +| The active scheme | `igneum::active_sig_scheme(genesis, class)` = the scheme the program class at the sink names (`SIG_SCHEME_OF_CLASS`, a genesis table with no row today), else the genesis byte; the finality manager re-reads it at every virtual change | 0 | +| The refusal | `FinalityManager::scheme_refusal`: a reveal is not registered, a vote is not recorded, carried or gossiped, a successor is refused; the RPC answers `refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one` | every node, whatever its switch | + +Why a class change names the scheme: the flip is the P2 mechanism (95 percent of mining weight over a window with a floor height, the one path a consensus change takes on this chain), and the aggregated-vote format must ship first (naive ML-DSA-44 votes at 8,192 voters cost 19.4 MB a checkpoint and 57 GB a day, `future.md` 7.3; with 250x SNARK aggregation about 223 MB a day). Adding a row to the table is a code change under the class path; the byte is in every item from genesis so the row costs no fork. + +## 2. Key succession, W5 + +| Item | Place | Value | +|---|---|---| +| The item | `finality::Succession` (tag 7, 297 bytes): `daa`, old key, successor key, successor scheme, the old key's signature, the successor's signature, both over `"igneum-succeed-v1/" \|\| chain_id \|\| 0 \|\| daa \|\| old \|\| new \|\| scheme` under `IGNEUM_SUCCEED_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_` | the successor's signature is its consent and its proof of possession in one | +| The switch | `Params::finality_succession_activation_daa` (override key of the same name) | never everywhere; 0 at the testnet genesis; in the digest once set | +| Submission | `submitFinalitySuccession` (RPC op 158, gRPC 1131/1132, wRPC, `igneum-miner succeed `) | carried after the leaves in the templates of the node that holds it; no p2p gossip kind (the successor's own node mines it) | +| The fold | `successions_at` (deterministic like `leaves_at`: the lowest-DAA carrier in C's past dates it) and `fold_successions` inside `voters_at`: the old key's window blocks are credited to the successor as they stand (count and oldest block), the old key leaves the table, a ban or a leave on the old key lands on the successor; the successor's presence counts the old key's carried votes | from the first checkpoint whose past holds the carrier; the window inherited, not a fresh one | +| Once | one record per old key: a second succession from a key that handed over is refused (`already handed its weight to`), a successor that has itself handed over is refused (`has itself handed`), which also refuses every cycle; a chain old to new to newer is legal | a record outlives the weight it moved by one window, then is trimmed | +| After | the old key's votes are refused (`handed its weight to`), never counted, never carried | the old key is dead | +| The report | `getFinalityWeights`: `succeededFrom` on the successor's row, a weightless row for the old key with `succeededTo` | both nodes of the unit test agree on every voter list | + +Not in this round: a p2p gossip kind for successions (the leave's shape, protocol version bump); the app's "rotate key" button, which signs the item from the old key's label and restarts the miner under the new label (the `succeed` subcommand is the primitive); the aggregated-vote format. + +## 3. The cache rung beside N + +| Item | Place | Value | +|---|---|---| +| The rung | `igneum::CacheRung { mib, admissible }` as `LatencyLadder::cache_rung` (override key `latency_ladder_cache_rung`) | `{512, false}` at genesis; a power of two above the 256 MiB genesis cache | +| The signal | `LadderSignal::Cache` = both ladder bits set (header version 0xc000; until today both set was "no signal" and no node ever stamped it, so no block written so far changes meaning); `IGNEUM_LADDER_SIGNAL=cache` | code 3 in `PowEpochInfo::latency_ladder_signal` | +| The rule | `latency_ladder_step_signalled_with_cache`: the cache step moves 0 to 1 when every one of the newest seven windows reaches 90 percent for the cache rung, the rung is admissible and the cool-down holds (the oldest window begins after the last decision, shared with N); never back; never in the same decision as N (one signal per block, exclusive shares) | `LadderState::cache_step` | +| The digest | the rung's size and flag enter with the ladder, once `latency_ladder_activation_daa` is set | the testnet's digest moves at the cut | +| The RPC | `powEpoch.latencyLadderCacheStep`, `nextLatencyLadderCacheStep`, `latencyLadderCacheMib`, `nextLatencyLadderCacheMib`, `latencyLadderCacheBps`, `latencyLadderCacheWeakestBps`, `latencyLadderCacheAdmissible` (proto fields 37 to 43); the daemon's ladder line (`cache [512 MiB]`) | the rung visible on every node | +| The gate | `admissible` in the genesis list, false until measured: the cold verify of one warp with the 512 MiB cache on the reference core with its SMT sibling loaded under 10 ms (the verifier reads the cache, so this is the bound), the day-cache build on a 2019-class core under twice today's, and the 8 GB tier still holding dataset, cache and the prover footprint | the rule never enters an inadmissible rung (tested) | + +Why beside N and not a seventh N rung: the six approved rungs and their indices stand (the project lead, 7 October 2026, 09:3x UK); a rung inserted in the list would either sit behind the three inadmissible rungs (unreachable) or shift the approved indices. A second lever on the same signal carrier keeps the list as approved and the cool-down shared. + +Owed with the measurement: the engine's consumption of `cache_mib` (`EpochSeeds` carries `shadow_reps` today and no cache size; the pack and the three hosts build a 256 MiB cache), so the flag stays false until the path exists and is measured. Per tier what the rung means: every tier from 8 GB holds a 512 MiB cache; the day-cache build doubles (about 0.7 s on the reference core today, approximate, from the class v4 fill line); the Apple tier's unified memory holds it; a pool user does nothing. + +## 4. The class-group VDF under a quantum computer + +Flagged in spec 04 section 4.8, not sized: Shor computes the class-group order, which removes the sequentiality assumption of the Wesolowski VDF, so an attacker with a cryptographically relevant quantum computer grinds the hourly seed (a liveness nuisance against the lottery, not a safety break; finality rests on the vote keys of section 1). The fallback is a hash-chain delay behind the same version byte, designed when the scheme flip is scheduled. + +## 5. Gates + +| Gate | Where | Result | +|---|---|---| +| The digest test | `consensus_digest_covers_every_consensus_field_and_nothing_else` (30 edits; the scheme byte and the cache rung alone move nothing), `override_params_carry_the_genesis_forward_fields_and_the_digest_moves_only_when_set` | section 6 | +| Scheme 1 refused by every node until the signal | unit: `a_vote_reveal_or_successor_of_another_signature_scheme_is_refused_until_a_class_names_it` (RPC, in a block, a reveal, a successor; the explicit template form); fast-time: `probe-scheme` on three nodes | section 6 | +| A succession carried once and refused twice | unit: `a_key_hands_its_window_to_a_successor_once_and_a_second_succession_is_refused` (two nodes); fast-time: `infra/fast-time/key-succession.mjs` (the known-failed case `--expect no-succession` first) | section 6 | +| The ladder rung visible in the RPC | `powEpoch.latencyLadderCache*` on `getBlockTemplate`, the daemon line; unit: `latency_ladder_rule` (an inadmissible cache rung never entered; with the flag, 90 percent in seven windows enters it, N still steps after it, one rung, never back) | section 6 | +| The codec | `scheme_byte_and_succession_items_round_trip_and_an_older_decoder_stops_at_them` | section 6 | + +## 6. Results (7 October 2026, 12:5x to 14:3x UK; igneum-build-1 for the gate build, the harness and the digests, igneum-build-2 for the suites) + +| Gate | Run | Result | +|---|---|---| +| The digest test | `cargo test --release -p kaspa-consensus-core --lib` on build-2 at 75810130 | 124 passed, 0 failed, 2 ignored (`consensus_digest_covers_every_consensus_field_and_nothing_else` with 30 edits, `override_params_carry_the_genesis_forward_fields_and_the_digest_moves_only_when_set`, `latency_ladder_rule` with the cache rung) | +| The 60x keeper test | `fast_time_60x_file_is_the_devnet_at_60x` on build-2 against the completed file (repo 9c9a1f52) | 1 passed (the file had lacked 17 fields on master, `emission` and `proving_consensus_verify_daa` among them; the box mirrors carry no `infra/`, so the test skips there unless the file is shipped) | +| Scheme 1 refused by every node | unit `a_vote_reveal_or_successor_of_another_signature_scheme_is_refused_until_a_class_names_it`; fast-time `probe-scheme` on three nodes, both harness cases | green in the suite runs; every node: `SCHEME 1 REFUSED ... (refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one)` | +| A succession carried once and refused twice | unit `a_key_hands_its_window_to_a_successor_once_and_a_second_succession_is_refused` (two nodes); fast-time `infra/fast-time/key-succession.mjs` on build-1 (3 nodes, one CPU miner each, override-60x with the three switches at 0) | known-failed case first (`--expect no-succession`, 13:04 to 13:13 UK, `genesis-forward-harness/known-failed-no-succession.json`): FAIL as it must on every carried-once check with the probe, the locks and the sinks holding. Pass case (`--expect succession`, node bdb34f62, 13:23 to 13:28 UK, `pass-succession.json`): PASS, every check holds: w5-old held 42 blocks at DAA 260; the succession accepted on n2 at DAA 261 and carried by a block at DAA 266 on every node; at the fold (DAA 290) every node reads w5-new 37 blocks (7 mined alone) and w5-old 0 with `succeededTo`; w5-old to w5-third refused on n2 and n0 (`already handed`), w5-new to w5-old refused on n1 (`has itself handed`); locks 4 to 7 on every node after the fold; 0 rejected blocks, sinks agree; 317 s wall | +| The cache rung visible in the RPC | `powEpoch.latencyLadderCache*` (proto fields 37 to 43); the daemon's ladder line | the testnet-shaped file prints `rungs 27, 35, 53, [88], [173], [267] shadow passes, cache [512 MiB] beside them` (`digest-testnet-shape.log`) | +| The codec | `scheme_byte_and_succession_items_round_trip_and_an_older_decoder_stops_at_them` | green in the suite runs | +| The digest, cross-binary | igneumd 75810130 against the 0.3.20 base dc141409 (bs0319's build), both with no file, devnet suffix 973 | both `079d8a7e736abbd4` (`digest-no-file.log`, `digest-base-dc141409.log`): the three fields at never move nothing; the ladder alone at 0 reads `772f9f8e3ef59ca1`, the testnet-shaped file (ladder at 0, scheme switch at 0, succession at 0, the cache rung) `60e842a738c7dea0`, on devnet params; the testnet lane's own number comes from `TESTNET_PARAMS` at its cut. The 0.3.18 line's `c562d70e` is behind the decimals, tail-emission and subsidy fields of the 0.3.19 and 0.3.20 lines, not behind these | +| The gate build | `tools/build-remote.sh --priority gate` on build-1 at bdb34f62 | igneumd 57,554,336 B sha256 6d0aa37b..., igneum-miner 10,240,768 B sha256 69fc3c63... (commit string carried) | +| The consensus suite | `cargo test --release -p kaspa-consensus` (all targets) on build-2 at f95178a1, twice | 114 passed, 0 failed, 3 ignored in the lib binary both times, the two moved targets 1 each; `cargo check -p kaspad` clean. Before the fix below the lib binary failed 1 of 114 on one of the two-node tests in three of four runs (the succession test once, the pre-existing F23 test twice), node 1 refusing block 61 at DAA 60 with `UnexpectedDifficulty`, the two nodes' bits about 17,000 apart in the mantissa | + +Faults found on the way, both mine: (1) rule v3's frozen table stood at the lock before the carrier, where the old key still weighed and signed nothing, so nothing locked after the fold (fixed in `frozen_table`, 9322cc1d); (2) the template read the explicit-form switch from the process-wide static that only the daemon installs, so `TestConsensus` wrote the plain form (the manager holds the activation now, daa61847). + +### 6a. The two-node refusal: found and fixed (f95178a1) + +The probe on build-2: F23 alone three times, green each time; the three two-node tests together three times, green each time; so the refusal needed the rest of the lib binary. The cause: `consensus/src/consensus/services.rs` built the difficulty manager with `igneum::pow_epoch_blocks()`, the process-wide static, where every other argument of that constructor comes from `params`; two pruning-proof tests in the same binary (`igneum_m20_tests.rs:27`, `igneum_pow.rs:346`) install a 60-block schedule process-wide, so a `TestConsensus` built inside that window read a 60-block epoch into its difficulty manager while its partner read 3,600, the two disagreed on `reference_window` from DAA 60, and the second node refused block 61, the exact block of every refusal. The fix is the manager's own field, `params.pow_epoch_blocks`. The node's behaviour is unchanged (the daemon installs the static from the same params before building the consensus); the class is the static-at-construction read, the sibling of the signal-table race the node lane moved two installing tests for on 7 October 2026. The test helper now names the node and the block it refuses, which is what found it. + +## 7. For the testnet lane + +Override keys and testnet values: `sig_scheme: 0`, `sig_scheme_activation_daa: 0`, `finality_succession_activation_daa: 0`, `latency_ladder_cache_rung: {"mib": 512, "admissible": false}` (the six N rungs unchanged). Digest: with the ladder already active from genesis the cache rung's two fields enter after the six rungs' fields; the scheme switch adds two fields, the succession switch one. `print_testnet_object` prints the four keys. diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 6944a3f9..d23f00b1 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -299,7 +299,7 @@ Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Finality ends wi ### F11. VDFs are exotic "A class-group VDF with Wesolowski proofs in a consensus-critical path, in a project with no cryptographer. Chia needed years and still got timelord ASICs." -Status: Answered by design, with the dependency conceded. +Status: Answered by design, with the dependency conceded. Update 7 October 2026 (era VDF lane): the era VDF is in the node (spec 4.4 Implemented, behind `era_vdf_activation_daa`, never until the project lead sets it per network), on a fixed-width integer with no C library, with the hash-chain fallback behind the genesis scheme byte for the day a class group's order is computable; the attack pass's F7 harness fires against the stand-in (1 of 6 cuts re-rolled at no delay) and is silent against the VDF (0 of 6); the measured rates, prove and verify times and the margin against the fastest known prover (chiavdf's AVX-512 path on the same box) are in `docs/analysis/era-vdf-2026-10-07.md`. The timelord-ASIC point is answered by the margin table of spec 4.6: the delay only has to exceed the 2-s publish window, and it does so by orders of magnitude on the fastest evaluator measured. The external review (O-4.1) is still owed. Was: Answered by design, with the dependency conceded. Answer: The VDF is used for one thing: making the hourly program unknowable within the roughly two seconds a miner has to decide whether to publish a block, closing a withhold-or-publish grind the review measured at about 130 to 1 for a 30% miner. The VDF input is a certified checkpoint at least one epoch before the epoch starts, so honest nodes have about 50 minutes of slack to evaluate a 10-minute VDF, and an evaluator 300x faster than reference would still be needed to beat the two-second decision window. Chia has run class-group VDFs in production since 2021, with faster hardware evaluators existing and not breaking it (approximate, from memory). The design doc lists the VDF as a new dependency and ships the evaluator in every node. The grinding simulation with and without the VDF is scheduled before gate 3. @@ -2463,3 +2463,35 @@ The second sub-version 3 commit is 017e70376489251e18564c0abce7e466e606c8b3 (pus F8's 64-seed gate on 017e7037 (the attack-pass lane, box 2, last seed 16:00:20 UTC): 60 of 64 under 1.2x; the four over are the named tail and nothing else (p10 1.5036x, p8 1.3776x, p34 1.2505x, p4 1.2167x; hottest items 355 to 541 reads of 2^31, unattributed, inside the ratio's clean spread); p23, p19, p15, p18 and p56 under the line; the clean spread 0.9915x to 1.144x. Exhaustion on 017e7037: 0 in the attack-pass lane's 20,532 chain-shaped seeds (max attempt 29) plus this lane's 4,099 (max 17); the 10^6 count continues as a strengthening line. Cost line for the node: the chain's epoch draw now pays the 2^20 ratio pass on every candidate that reaches it (the accepted one, and the about 4 percent that fail there), 2.2 s per pass on one box-2 core, so about 2.3 s per epoch draw on that core and, by the attack-pass lane's reading, about 4 to 5 s per epoch per node on slower cores; the earlier rejections cost milliseconds. From the attack-pass lane sub-version 3 at 017e7037 reads green on both gates with the named tail; its close line went to the plan, main and the Counter ASIC lane. This row stays open on the tail (p4, p8, p10, p34) until it is attributed or ruled accepted. Owed (recorded, not run, by the project lead's word): G2 (the CPU verifier on 1,024 hashes per card) on the amended stream; G3 (the Metal fuzz, edge, stats and determinism runs) on the amended stream; the hash-rate ladder re-measure on the M5 Max and the RTX 5090 (the amendment changes the base program's source draws, not the op mix or the load count, so the latency-bound rows of `docs/analysis/latency-shadow-2026-10-06.md` are expected to hold within their spread; unmeasured); AMD (the RX 9070 XT, PC 1); the 2019-class verifier core (O-1.14); F8's phase E (the 64-seed dynamic census) on the amended stream, which is the attack-pass lane's and the test of the per-op table. The row reads FIXED-AND-PASSED only after phase E passes against the amended class. + +## Genesis forward-compatibility entries (7 October 2026, mission item 8, branch `genesis-forward`) + +The three genesis fields of `docs/analysis/mission/mission.md` section 2.8, built on the node fork branch `genesis-forward` (from release-0.3.19-node dc141409) and the repo branch `genesis-forward`; the design and the gates in `docs/design/genesis-forward.md`. Every switch is never on the devnet (its digest c562d70e... does not move); the testnet genesis sets all three (the testnet lane re-pins and re-digests). + +### GF1. A post-quantum signature scheme would need a hard fork, and every vote key is a public BLS12-381 point +"When a quantum computer comes, every BLS vote key is forged and the chain has no way to change the scheme without a fork of the kind you say you never need." + +Status: Fixed (7 October 2026). `sig_scheme` byte in every vote item and key reveal (`finality::SIG_SCHEME_BLS12_381` = 0), `Params::sig_scheme` and `Params::sig_scheme_activation_daa` in the digest once set; any other byte refused by every node (`scheme_refusal`) until a program class the 95 percent signal moves to names it (`igneum::sig_scheme_of_class`, empty today). Gate: the digest test `override_params_carry_the_genesis_forward_fields_and_the_digest_moves_only_when_set` and `consensus_digest_covers_every_consensus_field_and_nothing_else` (30 edits); a scheme-1 vote refused over RPC, in a block, and as a successor's scheme (`a_vote_reveal_or_successor_of_another_signature_scheme_is_refused_until_a_class_names_it`); the fast-time probe on three nodes (`infra/fast-time/key-succession.mjs`, `probe-scheme`). + +Answer: The byte costs nothing now and a fork later. The flip is a class change (spec 03 W1 as amended): the aggregated-vote format ships first (naive ML-DSA-44 votes at 8,192 voters cost 57 GB a day, `future.md` 7.3), the scheme second, both by the 95 percent signal with a floor height. Per tier at migration: a home miner on any card runs the updater and signs one succession item (GF2); nothing hardware-specific, the signature runs on the CPU. + +### GF2. A vote key cannot move: a miner who changes keys re-earns 30 days of weight, and so does the post-quantum migration +"Your weight is bound to a key. Rotate it, lose a month. So nobody rotates, and the one day everyone must rotate, finality pauses for a month." + +Status: Fixed (7 October 2026). W5 key succession implemented (spec 03 W5 as amended): a succession item signed by both keys, carried in blocks after the leaves, folds the old key's window blocks and forfeit term into the successor from the first checkpoint whose past holds the carrier (`successions_at`, `fold_successions`); once per key, a second succession refused, a successor that has itself handed over refused. Behind `finality_succession_activation_daa`. Gate: carried once and refused twice in the unit test on two nodes and in the fast-time harness. + +Answer: The successor inherits the window, not a fresh one, so a key rotation costs no weight and the migration of GF1 is one item per key. The old key signs nothing after; a buyer of a key gets the clean transfer (spec 3.11.5) and the seller's copy is worthless. + +### GF3. A 256 MB on-chip cache makes the lottery hash 2 to 3x cheaper for the card that has it, and the cache size is a constant +"The dataset is built from a 256 MiB cache. A datacentre part with a 256 MB last-level cache keeps the whole cache on die and skips the memory. Consumer cards cannot." + +Status: Fixed as a genesis lever, measurement owed (7 October 2026). The latency ladder carries one cache rung beside N (`LatencyLadder::cache_rung`, 512 MiB, `LadderSignal::Cache` = both ladder bits, the same 90 percent in seven windows, one rung, never back, in the digest with the ladder); inadmissible at genesis until the verifier bound and the 8 GB tier are measured (design doc section 3); visible in `getBlockTemplate`'s `powEpoch` (`latencyLadderCacheStep`, `latencyLadderCacheMib`, `latencyLadderCacheBps`, `latencyLadderCacheAdmissible`) and in the daemon's ladder line. + +Answer: Consumer LLC is 96 to 128 MB today and datacentre 256 MB (`chip-model-v3`, approximate), so the shortcut is a datacentre card's today and a consumer card's in a generation or two. The rung lets the miners double the cache by signal the day the shortcut shows on the hash-rate charts, without a fork; the measurement that admits it is the same verifier bound as every N rung. Per tier: a 512 MiB cache is held by every tier from 8 GB up; the day-cache build doubles (about 0.7 s on the reference core today, approximate); the verifier reads the cache, not the dataset, so the 10 ms bound decides. + +### GF4. The class-group VDF falls to the same quantum computer +"Shor computes the class-group order; your epoch seed is then grindable." + +Status: Conceded, flagged in spec 04 section 4.8 (7 October 2026); not sized. The fallback is a hash-chain delay behind the same version byte that moves the signature scheme; designed when the scheme flip is scheduled. + +Answer: A grindable hourly seed is a liveness nuisance against the lottery, not a safety break: finality rests on the vote keys (GF1), the seed on the VDF. The two flip together by one class change. diff --git a/docs/plans/build-server.md b/docs/plans/build-server.md index 24c5ca04..a7e907d5 100644 --- a/docs/plans/build-server.md +++ b/docs/plans/build-server.md @@ -377,3 +377,28 @@ spill-over. Now (lib.sh `bs_route_spill`, master from this commit): them keeps its number; since this commit a bounded run takes the band its slot owns (slot 0 the last 32 cores, slot 1 the 32 below, slot 2 the 32 below that), so three bounded runs never share a core. A gate still takes its slot ahead of queued suites. - `--box N` still pins. Self-test: tools/ci/route-spill-check.sh (thirteen cases through `BS_ROUTE_STATE_`, no ssh), in the gate. + +## 8. The measure file is retired: per-core leases and the quiet class (7 October 2026, 15:07 UK) + +Main's reading at 15:07 UK: on build-1 a sync-fuzz probe (the capacity lane's, SIGSTOPped since 09:45Z, no owner) held the global +measure flock for five and a half hours; beside it attack-f6's phase2b waited exclusive on the same file behind seven F2 solvers +holding it shared on cores 6-11,54-59, and every new shared taker (every build) queued behind the exclusive waiter: load 120, slots +free, nine waiting. On build-2 the era VDF bench held the file exclusive while pinned to one core and five jobs waited. One global +exclusive lock across unrelated measurements was the wrong design. Now: + +- `infra/build-server/lease.sh`, installed on every box at `/srv/builds/_bin/lease` (provision.sh; by hand on build-1 and build-2 + at 14:2x BST): `lease cores --label "..." [--owner ] -- ` takes a lease on THOSE CORES ONLY (one flock per + core, `_locks/core-`, a `wait-` file with the label while it waits), runs the command under nice 10 and taskset, and + releases. Nothing else is excluded. `lease quiet --label "..." --owner -- ` is the whole-box class: refused (exit + 73) while any slot or core lease is held, capped at 20 minutes, holder line with the owner in `_locks/quiet`. `lease status`, + `lease reap`. +- remote-run.sh: an unbounded run (nice 0, the full set) takes `quiet` shared and waits for it; a bounded run (suites, benches, + everything on box 2) never takes it. Every run keeps off leased cores (its set minus the `core-` flocks, said once). A run's + keeper refreshes its holder file's mtime every 20 s and calls `lease reap`: a holder of a lease, the quiet file or a slot whose + process has been STOPPED for 5 minutes is killed and its file cleared, one line each in `_log/reaped.log`. The keeper closes the + lock descriptors it inherits (an orphaned `sleep 20` held a slot and a worktree lock 20 s past the release). BR_MEASURE=1 is the + quiet class with the same refusals; it needs a named owner (IGNEUM_AGENT). +- The lanes' own `flock -s /srv/builds/_locks/measure -c "nice -n 10 taskset -c ..."` lines no longer hold anything a build + waits for; they become `/srv/builds/_bin/lease cores --label "..." -- `, and `flock -x .../measure` becomes + `lease quiet`. Self-tests: lease.sh --self-test and remote-run.sh --self-test-slots, run on build-1 by tools/ci/box-locks-check.sh + in the gate. diff --git a/docs/plans/counter-asic-3-public-text-2026-10-07.md b/docs/plans/counter-asic-3-public-text-2026-10-07.md index c72a2964..ba75180b 100644 --- a/docs/plans/counter-asic-3-public-text-2026-10-07.md +++ b/docs/plans/counter-asic-3-public-text-2026-10-07.md @@ -1,33 +1,33 @@ -# The chip claim, public text (7 October 2026, 14:3x UK, on the project lead's "this needs updating with all of our updates"; served since 11:03 UK on master 9162c847 with main's two cuts: no mention of the disclosure prize until the publish word, and row 17 in evidence.md's eight-column shape) +# The chip claim, public text (7 October 2026; REWRITTEN LAUNCH-FIRST 18:3x UK on the project lead's "I thought we were making it 2.1 from launch?": the testnet and mainnet objects set program_class_v4_activation_daa to 0, so class v4 is live from genesis and the launch number is 2.1x to 3.9x on day one; the 5x to 9x is the class v3 baseline the work started from, stated only as that; the devnet's own activation height is a devnet fact only. Served since 11:03 UK on master 9162c847 with main's two cuts: no mention of the disclosure prize until the publish word, and row 17 in evidence.md's eight-column shape) Three texts and one ledger row, written by the Counter ASIC lane, which owns the chip model. Every number carries its label: measured (a card or a chain we ran, with the date), modelled (arithmetic on cited parts), claimed (a vendor's figure, never measured by us), designed (a rule in a class, not yet measured). Sources: `docs/analysis/chip-model-v3.md` sections 5 and 6, `docs/analysis/latency-shadow-2026-10-06.md`, `docs/plans/counter-asic-3-status.md`, `docs/analysis/attack-pass/f8-uniform.md` and `f4-weakday.md` (branch attack-pass), `docs/design/class-v5-stored-state.md`, the datacentre and market-cap rows of 7 October (lanes 3 and the fleet), the cryptanalysis plan in `docs/plans/funding.md`. ## 1. The home page's chip line (replaces the hero sentence served since 6 October 16:21Z) -Built for graphics cards. In our public model the strongest chip reaches 5x to 9x per joule against an RTX 5090 today; class v4, now on the vote, brings that to 2.1x to 3.9x, and class v5 makes the dataset the chain's own state, so a chip that stores it or recomputes it is wrong on every item. The model and every measurement are public. +Built for graphics cards. At launch the strongest chip in our public model reaches 2.1x to 3.9x per joule against an RTX 5090, under class v4 from the first block. Class v5 then makes the dataset the chain's own state, so a chip that stores it or recomputes it is wrong on every item. Without class v4 the same chip would reach 5x to 9x. The model and every measurement are public. ## 2. The litepaper's chip section (replaces the paragraph that begins "The chip model: 5x to 9x per joule") -The chip model. We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090's hash at 1.15x the tuned 5090's hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms. +The chip model. We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. Class v4 is live from the first block on the testnet and the mainnet (the ladder's rung 0 at genesis), so the launch number is the class v4 row. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090's hash at 1.15x the tuned 5090's hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms. | The chip and the class | Edge over an RTX 5090 per joule | Label and date | |---|---|---| -| A memory-controller chip that stores the whole dataset (the Ethash class), class v3 | 5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x) | modelled, 6 October 2026; the precedent measured by others, 2020 to 2022 | -| The same chip under class v4 (about 100,000 integer ops per hash in the latency shadow, so the chip carries a GPU-class datapath beside its memory) | 2.1x with a core as costly per op as the GPU's (k = 1); 3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped | modelled on measured card watts, 6 October 2026; the X9 figure claimed, never measured | -| The same chip at the ladder's second rung (about 200,000 ops per hash) | about 2.8x | modelled, 7 October 2026 | +| At launch: a memory-controller chip that stores the whole dataset, under class v4 (about 100,000 integer ops per hash in the latency shadow, so the chip carries a GPU-class datapath beside its memory) | 2.1x with a core as costly per op as the GPU's (k = 1); 3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped | modelled on measured card watts, 6 October 2026; the X9 figure claimed, never measured | +| The same chip at the ladder's second rung (about 200,000 ops per hash), reached by miner signal | about 2.8x | modelled, 7 October 2026 | | Any chip under class v5, where the dataset is the chain's own state | a stateless or stale chip is wrong on every item, so the stored-dataset chip and the recompute chip are removed as categories; the verifier pays 0.2 ms more per warp | designed, 7 October 2026 | | A chip caching the hottest 0.1 percent of items (about 1 MB of SRAM) | bounded at 1.067x at the ceiling, 1.005x on about half the hours and 1.048x on 5 percent | measured census of 1,024 programs, 7 October 2026; the source rule in the next class | | A per-day FPGA that recomputes the dataset with cheap multipliers on a weak day | at most 12 percent more hash rate on 12 days a century, nothing on the other days and nothing for any chip | measured census of 2^24 days, 7 October 2026; the rule in the next class | | When a stored-dataset chip pays for itself | at about USD 100 M of market cap in the first two years, not before | modelled, 7 October 2026 | +| The baseline the work started from: the same chip under class v3, without the shadow (the Ethash class) | 5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x) | modelled, 6 October 2026; the precedent measured by others, 2020 to 2022; never the launch state | -What a miner sees from this. Class v4 costs a 5090 about 80 W more for 0.2 percent of rate, an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (all measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at the testnet genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). The next test of the model is not ours: the cryptanalysis plan buys three external lots against the mixer, the chained cache and the acceptance rule. +What a miner sees from this. Class v4 costs a 5090 about 80 W more for 0.2 percent of rate, an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (all measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). On the devnet, which started on class v3, class v4 arrives by miner signal at a published height (a devnet fact, not a launch one). The next test of the model is not ours: the cryptanalysis plan buys three external lots against the mixer, the chained cache and the acceptance rule. ## 3. The miner page's line -Your card against the strongest chip we can price: an RTX 5090 at 136 MH/s on 350 W (measured 6 October 2026), the chip 5x to 9x per joule in the public model today, 2.1x to 3.9x under class v4 (modelled on measured watts), and under class v5 wrong on every item because the dataset is the chain's own state (designed); the model and the measurements are public. +Your card against the strongest chip we can price: an RTX 5090 at 136 MH/s on 350 W (measured 6 October 2026); at launch the chip reaches 2.1x to 3.9x per joule under class v4 (modelled on measured watts), and under class v5 it is wrong on every item because the dataset is the chain's own state (designed). Without class v4 it would be 5x to 9x. The model and the measurements are public. ## 4. The ledger row (docs/evidence.md row 17, in the table's eight columns as served) | # | Claim | Where it is made | Status | Version or commit | Reproducible test | Result, date, machine | Independent verification | |---|---|---|---|---|---|---|---| -| 17 | The chip resistance claim: the strongest chip in the public model reaches 5x to 9x per joule against an RTX 5090 today; class v4 brings it to 2.1x (k = 1) to 3.9x (k about 0.33) and its second rung to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 12 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/funding.md` (the three lots) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 5.1x to 9.2x; 2.1x, 3.9x, 2.8x; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 | none yet; the three cryptanalysis lots are the next test | +| 17 | The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (k = 1) to 3.9x (k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 12 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state) | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/funding.md` (the three lots) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.9x, 2.8x at launch; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 | none yet; the three cryptanalysis lots are the next test | diff --git a/docs/plans/counter-asic-3-status.md b/docs/plans/counter-asic-3-status.md index 6158ed19..d5831305 100644 --- a/docs/plans/counter-asic-3-status.md +++ b/docs/plans/counter-asic-3-status.md @@ -355,7 +355,75 @@ the project lead gave the go in advance for tonight: the shipper runs publish 1 | p25 | 1.28x | | | the 53 passing | 0.9915x to 1.16x | no predicted source | -Three residual classes, all a constant delivered through a writer the rule admits: (1) saturation or zero preserved through rotl, rotr, load or mad (p31, p6, p23, p26, p34); (2) zero from mulhi (p45) and zero preserved by rotates; (3) the iteration boundary, the rule's writer state starting fresh at instruction 0 so an or at 63 feeds a load at 1 (p11). Sub-version 2's dataflow-freshness rule closes all three IF the freshness is computed as a fixpoint over the loop (the state after instruction 63 feeds instruction 0 of the next iteration), with the dynamic (c') count on load sources as the backstop; sent to the hash lane. "No lossy-sourced load by construction" is not true of sub-version 1 and stays held. Chip consequence on sub-version 1 by the 1.4 arithmetic: the hot set is still one item at one site, under 1 percent of rate for a chip caching it, so the ship is safe on the rate side; the auditor's flag is what sub-version 2 removes. F9's hot-set harness cannot be the second re-gate (its metric counts the era's designed half and quarter windows as hot; its chain-path 8.3 percent on sub-version 1 is the window model, verified on its worst seed); F8's census is the single re-gate instrument, re-run on sub-version 2 within the hour of its commit. THE INTEROP FACT stands from the void run: the 5899f603 hub accepted 235 object-byte-5 blocks from the 8097d600 node with 0 rejected, one digest on all five nodes on the live sixteen-field file. The gates: the digest test and the kaspa-pow vector test (the amended devnet epoch-0 id 1a4230699a6b9c60 must equal, c120d7963abdcd96 must differ, the v3 control unchanged) on the box; the mixed-version Devnet 2 gate (the amended 0.3.20 node beside a 5899f603 node for ten minutes on the live file without the v4 fields) after the Mac build; the fresh-join canary the 0.3.20 cut's | +Three residual classes, all a constant delivered through a writer the rule admits: (1) saturation or zero preserved through rotl, rotr, load or mad (p31, p6, p23, p26, p34); (2) zero from mulhi (p45) and zero preserved by rotates; (3) the iteration boundary, the rule's writer state starting fresh at instruction 0 so an or at 63 feeds a load at 1 (p11). Sub-version 2's dataflow-freshness rule closes all three IF the freshness is computed as a fixpoint over the loop (the state after instruction 63 feeds instruction 0 of the next iteration), with the dynamic (c') count on load sources as the backstop; sent to the hash lane. "No lossy-sourced load by construction" is not true of sub-version 1 and stays held. Chip consequence on sub-version 1 by the 1.4 arithmetic: the hot set is still one item at one site, under 1 percent of rate for a chip caching it, so the ship is safe on the rate side; the auditor's flag is what sub-version 2 removes. F9's hot-set harness cannot be the second re-gate (its metric counts the era's designed half and quarter windows as hot; its chain-path 8.3 percent on sub-version 1 is the window model, verified on its worst seed); F8's census is the single re-gate instrument, re-run on sub-version 2 within the hour of its commit. SUB-VERSION 2 COMMITTED: ca3-v4-amend 07a809a7, 13:01Z (origin and build), the string with the attack-pass lane. The loop fixpoint is in as rule (a') in accept.rs (the freshness run to its fixpoint over base then shadow block; every load's source fresh in the steady state, else the candidate rejected and the next attempt drawn; it closes the iteration boundary the draw's fallback cannot see); (c') counts zero and all-ones alike (v == 0 or v == MAX) per load site over the 16,384 evaluations, rejected at 164 or more; both and the draw rule keyed on the class v4 shape on every draw path, so v2 and v3 do not move; mulhi never fresh. Epoch-0 id a788661687db4bb3 (the devnet seed's attempt 0 rejected by the new rules, attempt 1 accepted); must-differ c120d7963abdcd96 and 1a4230699a6b9c60 pinned; object byte 7 in recheck.rs. The seven fingerprints (Metal = Apple OpenCL on the M5 Max, 13:01:17 to 13:01:49Z, the control 90f794dd556f7a3b unchanged): + +| Pack | Fingerprint | +|---|---| +| v4-devnet-epoch0 | e370fb2080b7dbb1 | +| era-0 | b7237555d31fc3cf | +| era-1 | b6b167fa15dfe2c9 | +| era-2 | 28bdf65eff33f2c4 | +| era-3 | e26d38c46f3f1b16 | +| era-4 | dd8fdf6ff4f59eed | +| era-5 | 8bf40f5cb858d835 | + +Packs zip (eight packs, packs-ca3-v4-sub2) sha256 69c36772cd79e44e2ddd589466d9c64a94a13c9e970e9f27bd76feabb9b4581b. The suite re-runs through master's build-remote on box 2 (the worktree's own script predates --box; the first run died on the flag), line to follow; G1 on PC 2 under --cards-off after it. The sub-version-2 pairing waits on the node lane's re-pin to a788661687db4bb3 and byte 7. For the record, sub-version 1's pairing: igneum-pow 8c728ca3 against b7cc37e7 (8097d600's assert_ne in) 17 passed, 0 failed, rc 0, 12:21Z. 0.3.20's CUT SET AS IT STANDS (the shipper, 14:1x UK): pin c4459193, igneum-pow 8c728ca3 at object byte 5 (sub-version 1), the floor-moved file publishing with it (the project lead's word; the floor from the live DAA at the publish plus 604,800, the digest read on c4459193), publish about 15:15Z (16:15 BST) on CASES END, the sweep from then with PC 1 first. 0.3.21's clock tonight: the node lane stages release-0.3.21-node at the shipper's sweep-end word (about 15:45Z, 16:45 BST) with the sub-version-2 re-pin (07a809a7, byte 7, id a788661687db4bb3) as its own commit, held pending the F8 census on 07a809a7; the census's clock about 14:00Z (15:00 BST) by the attack-pass lane's within-the-hour line from 13:01Z; the pass line every one of the 64 seeds under 1.2x of the window model on the chain path. If the census fails or slips past 19:00Z (20:00 BST), main's standing ruling applies (nothing on sub-version 2 is proposed until the census is green): 0.3.21's node ships byte 5 again with the re-pin dropped and the rest of its line kept. CI NOTE (13:1x UTC): master's ci runs since 12dc5c97 (nineteen of mine) sit queued behind one self-hosted runner (igneum-build-1, busy; 31 queued across branches, one in progress); the last completed master runs (439a233f to 5f990a09) are success; no red exists, the conclusions are unread until the queue drains. MAIN'S WORD (14:2x UK): the floor move is the project lead's word already and ships with 0.3.20 at the cut; the CI lever is a second self-hosted runner on build-2 plus ubuntu-latest for docs-only pushes, ordered to the CI lane; the rule reads "own a red when the conclusion lands", never holding pushes; the census verdict about 14:00Z (15:00 UK) decides 0.3.21's byte. SUB-VERSION 2's STATIC CENSUS (the hash lane, tools/ca3-v4-uniform on box 2, 13:12Z, 1,024 chain-shaped seeds plus F8's p1 to p3): 0 lossy-sourced load sites of 16,432 (14,329 injecting, 2,103 bijective); 0 programs with an or-, mul- or mulhi-sourced load; the no-era draw path gives the devnet epoch-0 seed the pack's own id a788661687db4bb3, so every draw path reads one stream. Cost of (a') and (c'): 1.99 attempts per seed on average against 0.05 before (p2's seed five), about 2 ms of generation per rejected attempt on one core; nothing a miner or node notices. Ledger entry 715f14be. Master 36e08c80 merged into ca3-v4-amend as f5244ad7 (igneum-pow untouched, re-export 0 differing files), pushed with the gate GREEN, its CI runs queued; the box-2 suite runs through the merged tools (the first attempt died on test initialisers missing the (c') field, fixed in the same push; library and packs unaffected). G1 BLOCKED: PC 2 has not picked up fetch-ca3-v4-sub2-20261007 and run-ca3-v4-sub2-g1-pc2-20261007 (published 13:04:02Z, signature OK); the intake shows nothing from 1ccfe586 since job-update-now-0319 at 10:34:21Z; the PC 2 lock releases when the job closes or in 30 minutes; the run is republished when the app reports. PC 2 READS SILENT on the console (the shipper, 14:4x UK): last seen 2 h ago, app 0.3.19 on node 5899f603, its last line the 0.3.19 update-now at 10:34:21Z; the app went down or stopped polling on that update (the UI lane's update-now; PC 1 took the same update and reports). The build-server lane's PC 2 kept-datadir job (run-20261007-125433, published 12:54Z) is unpicked for the same reason, and it is the Windows kept-datadir gate for 0.3.20's PC 1 step. The sweep cannot bring PC 2 back (the app's poller applies updates; a silent app does not poll); a Windows restart of the app is a hand action, the project lead's or by main's word; the shipper has asked main. The hash lane's G1 and the Windows kept-datadir line wait on that answer; the PC 2 lock stays. SUB-VERSION 2's SUITE LINE (the hash lane): ca3-v4-amend 526fa757 (the code; the ledger tip f0fbd9da), box 2 through the merged tools, route line "13:15:07 build-remote: box 2 (build@142.132.249.238) for class suite, priority normal", rc 0, 66 s: 61 lib + 7 derive + 4 mixer + 19 packs + 2 recheck + 7 scratch = 100 passed, 0 failed; the pinned v2 and v3 packs byte-identical; the three v4 ids as pinned (a788661687db4bb3 equal; c120d7963abdcd96 and 1a4230699a6b9c60 differ). The two commits between 07a809a7 and 526fa757 touch tests only (the (c') field in the accept.rs initialisers; the two generator unit tests follow the amended facts); the library, the packs, the id and the seven fingerprints are unchanged from 07a809a7, so the attack-pass re-gate on 07a809a7 stands for 526fa757. CI: the merge commit's run cancelled by the next push (superseded, not red); 526fa757's run queued (37626985216), its conclusion owned by the hash lane. The 0.3.21 re-pin commit is therefore 526fa757 (or the branch tip at the node lane's archive, code-identical). MAIN'S WORD ON PC 2 (15:0x UK): the hand restart of PC 2's app is asked of the project lead. If PC 2 has not polled by 15:00Z (16:00 UK), "go PC 1": the sub-version 2 G1 on PC 1 under the runner's --cards-off after the 0.3.20 sweep step lands there, one job, read back, nothing else on PC 1. The PC 1 job publishes only after the shipper's line "PC 1 on 0.3.20" (app 0.3.20, node 2.1.0-c4459193, the published file's digest, synced, the sweep step closed with its lock line), about 15:30 to 15:40Z by the clock, and only if PC 2 is still silent; The PC 1 variant is on ca3-v4-amend at a2714d43 (tools/ca3-v4-amend/pc1-v4-sub2-g1.ps1; CI checks pass; no api/quit, pause, resume or cards call in the script): the RTX 5090 on PC 1 (ae432dc7) by its index-free key nvidia:NVIDIA GeForce RTX 5090 on the runner's --cards-off, restored by the runner after; the AMD card and the Intel Arc not named and mining on; the card confirmed quiet by the process list (90 s wait) and nvidia-smi's compute-apps; the installed worker's --bench on the eight packs (the v3 control and the seven sub-version 2 packs) for the 2^24 fingerprint and self-test, rates a reference only; the kit the same zip (69c36772...), as fetch-ca3-v4-sub2-pc1-20261007 immediately before run-ca3-v4-sub2-g1-pc1-20261007 (--timeout-minutes 20, --expires-hours 12); published only on the go-PC-1 line. AP-F8-2 ON SUB-VERSION 2 (the attack-pass lane, 15:1x UK, before anything is proposed): a chain-shaped epoch seed can exhaust all 32 draw attempts under rule (a'), and the generator treats exhaustion as a consensus fault (panic): seed igneum-f9/331672, "32 consecutive candidates rejected, last: (a') load at 16 reads r6, not fresh by dataflow in the loop's steady state". One such seed in the first 331,672 chain-shaped seeds (300,000 drew clean), a rate of order 10^-6 to 10^-5 per epoch seed; the 10^6-seed measurement with the attempts distribution runs on box 2. Meaning: an exhausted epoch seed is an epoch no node can draw a program for, a liveness halt, the era and epoch seeds being VDF outputs nobody can steer; at one epoch an hour, one halt per 11 to 40 years at the bracketed rate, which the firms would compute from the rule as written and file. Sub-version 1 had 0 exhausted in 10^6 chain-shaped seeds. The fix (to the hash lane): the draw enforces the freshness fixpoint itself so (a') never fires (no exhaustion by construction), or MAX_ATTEMPTS sized to the measured rate with the exhaustion probability stated in the spec. The 64-seed hot-set gate on sub-version 2 is separate: 13 of 64 seeds read, none over 1.2x so far. Sub-version 2 is NOT GREEN until both are settled. MAIN'S RULING ON AP-F8-2 (15:2x UK): the draw must be total and no consensus path may panic; preferred fix a deterministic repair instead of rejection (the draw rewrites the offending load's source to the nearest fresh register, or inserts a fresh mix, so every seed yields a program on the first attempt and (a') becomes a check that can never fire); if the repair changes the stream's statistics, the fallback is a stated attempt bound with a deterministic last-resort draw after it, never a panic, the probability in the spec and the ledger; either way a test walking seed igneum-f9/331672 and the exhausting class, the 10^6-seed exhaustion count at zero, and the 64-seed hot-set gate re-run on the fixed commit; the hash lane builds it now on the coordinator's direction; 0.3.21 ships byte 5 if not green by 19:00Z (20:00 UK). The 07a809a7 kit is not published to any PC. + +AP-F8-2 FIXED (the hash lane, ca3-v4-amend 8bdcbdd8, 13:31:10Z, origin and build, gate GREEN): sub-version number unchanged at 2 because the stream is unchanged for every non-exhausting seed (re-export diff 0 on v4-devnet-epoch0, v4-era-0 and v4-era-5; the id a788661687db4bb3 and the seven fingerprints stand; the packs zip sha256 69c36772... holds), so the attack-pass census at 13 of 64 continues on it. The route: the deterministic repair would have rewritten every seed whose attempt 0 fails (a'), about two thirds of seeds, a new stream and a restarted census against the 19:00Z line, so the second route main allowed was taken. The bound: MAX_ATTEMPTS_V4 = 256 for the class v4 shape (v2 and v3 keep 32, keyed on the shape); at the measured rejection rate of about two thirds per attempt, 32 attempts exhaust at about 2e-6 per epoch seed (one undrawable epoch every few decades at one an hour), 256 at under 1e-45, the worst-case draw about half a second on one core. After the cap the draw is total: the seed takes the last-resort program, deterministic and accepted as drawn, the candidate at attempt 256 with every or, mul and mulhi of the base program and the shadow block rewritten to xor, so every register stays fresh from the init words on and (a') holds by construction; no consensus path panics for the v4 shape. The test class_v4_draw_is_total_with_the_last_resort (the last resort on real (a')-rejected candidates, every load fresh after it, no lossy op left, the chain path over 64 seeds without a panic, the cap per class asserted) green on the Mac, the box-2 suite running; the hash lane's 4,096-seed census with the attempt histogram on box 2; the attack-pass lane's 10^6 count is the control; the string with the attack-pass lane with seed igneum-f9/331672 named. CI: 526fa757 success; 8bdcbdd8 queued. The spec and ledger text for the bound and the probability in the ledger entry. The PC 1 variant and fetch job carry 8bdcbdd8's packs (byte-identical to 07a809a7's); the PC 2 kit published at 13:04Z is the same packs. Per tier: a miner never sees the draw (the node draws once an hour, half a second at worst); a chip maker gains nothing from the last resort (a 1e-45 event); the auditor reads the bound and its probability in the spec. SUITE LINE AT 8bdcbdd8: box 2, route line "13:31:21 build-remote: box 2 (build@142.132.249.238) for class suite, priority normal", rc 0, 80 s, 62 lib + 7 derive + 4 mixer + 19 packs + 2 recheck + 7 scratch = 101 passed, 0 failed, the total-draw test included; ledger entry 32e96c9a; CI on 526fa757 success, the newest push's run queued and owned by the hash lane. + +THE 12 GB SETTLED-CLAIM LINE ON c4459193 (the fleet lane, 13:27Z): the floor reads right and the card proves, THE NODE REFUSES. p12-vast on c4459193 (sha 45be9b02, string read back) synced 13:22:47Z on the kept copy; first claim 13:23:01Z "segment 164198..164205 (8 shards, fresh) margin=414 tip=287564 settledNumber=0x28185 settledDaa=0x46317 settledBy=finality candidates=5"; proof complete 13:25:19Z on the 3060 (8 of 8 shards, 135.9 s, peak 8,487 MiB); submission refused "statement differs from the node's at hex offset 472 (lengths 616 vs 616); ours ...2b1a81cb413236cf... node ...0000". The node's start line on this binary reads "proving v1: ... shard program id unknown, aggregator id unknown" where 5899f603 on the same override file reads the ids; the statement is built with zeros and every proof fails its check. This blocks the paid line on any card and, after the sweep, every standing prover; with the node lane (the fix) and the shipper (the cut) since 13:27Z; the pod and proof files held for the node lane's read. The cut set is therefore NOT complete on c4459193. THE CAUSE (the node lane, 13:4xZ): no commit on the line lost the ids and the binary is not the difference; on every build including 5899f603 the statement's ids come from the override object's two fields (absent on the live sixteen-field file), else IGNEUM_PROOF_PROGRAM_IDS, else the verifier host's --mode id when IGNEUM_PROOF_VERIFIER is set. hub-1 runs with IGNEUM_PROOF_VERIFIER=/opt/igneum-floor/bin/igneum-prove-host in its process environment, so the host hands it the ids; the pod's c4459193 node was started bare for the kept-datadir read, so program_ids answered None and the statement carried zeros; a bare 5899f603 reads "unknown" too. The start environment, not the binary. What the child commit fixes anyway: the binary embeds the verifying keys it verifies carried proofs with, so it knows the ids it expects; the child resolves them in that order and last from the embedded keys, with a test whose known-failed shape is the bare node's None and the zero-id statement; the diff two files (resolve_program_ids in igneum/exec/src/proving.rs and its call in kaspad/src/daemon.rs; nothing in acceptance, the version check, relay or peer handling); its exec suite running, the string and sha256 about 13:52Z. Gate carry: the digest and mixed-version gates are outside the diff's territory and carry from c4459193, but rule 4a runs every gate on every candidate from its build, so both run again on the child's binary and the fleet's set with them; the re-run that bears on the diff is the 12 GB line itself, the pod's already-proved claim submitted against a node that names the ids. Per tier: a solo miner on a bare node never proves, so feels nothing; a standing prover beside hub-1's environment was never affected; a prover on a bare node could not be paid on any build until the child. THE CONTROL (the fleet lane, p12-vast): the same c4459193 (sha256 45be9b02d1b002f5, string read back) on the same kept copy, killed and restarted 13:30:28Z with IGNEUM_PROOF_VERIFIER=/opt/igneum-floor/bin-0317/igneum-prove-host (sha 71bc2438) and HOME on the floor: the start line reads "proving v1: ... shard program id 0x2b1a81cb413236cf..., aggregator id 0x474678f3...", no panic, synced 13:31:49Z (155,725 blocks, 4 peers); the bare start of the same binary on the same copy at 12:36:11Z read "unknown". The ids are the start environment on the pinned build, not the binary. The submission verdict against the ids-naming node: the prover restarted 13:31:56Z and claims fresh (the 13:23Z proof held as evidence, past its margin), the first chain proof about 2.5 minutes on the 3060, the verdict line about 13:36Z; the bare-child line runs the minute the child's string and sha land (about 13:52Z). THE CONTROL'S VERDICT (13:33:56Z): against c4459193 restarted with the verifier set, the 3060's first proof "RESULT seg 164286 chain ... 8 shard records, chain_len 8, proof 1272909 bytes, shards 44.9 s, aggregation 39.7 s, wall 110.6 s, peak 8423 MiB", "shards accepted 8 of 8", no "FAILED: statement": the statement check passes, so the zero-id refusal at 13:25Z was the bare start's environment and nothing in the binary, the pin included. The submission then read "segment_refused ... segment already paid; end to end 113.1 s": the claim race (a 24 GB box proved the same fresh segment inside the 3060's 113 s, the shape of p2-4070-1 this morning); the settled floor does not reserve a claim per key, so a 12 GB prover on the open devnet wins only when no faster box picks its segment; the prover runs on (claim 164342..164349, settledNumber 0x28208 by finality, margin 470) and the paid line goes out the minute a race is won, minutes to tens of minutes of races, not the floor. Per tier: a 12 GB card proves and verifies on the pin; whether it is paid on the open devnet is the race against bigger cards, which is the settled floor's design today and a question for the claim rule, not this cut. THE PROVING-IDS CHILD: 55768f88 on release-0.3.20-node (c4459193's child; resolve_program_ids reads the override's fields, then the env or the host, then the embedded verifying keys; one call in the daemon), pairing igneum-pow 8c728ca3 at byte 5; the exec suite 32 passed at 13:29Z with a_bare_node_resolves_its_program_ids_from_the_embedded_keys (known failed first: the bare node's None and the zero-id statement), kaspad check green 13:33Z; igneumd and igneum-miner built on build-1 at 13:35Z, sha256 279b1b690e854fc9, the string read back; the node lane's digest and mixed-version gates on it from 13:37Z (lines about 13:52Z); the fleet has the path, sha and string for its full set from the same minute; ledger N14 on ca3-v4-node. MAIN'S WORD THROUGH THE SHIPPER (15:5x UK): THE PIN IS c4459193 (the control showed the environment names the ids on it; the ids commit 55768f88 is 0.3.21's first node commit, with the ids gate on every candidate from then); the publish about 14:55Z (15:55 BST) on CASES END. PC 1 is offline for the project lead's cable work, out of the sweep's waves; its app updates on its poller when it returns; the "PC 1 on 0.3.20" line comes after the cable work, not at the publish. PC 2 still silent. The sub-version 2 G1 waits for whichever PC returns first; nothing on either before the shipper's line. 0.3.21's node line stages tonight on 55768f88 with the re-pin held for the census. MAIN'S RULING ON 0.3.21's BYTE (16:0x UK): neither PC is needed for the CUDA half; G1 for 8bdcbdd8 runs on a fleet 5090 now (p1-5090 or a one-shot 5090 pod through the fleet lane; the Linux CUDA worker's 2^24 fingerprints and self-test against the Mac's seven; no --cards-off on a pod; ordered to the fleet lane with the kit's sha256 and the pass line). If that G1, the attack-pass lane's two gates on 8bdcbdd8 and the node lane's re-pin and pairing are all green by 19:00Z (20:00 UK), byte 7 ships in 0.3.21 with the Windows G1 owed and run on the first PC that returns (a Windows-only CUDA mismatch would be a 0.3.22 re-pin; nothing flips before the moved floor); if any is not green by then, byte 5 ships and the re-pin stages for 0.3.22. THE FLEET G1 PACKAGE (the hash lane to the fleet lane, 13:4xZ): the kit packs-ca3-v4-sub2-20261007.zip on the dl host (sha256 69c36772...), the eight packs; the worker proto-cuda/nvrtc/worker.cpp built for Linux by infra/cross/build-workers-linux.sh (dlopens libcuda and libnvrtc, compiles each pack's own text; any 0.3.20-tree build is the right binary, its string from --help); the bench `igneum-worker-cuda --bench --pack --batches 5 --batch-log2 24 --block-warps 1`, the pass per pack self-test PASS plus the fingerprint equal; the eight expected fingerprints. THE PC 2 RUN JOB WITHDRAWN: run-ca3-v4-sub2-g1-pc2-20261007 had been live in the signed file since 13:04Z and would have fired the moment PC 2's app polled, before any sweep step; removed and deployed 13:39:54Z, the file verified; the fetch kit stays; the PC 1 variant never published; the PC 2 lock released 13:39:22Z. PC 2 BACK (the shipper, 13:4xZ): polling since 13:38:32Z, app 0.3.19, non-elevated, node synced; the silence from 10:46Z was the whole PC losing power (Kernel-Power 41, no bugcheck), not the update; the build-server lane's kept-datadir job ran on it at 13:38:32Z and passed; PC 2 takes 0.3.20 on its poller in wave 1 at the publish. The Windows G1 on PC 2 ordered now under the PC 2 lock with --cards-off on the 5090, the 0.3.19 worker (nvrtc compiles each pack's text), to close well before the 14:55Z publish (a job under an app relaunch is the shape that killed the 9070 XT on 6 October); if it cannot start by 14:20Z it waits for the shipper's line that PC 2 reads 0.3.20. The fleet 5090 G1 runs regardless. THE LINUX CUDA G1 FOR SUB-VERSION 2: PASS (the fleet lane, p1-5090, the fleet's standing RTX 5090, no rent, 13:43:22Z to 13:44:07Z; kit sha256 69c36772... asserted; the box's igneum-worker-cuda 1.0 of 4 October 2026, sha256 97e036e23f4ace66; --batches 5 --batch-log2 24 --block-warps 1). + +| Pack | Fingerprint on the 5090 | Equal to the Mac | +|---|---|---| +| mx8-devnet-epoch0 (the v3 control) | 90f794dd556f7a3b | yes | +| v4-devnet-epoch0 | e370fb2080b7dbb1 | yes | +| v4-era-0 | b7237555d31fc3cf | yes | +| v4-era-1 | b6b167fa15dfe2c9 | yes | +| v4-era-2 | 28bdf65eff33f2c4 | yes | +| v4-era-3 | e26d38c46f3f1b16 | yes | +| v4-era-4 | dd8fdf6ff4f59eed | yes | +| v4-era-5 | 8bf40f5cb858d835 | yes | + +Self-test PASS on each (FNV-1a 448274a57f508cbc); rates 120 to 142 MH/s with the box's miner loop sharing the card, a reference only; p1-5090's node untouched, its supervisor restarted after. The CUDA half of G1 is green. THE WINDOWS G1 ON PC 2: GREEN (job run-ca3-v4-sub2-g1-pc2-20261007b, published 13:46:33Z under the PC 2 lock taken 13:45:03Z, the runner's --cards-off on the 5090, 15-minute timeout, nothing of the proving lane's running; start 13:46:36Z, end 13:46:50Z, exit 0; lock released 13:47:18Z; app 0.3.19, the installed worker sha256 14b6637e..., the card off before the script and restored on exit, igneum-worker-cuda 0 before and after, the prover untouched). + +| Pack | Fingerprint on PC 2's 5090 | MH/s (card alone, 5 batches) | Equal to the Mac and the fleet 5090 | +|---|---|---|---| +| mx8-devnet-epoch0 (the v3 control) | 90f794dd556f7a3b | 118.1 | yes | +| v4-devnet-epoch0 | e370fb2080b7dbb1 | 119.3 | yes | +| v4-era-0 | b7237555d31fc3cf | 115.8 | yes | +| v4-era-1 | b6b167fa15dfe2c9 | 116.7 | yes | +| v4-era-2 | 28bdf65eff33f2c4 | 119.3 | yes | +| v4-era-3 | e26d38c46f3f1b16 | 129.5 | yes | +| v4-era-4 | dd8fdf6ff4f59eed | 115.2 | yes | +| v4-era-5 | 8bf40f5cb858d835 | 117.1 | yes | + +Self-test PASS on every pack (cache FNV 448274a57f508cbc); both rows in the ledger entry 43c5bf5b. G1 FOR SUB-VERSION 2 IS COMPLETE on three platforms (Metal, Linux CUDA, Windows CUDA), nothing owed. Per tier: the 5090 rate on sub-version 2 is the same band as sub-version 1 (115 to 130 MH/s), so a miner's rate does not move with the class amendment. The lines left for byte 7 by 19:00Z: the attack-pass lane's two gates and 10^6 count on 8bdcbdd8, the node lane's re-pin and the pairing. THE 64-SEED GATE ON SUB-VERSION 2 IS HEADING TO FAIL (the attack-pass lane, 13:55Z; its earlier "none over 1.2x at 13 of 64" was not read from the log and is withdrawn): 39 of 64 seeds read, 8 over 1.2x of the window model, worst p23 at 4.82x; 44 minutes for 39 seeds, the finish about 14:25Z; the eight seeds' hottest items and predicted sources being read (a residual constant through a writer the freshness rule still admits, or the window model's tail). The 10^6 exhaustion count at 8bdcbdd8: 630,000 drawn, finish about 14:05Z; the 07a809a7 control 880,000 drawn, finish about 13:59Z; the exhaustion and past-31 counts with the ends. The hot-set gate is F8's 64-seed census alone (F9's table serves the attempt histogram and the exhaustion count only). Sub-version 2 is NOT GREEN. THE EIGHT SEEDS (the attack-pass lane, 14:0xZ): three are the window model's own tail at 2^24 nonces with no predicted source (p4 1.22x, p8 1.38x, p10 1.50x); five are constants the freshness rule cannot see because it tracks lineage, not value: p23 4.82x (zero from xor of a register with itself at instruction 0, item 0x000000 at 41,727 reads), p34 1.25x (sub of a register with itself), p15 2.57x (zero through rotl at 0), p18 2.50x and p19 3.32x (a load whose address is constant delivers one word to the next load; p19 byte for byte the sub-version 1 program, untouched by the rule). (c') cannot catch them: its 164-of-16,384 per-site bound (1 percent) is about fifty times coarser than the gate (p23's item is 0.002 percent of all reads and still 4.8x at the top 0.1 percent). Chip side unchanged: one item at one site, nothing to a chip; it is the auditor's uniformity test that fails. THE EXHAUSTION HALF (AP-F8-2) at 8bdcbdd8: 0 exhausted and 0 panics in 650,000 chain-shaped seeds (the 10^6 finishes about 14:05Z), max attempt 35, nobody at the last resort, past attempt 31 about 3.2e-6 (5 in 1.55 million draws, inside the (2/3)^32 estimate), per-attempt rejection 0.67, mean 2 attempts; seed 331672 accepts at attempt 32; the 07a809a7 control's clean evidence one exhaustion in 331,672 (its later chunks contaminated by a rebuild on the same path, not used); FIXED-AND-PASSED at the 10^6 end if the count stays 0. THE GATE QUESTION (the hash lane to the attack-pass lane): three of the eight are the null's own tail at 2^24 nonces, so a 1.2x-on-every-seed threshold sits below the null's spread and no rule can pass it on 64 seeds; the threshold must be set from the null's measured 64-seed quantile or the nonce count raised; the attack-pass lane asked to state that quantile. SUB-VERSION 3 (the fix shape, the hash lane; new ids, packs, fingerprints, the G1s and the census again): (1) the draw forbids a self-operand on xor, sub and mad (dst == src) in the base program and the shadow block; (2) (c') becomes a per-site bound on the MOST REPEATED source value, any value, over the 16,384 evaluations, set from the gate's sensitivity (a uniform source repeats a value two or three times by chance; a bound of 8 is 0.05 percent of a site's reads, 0.003 percent of all reads, 1.02x at the top 0.1 percent), catching the load-after-load constant, the rotated zero and anything a static rule misses; (a') stays for the or, mul and mulhi classes; (3) the attempt cap and the last resort stay, the last resort's rewrite gaining the self-operand guard (a lossy op with src equal to dst becomes add with the immediate). Clock (UTC): build, re-export, Mac fingerprints and the census by about 14:50; the fleet and PC G1s by about 15:20; the attack-pass 64-seed re-gate about 1.5 hours after the string, green by about 16:45 if the threshold question is settled; inside 19:00Z with no slack for a second miss. CORRECTION (the hash lane, from igneum-pow show on p23, p15 and p18 at 8bdcbdd8): the draw already forbids src == dst on every ALU op, so the self-operand ban (1) is void; p23's instruction 0 is xor r2 ^= r1 and site 1 reads r2, so the zero means r2 equals r1 at the start of most iterations, which only the shadow block arranges (a pair of ORs between two registers makes them equal; lossy ops are free in the shadow because only load sources are ruled); p15's rotated zero and p18's load-to-load constant are the same class, a value equality or a constant made upstream that lineage cannot see. The only fix that closes the class is the dynamic bound (2), whose reach the acceptance sample sets: a uniform source repeats a value three times with probability about 4e-8; p23's zero at 3e-4 of its site's reads shows up about five times in 16,384, so "no value three times at a site" catches p23 with about 88 percent probability and misses rarer constants; catching a constant at 1e-4 of a site's reads reliably needs 256 units instead of 64 (four times the draw cost per attempt, about 8 ms), a bigger consensus change. THE COORDINATOR'S PLAN (15:1x UK, to main): 0.3.21 stages on byte 5 (sub-version 1, what 0.3.20 carries); byte 7 goes in only if a sub-version 3 reads green on both gates by 19:00Z; otherwise sub-version 3 is 0.3.22's, built against a gate defined in numbers. The attack-pass lane asked for the gate's three numbers by 14:30Z (the ratio's formula; the single-item read count at 2^24 that still passes 1.2x; the null's 64-seed tail and a threshold defendable to an auditor, or a higher nonce count); the hash lane prepares sub-version 3 uncommitted (the bound and the sample size as parameters, the test with p23, p15 and p18 as the known-failed shapes, the draw-cost line per sample size) and commits on the coordinator's one line once the numbers land; if they do not land by 14:30Z or the census would pass 18:00Z, sub-version 3 is 0.3.22's. THE GATE IN NUMBERS (the attack-pass lane, 14:2xZ, from tools/attack/f8-uniform/src/main.rs lines 289 to 290 and 1240 to 1252). (1) The ratio: the items are the 2^22 dataset items; a census counts reads per item over 2^24 nonces x 128 loads = 2^31 reads; S_f is the share of all reads on the top f of items by measured count (f = 0.1 percent = 4,194 items); W_f the same statistic on a windowed control (a simulated read map from the program's own 16 window draws under the era map, Poisson, no program structure); ratio_w = S_f / W_f, the gate ratio_w at f = 0.1 percent under 1.2; the flat ratio against a uniform map reported beside it; X_f = S_f minus W_f the excess share. (2) The reach: on a typical seed W_0.1 is 0.14 to 0.16 percent of all reads, so 1.2x is an excess of about 0.03 percent, 640,000 reads of 2^31; a single item trips the gate alone only at about 640,000 reads (0.48 percent of its site's 2^27, 78 repeats per 16,384 evaluations), which a per-site most-repeated-value bound sees; the five constants are the tops of low-entropy BANDS: a site whose index has k bits of entropy over its window spreads 2^27 reads over 2^k items, ratio about 45x at k = 12, 6.7x at 15, 2.4x at 17, about 1.2x at 18 (512 reads per item, the uniform level); so the reach is a per-site index entropy of about 18.5 bits of the window's 20 to 22, and the matching dynamic statistic is the count of DISTINCT source values per site, not the most repeated (at 16,384 evaluations every k above 14 reads about 16,380 distinct and is invisible; at 2^20 evaluations a k = 18 site reads about 2^18 distinct against 2^20 uniform). The bound: distinct index values per site over 2^20 evaluations at least 2^19.5 (about 740,000), run once on the chosen candidate (about 10 s per candidate), with the most-repeated-value bound at 16,384 beside it. (3) The null's tail: the Poisson spread of ratio_w at 2^24 nonces is about 0.2 percent, so a seed at 1.22x is hundreds of sigma from the sampling null and a higher nonce count tightens nothing; sub-version 1's 53 clean seeds median 1.004x, p75 1.051x, max 1.156x (p17), then 1.103 and 1.080, the window model's own error, not noise; sub-version 2's three no-source seeds are reproducible under a re-draw (p10 1.5048x on sub-version 1 and 1.5036x on sub-version 2 with the identical program; p4 1.57x to 1.22x with the rule; p8 1.38x): structure the predictor does not name (near-zero or low-entropy sources whose images sit in the 0x40xxxx band), not tail. Defendable to an auditor: 1.2x sits just above the window model's measured error (1.04x over the clean maximum, 1.15x over the clean p75) and far above the sampling null; a seed over it with no named source is reported as unattributed and chased, never absorbed; neither the threshold nor the nonce count moves. Also: F6 closed PASS at 13:57Z (the worst of 10^5 programs 8.708 ms on the half-core proxy); the 64-seed census on sub-version 2 at 46 of 64, 8 over, finish about 14:40Z. THE LINE FOR SUB-VERSION 3 (the coordinator to the hash lane, 15:3x UK): commit now with the dynamic rule in two parts keyed on the class v4 shape: (A) per load site the count of distinct index values over 2^20 evaluations of the chosen candidate at least 2^19.5, run once on the candidate that passed (a') and the repeat bound, a failing candidate rejected and the next attempt drawn under the same 256 cap and last resort; (B) the most-repeated-value bound at 16,384 evaluations at 8 beside it; the threshold stays 1.2x; new ids, packs and fingerprints; the string to the attack-pass and fleet lanes; nothing to any PC. The 0.3.21 re-pin target moves from 8bdcbdd8 to sub-version 3's commit, on the coordinator's word after both gates, before 19:00Z or not at all for 0.3.21. MAIN'S WORD (15:4x UK): the plan accepted as written: 0.3.21 stages on byte 5; byte 7 only if sub-version 3 reads green on both gates by 19:00Z with the gate defined in numbers; otherwise sub-version 3 is 0.3.22's, read green before it is proposed; do not force the clock. AP-F8-2's EXHAUSTION HALF CLOSED: 10^6 chain-shaped seeds at 8bdcbdd8 through the chain path, 0 exhausted, 0 panics, max attempt 35, 4 seeds past attempt 31 (4e-6, inside the (2/3)^32 estimate), none at the last resort, r = 0.67, mean 2.0 attempts; final 14:03:53Z; FIXED-AND-PASSED in the pass record. The hash lane's sub-version 3 commit waits on its known-failed test's result on box 2, then the re-export, fingerprints, suite, census and the three strings. A SEPARATE FINDING ON THE 0.3.20 LINE (the node lane from the fleet's per-node read at 14:05Z, ledger N15 on ca3-v4-node): the exec layer's chain block number is the node's own record index (seeded from genesis, the restart pin or a snapshot, extended one per chain block the follower appends), not a canonical index of the DAG; seven standing provers number the same DAG block 2 to 46 higher than the hub and the five paid boxes, constant since some past follower event, so their segment records name block ranges the carriers refuse ("is not chain block N on this chain"; p1-5090's record for the worked example carried seven times and refused seven times while p1-4090's for the same DAG blocks was paid); a prover on a drifted node is never paid whatever the card or the claim rule. Nothing on chain is wrong and the pin's gates stand; the fleet scans the two worst nodes for the drift point; the fix direction (the number canonical by construction from the pin plus the selected-parent distance, a continuity check at every append, a drift self-check at start, the carrier resolving a record's segment by the block hash it names) in 0.3.21 if the scan names the event in time, else 0.3.22. Per tier: the hub and the five paid boxes are right; seven standing provers earn nothing until their node is restarted on a clean number or the fix lands; a solo miner is untouched. AP-F8-3, THE ROOT OF THE RESIDUAL CLASSES (the hash lane, 15:5x UK; in the attack-pass record c2203b55): accept.rs never runs the latency-shadow block. Its interpreter run_unit was written for class v2 and v3 and executes the 64 base instructions per iteration and nothing after instruction 63, while the hash (verify.rs, the GPU kernels) runs the shadow block 27 times at the end of every iteration. So every dynamic acceptance test on a class v4 program, (c), (c') and the (A) and (B) bounds, judged a program the chain never hashes: the forced equalities and constants that make F8's bands are produced by the shadow's lossy pairs (or r2 |= r1 then or r1 |= r2, the xor swap), which the acceptance never executed. Confirmed on the prepared bounds: p23 at attempt 4 passes (B) at 16,384 and (A) at 2^20 evaluations (492 ms on one box-2 core) because in the shadow-less run its registers are uniform. (c)'s own v4 figures (saturation, bias, distinct addresses) were measured on the wrong program, harmless only because the base program alone is a well-formed v3 program. THE FIX (sub-version 3): run_unit executes the shadow block after instruction 63 of every iteration, reps times with the iteration's sel, exactly as verify.rs does (the shadow holds no load, so its instructions take the same arms); then (B) at 8 repeats over the 16,384 (c) evaluations and (A) the distinct-index floor of 2^19.5 over 2^20 evaluations, both keyed on the v4 shape; (a'), the 256 cap and the last resort unchanged; a new stream and a new acceptance verdict for v4 (new ids and packs), v2 and v3 untouched (their shadow is empty). The known-failed test on p23, p15 and p18 re-runs on box 2 with the shadow executed; its result and the draw-cost line at 2^20 (492 ms per chosen candidate before the shadow, more with it) decide the commit. The attack-pass lane ships a class check beside the fix (the acceptance's program equal to the hash's). Per tier: nothing on the live chain changes (sub-version 1's acceptance is the same shadow-less check and its programs hash exactly as published); the auditor's finding is that class v4's acceptance was checking the wrong program since 6 October, closed in sub-version 3. THE SUB-VERSION 3 BUILD RESULT (the hash lane, box 2, 14:09Z): run_unit now executes the shadow block as the hash does and the test acceptance_executes_the_shadow_block_as_the_verifier_does is green (the acceptance's execution and verify.rs agree on the output bit counts over the 64 units for the devnet epoch-0 program and the six test eras, 8 x 256 x 27 shadow instructions per hash; the same program with its shadow stripped gives different counts, so the two paths cannot diverge silently again). But (A) and (B) do not reach the class even with the shadow executed: F8's exact p23 candidate (attempt 4, id 06263572197875d2, measured at 4.82x) passes (B) at 8 repeats over 16,384 and (A) the 2^19.5 distinct-index floor over 2^20 evaluations (2.08 s on one box-2 core), no low-entropy site. The acceptance now runs the whole program, so the remaining difference from the census is the dataset (the acceptance's seed-keyed closed-form words against the chain's memory-hard items) or the census's consecutive nonces; a band that exists only under the real dataset is outside the reach of any in-acceptance rule unless the acceptance builds the real dataset (a 256 MiB cache fill and a 1 GiB day per candidate: seconds to minutes per attempt). The attack-pass lane localises p23's zero (which iteration, which registers, whether it reproduces on the closed-form dataset; the register history at instruction 38 on the memory-hard day, the closed-form words and random against consecutive nonces), which decides whether the rule is nonce-aware, dataset-aware or structural; neither is a 19:00Z build with a 75-minute census behind it. THE DECISION (the coordinator under main's accepted plan, 16:1x UK): 0.3.21 ships byte 5; sub-version 3 is 0.3.22's. The hash lane commits the shadow fix with the agreement test as sub-version 3's first commit (a new stream, new ids, byte 7 unchanged; AP-F8-2's exhaustion half FIXED-AND-PASSED at 8bdcbdd8 and AP-F8-3 fixed in the ledger entry); (A) and (B) held uncommitted until the localisation lands, with the cost of each form on one line (the dataset-aware form's cache fill per attempt decides it). The node lane and the shipper told: no re-pin and no CLASS_SIGNAL change in 0.3.21; byte 7 reserved for sub-version 3, byte 6 for class v5. Per tier: no miner, pool or chip consequence tonight; the auditor's record carries sub-version 1's 11 of 64, sub-version 2's 8 of 56, AP-F8-2 closed and AP-F8-3 found and fixed, with the uniformity rule open as a named item. THE N15 DRIFT FIX DONE (the node lane, 14:13Z): rides 0.3.21 as two commits after f95178a1, branch numbering-fix on the mirror at d8bceca5 (a6864e36: the chain path's continuity rule, the orphans above the fork point handed to the reorg unwind; d8bceca5: the start-time self-check from the restart pin against the DAG's selected parents, the first break unwound and re-walked, and recordsContinuous and continuityBreak on the status RPCs so a prover claims only on true); the scans named both events (p1-5090's short reorg path at 15:51Z on 6 October, p2-3090-3's inherited snapshot at 21:09Z); two unit tests known-failed first, the exec suite 35 passed, the kaspad check green on build-2 at 14:13Z; the live line is the fleet's restart of the two drifted boxes on the 0.3.21 candidate. Plan 6.9 reads byte 5 with igneum-pow 8c728ca3, no CLASS_SIGNAL change. SUB-VERSION 2's FINAL VERDICT (the attack-pass lane; the 64 seeds p2 to p65 at 2^24 nonces, chain path, window-model control, box 2, 13:10:15Z to about 14:40Z; pairing id a788661687db4bb3): FAIL, 55 of 64 PASS (0.9915x to 1.144x), 9 FAIL. + +| Seed | Ratio | Hottest item, reads | Site, instruction, share of the site's reads in the top 0.1 percent | Source | +|---|---|---|---|---| +| p23 | 4.82x | 0x000000, 41,727 | site 7, instruction 38, 9.43 percent | or-then-xor same-operand mask over a mulhi (r6 and not r4) | +| p19 | 3.32x | 0x400000, 28,114 | site 15, instruction 62, 6.64 percent | unchanged from sub-version 1 | +| p15 | 2.57x | 0x000000, 12,313 | site 2, instruction 12, 4.49 percent | | +| p18 | 2.50x | 0x75f0fd, 13,866 | site 6, instruction 30, 5.55 percent | | +| p56 | 2.01x | 0xbeb53c, 6,091 | site 2, instruction 10, 3.34 percent | unattributed | +| p10 | 1.50x | | site 8, 2.04 percent | unattributed, identical to sub-version 1 | +| p8 | 1.38x | | site 14, 1.42 percent | unattributed | +| p34 | 1.25x | | site 1, 1.35 percent | | +| p4 | 1.22x | | site 1, 1.45 percent | unattributed, 1.57x on sub-version 1 | + +Every failing seed is ONE low-entropy load site; the mechanism is lineage-blind (AP-F8-1's residual) and the acceptance could not see it because it never ran the shadow block (AP-F8-3). SUB-VERSION 3's FIRST COMMIT: ca3-v4-amend ddacfbd3, 14:20:37Z (origin and build, gate GREEN): the acceptance executes the shadow block as the hash does, the test pins it to verify.rs on the seven v4 programs; PROGRAM_SUBVERSION_V4 = 3; byte 7; (A) and (B) held in a stash. Epoch-0 id a785001687d8688a (must-differ c120d7963abdcd96, 1a4230699a6b9c60, a788661687db4bb3; the devnet seed still accepts at attempt 1, so its program is sub-version 2's under the new id); the seven fingerprints unchanged from sub-version 2 for the same reason (e370fb2080b7dbb1, b7237555d31fc3cf, b6b167fa15dfe2c9, 28bdf65eff33f2c4, e26d38c46f3f1b16, dd8fdf6ff4f59eed, 8bf40f5cb858d835; control 90f794dd556f7a3b; Metal = Apple OpenCL 14:18:41 to 14:19:13Z), so the fleet and PC 2 G1s already read them and the G1 on sub-version 3's packs is a re-run of a known result; packs zip packs-ca3-v4-sub3 sha256 4f2445c50c58d76a5544023492d8b858d0b07c5e372d31f9c90c4ce51f829154; the ledger entry carries AP-F8-2's exhaustion half FIXED-AND-PASSED at 8bdcbdd8 and AP-F8-3 fixed here; the suite and the 4,096-seed census at ddacfbd3 on box 2. THE LOCALISATION (the hash lane): p23's band is dataset- and nonce-independent and reproduces in the acceptance's own execution: site 7 (instruction 38) reads r6 after 25 mulhi, 31 or r6 |= r4, 35 xor r6 ^= r4, which is r6 and not r4, an AND mask the lineage rule counts as fresh because the xor's operand is the or's; over 2^20 evaluations on the closed-form words site 7 reads 874,953 distinct word indices against about 1,046,500 at every other site (0.84 of uniform, 2.2 s on one box-2 core); over 2^24, 8,979,203 against about 16,260,000 (0.55, 35 s). THE COST LINES FOR THE SECOND COMMIT (0.3.22): structural (an abstract value class tracking shared operands) 0 s per attempt, this idiom only; the distinct-index ratio at 2^20 2.2 s per chosen candidate; at 2^24 35 s; no dataset-aware form needed (no cache fill). The hash lane's recommendation: the ratio at 2^20 with the threshold set from the clean seeds' per-site spread (p23's site 0.84; every clean site 0.995 to 1.000), plus the structural rule for the idiom so the ratio is a never-firing check on it. The attack-pass lane's verdict: sub-version 3 is the stream to gate and cannot read green by 19:00Z; byte 5 for 0.3.21 stands on its evidence. THE THRESHOLD NUMBERS FOR SUB-VERSION 3's SECOND COMMIT (the hash lane, box 2, the per-site distinct-index ratio over 2^20 evaluations against the window expectation N minus N^2 / 2W, on the 64 F8 programs as ddacfbd3 draws them, 2.8 s per seed on one core, all sixteen sites): the 55 clean seeds' per-seed minimum 0.9962 to 1.0000 (median 0.9999); over all 880 clean site rows min 0.9960, p1 0.9990, p5 1.0000, median 1.0000. The nine failing seeds' minimum site: p23 0.8361 (site 7), p18 0.9274 (site 6), p19 0.9335 (site 15), p15 0.9432 (site 2), p56 0.9654 (site 2); then p34 0.9927, p4 0.9961, p8 0.9963, p10 0.9963. A threshold of 0.98 sits 0.016 under the clean minimum and 0.015 over the strong five's maximum and rejects exactly those five; the weak four (1.22x to 1.50x in F8's gate) sit inside the clean spread at 2^20 and no threshold reaches them without rejecting clean seeds; a 2^24 run (35 s per candidate) on the weak four, p23 and five clean seeds measures whether they separate there (p23 went 0.84 to 0.55). The structural rule is in and bites where the band was: with the shared-operand relation tracked in the draw and in (a'), p23's attempt 1 draws site 7 from r5 instead of r6 (the or-then-xor on r4 marked r6 lossy); the devnet seed still accepts at attempt 1 (id unchanged); the (a') fixpoint carries the relation. THE COORDINATOR'S LINE: decide by the 2^24 lines: if they separate the weak four from the clean seeds with a gap at least the 2^20 gap, commit (iii), the 2^20 ratio at 0.98 always plus the 2^24 ratio only when the 2^20 per-seed minimum sits under a band edge set from the clean p1 with margin (0.999 fires it on about 1 percent of clean candidates, 35 s once an hour on a node); otherwise commit (i), the 2^20 ratio at 0.98, and name the weak four (p4, p8, p10, p34) as the open tail in the ledger and the commit, unattributed-and-chased, not absorbed. SUB-VERSION 3's SECOND COMMIT: ca3-v4-amend 017e7037 (017e70376489251e18564c0abce7e466e606c8b3; origin and build; gate GREEN; CI run 37639406567 queued), choice (i) by the 2^24 lines: 2^24 does not separate the weak four from the clean seeds (weak p34 0.9181, p4 0.9614, p8 0.9630, p10 0.9612; clean p44 0.9612, p52 0.9613, p3 0.9971, p2 1.0004, p5 1.0004; p23's chain attempt 1 1.0004), two clean seeds sitting on the weak four's value, so any 2^24 floor that reaches them rejects clean seeds. Committed: the per-site distinct-index ratio at 0.98 over 2^20 alone (ACCEPT_UNITS_DISTINCT_V4 = 4096, MIN_DISTINCT_RATIO_V4 = 0.98; expectation per site N minus N^2/2W, window 2^28 >> min(win, 2), the shadow executed), no 2^24 stage, (B) unwired; the structural shared-operand rule in the draw and in (a'); the open tail named in the ledger and the commit: p4, p8, p10, p34 (0.9927 to 0.9963 at 2^20), unattributed and chased. + +| Threshold line | Value | +|---|---| +| Floor at 2^20 | 0.98 | +| Clean minimum over the 55 clean seeds' 880 site rows | 0.9960 (p1 0.9990, median 1.0000) | +| Strong five | p23 0.8361, p18 0.9274, p19 0.9335, p15 0.9432, p56 0.9654 | +| Margin | 0.015 to each side | +| Cost per chosen candidate | one 2^20 pass, 2.1 to 2.2 s on one box-2 core, once an hour on a node | + +Known-failed test class_v4_distinct_ratio_rejects_the_low_entropy_band green on box 2 (12.95 s): p15 attempt 3 (52638ea2e8b0fd68) site 2 at 0.943; p18 attempt 2 (9a37e9489d8ba698) site 6 at 0.927; p19 attempt 0 (79d7441de0689223) site 15 at 0.933; p56 attempt 2 (486a8ad2701ec3b5) site 2 at 0.965; p23 attempt 1 (d65122675f16a1c7) draws site 7 from r5 and passes, and with r6 put back is refused by (a') UnfreshLoadSource and, run anyway, by the ratio at 0.836. Stream unchanged from ddacfbd3 (re-export diff 0 on all eight packs): id a785001687d8688a, the seven fingerprints and the packs zip sha256 4f2445c5... as recorded. THE SUITE AT 017e7037 on box 2: 103 of 103 (64 lib + 7 derive + 4 mixer + 19 packs + 2 recheck + 7 scratch, 3 diag ignored), rc 0; the lib tests 140.8 s against the 41 s whole-suite line at ddacfbd3, because every class v4 draw in the tests pays the 2^20 ratio pass on its chosen candidate (2.2 s each): a CI-time cost, not a node cost (one pass per epoch draw). CI run 37639406567 on 017e7037 success. THE CENSUS AT 017e7037 (box 2, 4,096 chain-shaped seeds plus F8's p1 to p3, draws in parallel across the cores; tools/ca3-v4-uniform now draws across available_parallelism since the serial run became a four-hour job): 4,099 programs, 0 lossy-sourced load sites of 65,584 (57,322 injecting, 8,262 bijective), 0 exhaustions; attempt histogram 0:1297 1:899 2:609 3:416 4:298 5:197 6:125 7:92 8:54 9:46 10:21 11:14 12:13 13:9 14:6 16:2 17:1, mean 2.086, max 17 (ddacfbd3 read 1328/917/622/409/284..., mean 1.998, max 17): the ratio refuses about 4 percent of candidates that pass every other test, one extra attempt on about one seed in twelve, the worst case unchanged at 17; devnet epoch-0 at attempt 1, id a785001687d8688a; F8's p2 attempt 5, p3 attempt 1. The attack-pass lane's class check: ddacfbd3's shadow-executed verdicts against 8bdcbdd8 on 598,678 chain-shaped seeds move 11,990 (2.0 percent) to a different attempt, 0 exhausted, max 32; on 017e7037 the pairing holds and the 64-seed gate at 2^24 plus the 10^6 exhaustion count run to about 16:05Z. The hash lane's ledger lines 2a111fb1 on origin and build (the GitHub 500s cleared on their own), CI run 37642582140 success at 15:25Z; the hash lane has nothing in flight. Nothing on the hash side stops a cut of sub-version 3 at 017e7037 for 0.3.22; then the attack-pass lane's 64-seed gate at 2^24 and 10^6 exhaustion count. Owed as before: G2, G3, the ladder re-measure, AMD (PC 1), the 2019-class core, the fleet and PC 2 G1 on the sub-version 3 packs (a re-run of a known result). release-0.3.21-node STAGED (the node lane, 16:0xZ): 96161037 on the mirror, at the shipper's sweep-end word, in the final order on 55768f88 (c631c64b, 52e96c94, f067f7c1, b0444f51, 437f0438, 2e32d5f6, f95178a1 cherry-picked, a6864e36 and d8bceca5), pairing igneum-pow 8c728ca3 at byte 5, no re-pin. The whole set on the tip green: consensus-core 126, the consensus crate whole (lib 120, both integration targets), igneum-miner 25, kaspa-pow 17, igneum-exec 36, the three checks, 15:49 to 15:57Z on build-2. Binary built on build-1 at 15:58Z, igneumd sha256 f99340b3cf4ce32e, the string read back; the digest eada4bda on the previous live object and 4bbbe816 on the published floor file (so the 0.3.20 floor file is published), as the pin reads them. The node lane's digest and mixed-version gates on it from 16:00Z; the fleet's set from the same minute; plan 6.9 carries the steps and the two box-input rules the staging added. THE 0.3.20 RECORD (the shipper, UTC). Cases: the dc141409 run on c18-1 CASES END rc 0 at 12:37:18Z (both halves PASS); the c4459193 run on c20-1 CASES END rc 0 at 14:54:02Z with its relay half void (one RunPod host, no hairpin) and the poison half PASS (13 rejected, 0 accepted); main's (b): the publish on the dc141409 cases plus the diff argument (the class byte the only touch in the cases' territory) and c19-1's tip-following, with the separate-host relay re-run on c19-1 on the live digest as the halt condition and the Discord card's gate (CASES END about 16:25Z). PUBLISH 14:54:17Z (15:54 BST): manifest 0.3.20, mac DMG sha256 73796c5f..., Windows installer 45b2f3fb..., the hive tar d9dd12df... on the public alias. THE FLOOR FILE: program_class_v4_activation_daa 900,000 (the live DAA 294,073 at 14:51Z; 294,073 + 604,800 = 898,873 rounded up to the 3,600 boundary), window 86,400 unchanged, file sha256 294f1f80...; the digest 4bbbe8162ea9fff277aa5b16b4ffad9e2262ba5e6a5acac7b697ff77211e7328 read on c4459193's binary before the cut and on the hub's handshake line after. The pin c4459193, igneum-pow 8c728ca3, byte 5; the sweep's node pair a80ed39c / 70a5180f (the build-server lane's native build of the same tree). THE SWEEP complete 15:39Z (16:39 BST): wave 1 the hands (observer-node, node1 at 14:57Z), the Mac (15:23Z on its poller, interface 1.0.1), the hub, pool-1 and the eight heaviest voters (15:04 to 15:21Z); wave 2 the four lighter voters (15:23 to 15:26Z); wave 3 Devnet 2's four pods and bps-seed (digest 4a0b8726 unmoved); the first new-side lock 9313 at 15:28:08Z after a 23-minute split; every lock line "sweep complete before 13 October 09:00 UK (the margin; the floor is now DAA 900,000)". 0.3.17 nodes remaining: PC 1 and PC 2 (offline for the project lead's cable work; their apps update on their pollers on return) and the three testnet seeds (on the testnet, not on the devnet's floor); no devnet node of the fleet, the hands or the Mac on 0.3.17. EARLIEST FLIP: the floor at DAA 900,000 is about 7.0 days of DAA from the publish (605,927 DAA at about one a second), so about 14 October 23:00Z (15 October 00:00 BST) at the earliest, and only once the seven 86,400-DAA windows read 95 percent of blue weight signalling byte 5; the live floor of 831,600 (13 Oct 08:00Z) is replaced by the published file on every swept node, so the chain never flips to the 6 October stream. Per tier: a solo miner on the Mac or a swept box mines on; a PC miner on 0.3.17 is refused by digest when it next connects until its app updates (its poller does this on return; nothing by hand); the pool and the hub are on the pin; the auditor reads one object, one digest, one floor. + +SUB-VERSION 3 PASSES BOTH GATES (the attack-pass lane, the close line dated 7 October 2026): class v4 sub-version 3, commit 017e70376489251e18564c0abce7e466e606c8b3 on ca3-v4-amend, pairing id a785001687d8688a (verified by the harness). F8's 64-seed census (p2 to p65) at 2^24 nonces each, chain path, window-model control, box 2, 14:51Z to 16:00:20Z: PASS, 60 of 64 under 1.2x (0.9915x to 1.144x); the only four over are the named tail, unattributed and chased: p10 1.5036x (identical to sub-versions 1 and 2, hottest item 0x4004da at 362 reads, no predicted source), p8 1.3776x (0x837de4, 420 reads), p34 1.2505x (0x800010, 541 reads, the one-bit value through sub at 5), p4 1.2167x (0x4000e7, 355 reads); every strong seed gone (p23 4.82x, p19 3.32x, p15 2.57x, p18 2.50x, p56 2.01x all under 1.2x); the worst ratio on the stream 1.50x; the tail's hottest items carry 355 to 541 reads of 2^31 (one to two per 2^22 items above the mean), no chip consequence. The exhaustion gate as it is: the chain-path count on 017e7037 runs slowly (the draw evaluates (c'') at 2^20 per candidate: 20,532 seeds in 59 minutes, 0 exhausted, 0 panics, max attempt 29), so a 10^6 count is two days away and is not waited on; the substance is met by construction (the 256 cap and the last resort unchanged from 8bdcbdd8, 0 of 10^6 there) and by measurement at 017e7037 on 24,631 seeds (0 exhausted, max 29; r about 0.68); the count runs on as a strengthening line. The node's epoch draw now costs about 2 attempts at 2.2 s each, 4 to 5 s per epoch on slower cores, once an hour. The hash lane's ledger at 6941da1d. SUB-VERSION 3 AT 017e7037 IS THE FROZEN GENERATOR FOR 0.3.22 (byte 7), THE TAIL RULED (main, 18:1x UK): the four seeds (p10 1.5036x with its hottest item at 362 reads, p8 1.3776x at 420, p34 1.2505x at 541, p4 1.2167x at 355, of 2^31 reads) are accepted as the window model's unattributed residue at 1.22x to 1.50x with nil chip consequence; the AP-F8-1 row CLOSES with that wording and the hottest-item counts beside it; the 10^6 count on 017e7037 runs on as the strengthening line. The attack-pass plan's start 15 October or the morning after. 0.3.21's FIRST CANDIDATE 96161037 (sha256 f99340b3cf4ce32e, string read back) passed the node lane's two gates on its own binary: the digest gate 15:59:54Z to 16:01:32Z PASS (a89be8a7 with the peers right; db9a85f9 refused, no peer); the mixed-version gate 16:01:53Z to 16:12:05Z PASS (one digest b0afb2ee on five; 252 new and 352 old accepted, 0 rejected; counts equal at 316, 493 and 604 through both clean joins and the restart step; no panic); the node side complete; the fleet's set on the same binary (the kept start with the ids gate, the wipe canary, the cases rerun, the 12 GB line, N15's restarts of p1-5090 and p2-3090-3) is what the shipper's pin word waits on; byte 5 throughout, nothing on the class v4 seam moved. DEVNET 3 NOW (the project lead through main, 17:3x BST): 0.3.22 is the Devnet 3 release (a fresh network object igneum-devnet-3 with every activation at 0 and no override file, the era VDF fork, class v4 sub-version 3 at byte 7 from genesis), the node building on build-1, genesis by 17:30Z (18:30 BST). THE HANDOFF (17:3x BST, inside the 17:40 BST line, to the shipper and the node lane): igneum-pow 017e70376489251e18564c0abce7e466e606c8b3 (the audit-freeze-2026-10-07 tag; 2a111fb1 and 6941da1d above it docs only), object byte 7, PROGRAM_SUBVERSION_V4 = 3, devnet epoch-0 program id a785001687d8688a (must-differ c120d7963abdcd96, 1a4230699a6b9c60, a788661687db4bb3), kit packs-ca3-v4-sub3 zip sha256 4f2445c50c58d76a5544023492d8b858d0b07c5e372d31f9c90c4ce51f829154, the eight fingerprints as recorded (equal on Metal, Apple OpenCL, the fleet 5090 and PC 2's 5090), both attack-pass gates GREEN, suite 103 of 103, CI success; the open items stated as open: the four-seed tail under main's ruling (the attribution for 0.3.23), the 10^6 count as a strengthening line, the 4 to 5 s epoch draw, the owed measurements that do not gate Devnet 3. NO FURTHER HASH CHANGE RIDES ON 0.3.22; anything from the tail goes to 0.3.23. The node lane stages the re-pin on the 0.3.21 tip as its own commit (the fork commit and the kaspa-pow suite line owed to this record); the hash lane's sub-version 3 pairing follows it. THE PUBLIC CHIP TEXT REWRITTEN LAUNCH-FIRST (the project lead: "I thought we were making it 2.1 from launch?"; master 9b996d06, docs/plans/counter-asic-3-public-text-2026-10-07.md): the testnet and mainnet objects set program_class_v4_activation_daa 0, so class v4 is live from genesis and the launch number is 2.1x to 3.9x on day one; the three texts and evidence row 17 lead with that (labels kept), then class v5, then the 5x to 9x only as the class v3 baseline the work started from, the devnet's activation height a devnet fact only; no em dashes, no prize mention, eight columns; with the site lane to apply in the same deploy as the padding sweep (its commit and deploy time owed to this record). The lane carries on until the re-pin line, the site commit and the genesis record land. 0.3.21's STAGING (the node lane): the order dry-merges onto 55768f88 with nothing moving to 0.3.22; the late-join fix is 52e96c94 (70e4601e rebased onto 55768f88, exec suite 33 green with both new tests); f067f7c1, b0444f51 and 437f0438 merge clean in order; 2e32d5f6's one conflict (DST_ADDRESS beside pool-finish's DST_BINDING in consensus/core/src/finality.rs) kept both; the live-file digest eada4bda after each (every switch at never); the staging waits on the shipper's sweep-end word; the re-pin held. PC 2 DOWN AGAIN (main, 16:5x UK): the project lead takes PC 2 down for cable work (PC 1 back but his desk); both PCs out of the sweep's waves, each updates on its poller on return; no PC job to PC 1; the Windows G1 completed before the outage, nothing reruns. 0.3.21's SECOND GATE LINE on 55768f88 (sha256 279b1b690e854fc9): the ten-minute mixed-version gate beside the 5899f603 pair, 13:37:40Z to 13:47:52Z, SUMMARY PASS (one digest b0afb2ee on five nodes; 223 new and 381 old blocks accepted by the old hub, 0 rejected; counts equal at 319, 486 and 604 through both clean joins and the restart step at 13:45:22Z; no panic); the node lane's two lines on 0.3.21's first candidate complete, in plan 6.9 on ca3-v4-node; the fleet's set on it (the bare-child 12 GB line, the wipe, the kept read, the cases) is the fleet's. 0.3.21's FIRST GATE LINE on 55768f88 (sha256 279b1b690e854fc9, the string read back; pairing igneum-pow 8c728ca3 at byte 5): the digest gate 13:35:41Z to 13:37:19Z SUMMARY PASS (a89be8a7 on both binaries with the peers; db9a85f9 refused, no peer; the live file's eada4bda unmoved); the ten-minute mixed-version gate from 13:37:40Z, line about 13:50Z. The 0.3.21 order as the shipper sent it: 55768f88; f067f7c1 and 70e4601e; b0444f51; 6eb21fc9; db28d331; then the re-pin from 8bdcbdd8 on the coordinator's word; suites between, the digest read after every one; the mirror's release-0.3.20-node back at the pin c4459193, release-0.3.21-node open at 55768f88. THE LATE-JOIN COMMIT (N9's second half, the node lane): 70e4601e on the box mirror as branch proof-hold-fix, from c4459193, two files (igneum/exec/src/proving.rs, protocol/flows/src/v10/proving.rs); the gap was the fetch side on the joiner (the served record ran the native check against the joiner's trailing exec state before anything was stored, the check refused it, the proof was never held, the body rule read "not held" for 20 s and failed the IBD); the fix holds the proof by hash before the checks (the pool entry still needs them) and the serve side says when it holds fewer than asked; the exec suite 32 passed at 13:26Z with the known-failed shape first, the flows check green 13:28Z, igneumd on build-1 at the 0321 worktree path built 13:32Z, sha256 17649eeb2f7d1290, string read back; with the testnet lane (the resume form, B alone); it joins the 0.3.21 staging as its own commit. THE WIPE CANARY ON c19-1, c4459193 (sha 45be9b02d1b002f5, string read back): FORM END rc 0 at 13:50:53Z. Wipe synced 13:35:50Z (57 minutes, inside the 98-minute class); mining 13:36:00Z to 13:47:07Z, 66 mined, 66 accepted, 0 rejected, isSynced true at the tip throughout; the hub holds 41 of its blocks in its last 700 with 0 rejects (13:47:09Z); the restart on its kept datadir at 13:47:15Z: the old process stopped at once (the new process's first lock line seven seconds after the marker; the watchdog held nothing, the b7cc37e7 fault closed), synced again at 13:48:39Z after 84 s, 109 templates read with max 3,432 ms and 0 timeouts; the kept read on pool-1's 0.3.17 copy on the same pod passed at 13:38Z (the rewrite line once, a clean second start). The pin's set on c4459193: the digest gate PASS, the mixed-version gate PASS, the wipe canary PASS, the kept read PASS, the restart PASS, the 12 GB line proves and verifies (paid is a race, not a gate); CASES END from c20-1 (about 14:50Z) is the last pin line. THE INTEROP FACT stands from the void run: the 5899f603 hub accepted 235 object-byte-5 blocks from the 8097d600 node with 0 rejected, one digest on all five nodes on the live sixteen-field file. The gates: the digest test and the kaspa-pow vector test (the amended devnet epoch-0 id 1a4230699a6b9c60 must equal, c120d7963abdcd96 must differ, the v3 control unchanged) on the box; the mixed-version Devnet 2 gate (the amended 0.3.20 node beside a 5899f603 node for ten minutes on the live file without the v4 fields) after the Mac build; the fresh-join canary the 0.3.20 cut's | | Main's rulings (7 October, morning) | no generator change to v4 on the live devnet; the record's null is the window model with numbers, sent by the hash lane to the attack-pass lane so AP-F8-1 re-gates against it; a fault beyond the model (a low-entropy source at site 15) stops at the coordinator with the two options priced (a 0.3.19 class amendment before the flip, or the flip held at the floor), nothing shipping without the project lead's word; the tighter tail, an acceptance bound on the hot-set share, is a CLASS V5 item (sent to the v5 lane a6410f3b8abefb762 with the 64-seed census as its gate; the bound's number follows from the model) | ### AP-F4-1, the weak-day MUL draw (the attack-pass lane, 7 October, morning): PASS against v4, a class v5 rule diff --git a/docs/plans/era-layout.md b/docs/plans/era-layout.md index 661d9e02..c1ee708a 100644 --- a/docs/plans/era-layout.md +++ b/docs/plans/era-layout.md @@ -171,7 +171,7 @@ Filled from a CPU census over programs (section 6). ## 8. What is unverified - Everything in section 6 marked pending. -- The 1-hour VDF does not exist; the devnet stand-in of section 2 is a proposal. +- The 1-hour VDF: BUILT on 7 October 2026 (era VDF lane, after the attack pass's F7 row named it the gating dependency): `kaspa_consensus_core::era_vdf` (the class-group Wesolowski scheme on a fixed-width integer and the hash-chain fallback behind the genesis byte `vdf_scheme`), `kaspa_consensus::processes::era_vdf` (the cut rule, the day-of-blues input, the evaluator thread, the record store), behind `Params::era_vdf_activation_daa` (never on every network until the project lead's word per network); the stand-in of section 2 stands below the activation and is what the VDF reads its input from above it. Verified: the F7 re-roll harness against the real era cut fires with the VDF off and is silent with it on across 6 cuts (`tools/era-vdf/reroll.mjs`, the record `docs/analysis/era-vdf-2026-10-07.md` section 3), the parameters and the measured prove and verify times are in spec 04 section 4.6. Still unverified: the P2P relay of a record to a syncing peer (spec 4.5, owed before era 1 of any network with the switch set), the binding of the cut to the certified checkpoint (left at the O-4.3 reading, one function to change), an external review of the class-group port (O-4.1), and the 2019-class-core verify time, which is measured on a proxy until a 2019 host is rented (record section 5). - The interleave's value against a chip with a programmable address decoder is nil (1.2); the claim is limited to hard-wired layouts. - The window floor of 2^26 words is set by the 5090's L2 (96 MiB) and the 9070 XT's Infinity Cache (64 MB, vendor figures); a future card with a larger cache moves the floor, which is a genesis constant. - No cryptanalysis of the stride (a multiply and a rotate before the mask); it is a bijection, so the address distribution is that of the register value, as today. diff --git a/docs/plans/ledger-decisions.md b/docs/plans/ledger-decisions.md index 7639ef79..e794af09 100644 --- a/docs/plans/ledger-decisions.md +++ b/docs/plans/ledger-decisions.md @@ -112,3 +112,10 @@ Standing rulings of the same hour: "We dont want to penalise holders" (dormant-c | 3 | The latency ladder | Approved | The six rungs (27, 35, 53, 88, 173, 267 passes), rungs 0 to 2 admissible, rung 3 re-measured on a quiet core before genesis, 4 and 5 inadmissible until verifiers allow; every step by 90 percent in each of seven windows, never unconditional; `latency_ladder_activation_daa` = 0 on the testnet at rung 0. | | 4 | Cryptanalysis | Approved, "make sure they find ZERO flaws, also cut costs if possible" | The engagement runs at the low point (about USD 80,000) unless a quote forces more; an internal attack pass precedes it so the firms find nothing new; every finding is fixed before the testnet go. The contracting entity and the prize are still the project lead's to confirm. | | 5 | Re-cut the testnet genesis | Approved | One cut with 18 decimals, `TESTNET_1`, and the switches on from genesis: proof verification, the leave item, the signing bonus, finality v3, the ladder at rung 0. Nothing live is touched; the go checklist decides the date. | + +## Era VDF (7 October 2026, 12:xx UK, era VDF lane): two decisions for the project lead + +Question 1, the activation. The era VDF (spec 04 section 4.4) is in the node behind `era_vdf_activation_daa`, never on every network, with the genesis scheme byte `vdf_scheme` 0 (the class group) and `era_vdf_t` at the reference rate of igneum-build-1's core (spec 4.6). Facts: the F7 harness shows the stand-in grindable with one block of hash at no delay and the VDF closing it; the first era with a VDF is era 1, 180 days after a network's genesis; the P2P record relay (O-4.10) is owed before then. Recommendation: igneum-testnet-1 and mainnet carry `era_vdf_activation_daa: 0` in their genesis objects (the switch costs nothing before era 1 and the digest then pins it from the start); the live devnet keeps never (it will not reach era 1). Unblocks: the freeze of the era draw procedure and the C_era cut rule, which the attack pass's F7 row holds open on the VDF. + +Question 2, the cut's binding (O-4.11). The node names the cut block as the chain block the lead rule names, certified or not (the O-4.3 reading of 3 October 2026), so a finality pause across the cut never leaves an era without a seed and the rule is a function of the header's past alone. The design document's wording binds the era draw to the last certified checkpoint. Facts: the grinding defence does not depend on the binding (the delay makes any candidate's draw unknowable); the certified binding couples the era seed to finality liveness and needs a rule for a certificate that lands after the cut (`docs/analysis/era-vdf-2026-10-07.md` section 4). Recommendation: keep the O-4.3 reading for the era as for the epoch; one function (`EraVdfManager::cut_block`) changes if the finality lane wants the certified binding. Unblocks: the sentence in spec 4.4 step 1 stops carrying "under the O-4.3 reading" once decided. + diff --git a/docs/plans/mission-item-12-gate/case-off-eight.log b/docs/plans/mission-item-12-gate/case-off-eight.log new file mode 100644 index 00000000..82d701bf --- /dev/null +++ b/docs/plans/mission-item-12-gate/case-off-eight.log @@ -0,0 +1,21 @@ +13:27:58.207 pd1 case switch-off-expect-eight: switch off, 10 listing nodes, joint 200 s, watch 180 s, expect eight +13:27:59.744 pd1 n0 up pid 690270 json 31292 p2p 31291 +13:28:01.258 pd1 n1 up pid 690864 json 31302 p2p 31301 addpeer 31291,31291 +13:28:02.766 pd1 n2 up pid 691561 json 31312 p2p 31311 addpeer 31291,31301 +13:28:04.272 pd1 n3 up pid 692232 json 31322 p2p 31321 addpeer 31291,31311 +13:28:05.777 pd1 n4 up pid 692823 json 31332 p2p 31331 addpeer 31291,31321 +13:28:07.281 pd1 n5 up pid 693470 json 31342 p2p 31341 addpeer 31291,31331 +13:28:08.785 pd1 n6 up pid 694063 json 31352 p2p 31351 addpeer 31291,31341 +13:28:10.290 pd1 n7 up pid 694656 json 31362 p2p 31361 addpeer 31291,31351 +13:28:11.797 pd1 n8 up pid 695316 json 31372 p2p 31371 addpeer 31291,31361 +13:28:13.304 pd1 n9 up pid 695947 json 31382 p2p 31381 addpeer 31291,31371 +13:31:35.437 pd1 phase 1 done at 200.1 s: node 0 at 243 blocks DAA 243; 0 directory listing line(s) on node 0 +13:31:36.962 pd1 fresh up pid 705981 json 31392 p2p 31391 addpeer 31291 +13:32:07.031 pd1 t=231.7 s fresh: 1 outbound, 0 inbound, 272 blocks, 0 draw line(s), 0 directory connection(s) +13:32:37.109 pd1 t=261.8 s fresh: 1 outbound, 0 inbound, 314 blocks, 0 draw line(s), 0 directory connection(s) +13:33:07.190 pd1 t=291.9 s fresh: 1 outbound, 0 inbound, 332 blocks, 0 draw line(s), 0 directory connection(s) +13:33:37.273 pd1 t=322.0 s fresh: 1 outbound, 0 inbound, 359 blocks, 0 draw line(s), 0 directory connection(s) +13:34:07.348 pd1 t=352.0 s fresh: 1 outbound, 0 inbound, 379 blocks, 0 draw line(s), 0 directory connection(s) +13:34:37.426 pd1 t=382.1 s fresh: 1 outbound, 0 inbound, 420 blocks, 0 draw line(s), 0 directory connection(s) +13:34:37.428 pd1 SUMMARY FAIL (switch-off-expect-eight): node 0 logged 0 listings; the fresh node never reached 8 outbound (last 1), 0 connection(s) from the directory, 0 draw line(s), 420 blocks; FAILED CHECK listing_lines_on_node_0, fresh_reached_eight_outbound, fresh_connected_from_directory +13:34:37.428 pd1 summary: /srv/builds/igneum-wt-peer-directory/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-eight.json diff --git a/docs/plans/mission-item-12-gate/case-off-one.log b/docs/plans/mission-item-12-gate/case-off-one.log new file mode 100644 index 00000000..fe4af039 --- /dev/null +++ b/docs/plans/mission-item-12-gate/case-off-one.log @@ -0,0 +1,21 @@ +13:27:58.206 pd0 case switch-off-expect-one: switch off, 10 listing nodes, joint 200 s, watch 180 s, expect one +13:27:59.744 pd0 n0 up pid 690269 json 31092 p2p 31091 +13:28:01.255 pd0 n1 up pid 690863 json 31102 p2p 31101 addpeer 31091,31091 +13:28:02.763 pd0 n2 up pid 691557 json 31112 p2p 31111 addpeer 31091,31101 +13:28:04.270 pd0 n3 up pid 692228 json 31122 p2p 31121 addpeer 31091,31111 +13:28:05.775 pd0 n4 up pid 692819 json 31132 p2p 31131 addpeer 31091,31121 +13:28:07.280 pd0 n5 up pid 693466 json 31142 p2p 31141 addpeer 31091,31131 +13:28:08.786 pd0 n6 up pid 694058 json 31152 p2p 31151 addpeer 31091,31141 +13:28:10.292 pd0 n7 up pid 694658 json 31162 p2p 31161 addpeer 31091,31151 +13:28:11.800 pd0 n8 up pid 695318 json 31172 p2p 31171 addpeer 31091,31161 +13:28:13.306 pd0 n9 up pid 695955 json 31182 p2p 31181 addpeer 31091,31171 +13:31:35.436 pd0 phase 1 done at 200.1 s: node 0 at 250 blocks DAA 250; 0 directory listing line(s) on node 0 +13:31:36.969 pd0 fresh up pid 705982 json 31192 p2p 31191 addpeer 31091 +13:32:07.034 pd0 t=231.7 s fresh: 1 outbound, 0 inbound, 288 blocks, 0 draw line(s), 0 directory connection(s) +13:32:37.118 pd0 t=261.8 s fresh: 1 outbound, 0 inbound, 308 blocks, 0 draw line(s), 0 directory connection(s) +13:33:07.199 pd0 t=291.9 s fresh: 1 outbound, 0 inbound, 349 blocks, 0 draw line(s), 0 directory connection(s) +13:33:37.276 pd0 t=322.0 s fresh: 1 outbound, 0 inbound, 377 blocks, 0 draw line(s), 0 directory connection(s) +13:34:07.351 pd0 t=352.0 s fresh: 1 outbound, 0 inbound, 405 blocks, 0 draw line(s), 0 directory connection(s) +13:34:37.431 pd0 t=382.1 s fresh: 1 outbound, 0 inbound, 448 blocks, 0 draw line(s), 0 directory connection(s) +13:34:37.432 pd0 SUMMARY PASS (switch-off-expect-one): node 0 logged 0 listings; the fresh node never reached 8 outbound (last 1), 0 connection(s) from the directory, 0 draw line(s), 448 blocks +13:34:37.432 pd0 summary: /srv/builds/igneum-wt-peer-directory/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-one.json diff --git a/docs/plans/mission-item-12-gate/case-on-eight.log b/docs/plans/mission-item-12-gate/case-on-eight.log new file mode 100644 index 00000000..968aee53 --- /dev/null +++ b/docs/plans/mission-item-12-gate/case-on-eight.log @@ -0,0 +1,22 @@ +13:27:58.204 pd2 case switch-on-expect-eight: switch on, 10 listing nodes, joint 200 s, watch 180 s, expect eight +13:27:59.743 pd2 n0 up pid 690268 json 31492 p2p 31491 +13:28:01.254 pd2 n1 up pid 690860 json 31502 p2p 31501 addpeer 31491,31491 +13:28:02.762 pd2 n2 up pid 691556 json 31512 p2p 31511 addpeer 31491,31501 +13:28:04.268 pd2 n3 up pid 692227 json 31522 p2p 31521 addpeer 31491,31511 +13:28:05.773 pd2 n4 up pid 692818 json 31532 p2p 31531 addpeer 31491,31521 +13:28:07.279 pd2 n5 up pid 693462 json 31542 p2p 31541 addpeer 31491,31531 +13:28:08.787 pd2 n6 up pid 694062 json 31552 p2p 31551 addpeer 31491,31541 +13:28:10.291 pd2 n7 up pid 694659 json 31562 p2p 31561 addpeer 31491,31551 +13:28:11.800 pd2 n8 up pid 695317 json 31572 p2p 31571 addpeer 31491,31561 +13:28:13.304 pd2 n9 up pid 695954 json 31582 p2p 31581 addpeer 31491,31571 +13:31:35.435 pd2 phase 1 done at 200.1 s: node 0 at 233 blocks DAA 233; 10 directory listing line(s) on node 0 +13:31:36.954 pd2 fresh up pid 705980 json 31592 p2p 31591 addpeer 31491 +13:32:07.025 pd2 the fresh node holds 10 outbound peers at 231.7 s (9 from the directory) +13:32:07.025 pd2 t=231.7 s fresh: 10 outbound, 0 inbound, 262 blocks, 1 draw line(s), 9 directory connection(s) +13:32:37.102 pd2 t=261.8 s fresh: 10 outbound, 0 inbound, 290 blocks, 1 draw line(s), 9 directory connection(s) +13:33:07.182 pd2 t=291.9 s fresh: 10 outbound, 0 inbound, 323 blocks, 1 draw line(s), 9 directory connection(s) +13:33:37.265 pd2 t=322.0 s fresh: 10 outbound, 0 inbound, 357 blocks, 1 draw line(s), 9 directory connection(s) +13:34:07.342 pd2 t=352.0 s fresh: 10 outbound, 0 inbound, 391 blocks, 1 draw line(s), 9 directory connection(s) +13:34:37.418 pd2 t=382.1 s fresh: 10 outbound, 0 inbound, 414 blocks, 1 draw line(s), 9 directory connection(s) +13:34:37.418 pd2 SUMMARY PASS (switch-on-expect-eight): node 0 logged 10 listings; the fresh node reached 8 outbound at 231.7 s, 9 connection(s) from the directory, 1 draw line(s), 414 blocks +13:34:37.419 pd2 summary: /srv/builds/igneum-wt-peer-directory/docs/plans/mission-item-12-gate/peer-directory-switch-on-expect-eight.json diff --git a/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-eight.json b/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-eight.json new file mode 100644 index 00000000..7570b9d6 --- /dev/null +++ b/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-eight.json @@ -0,0 +1,370 @@ +{ + "pass": false, + "expect": "eight", + "case": "switch-off-expect-eight", + "switch": "off", + "listing": 10, + "joint": 200, + "watch": 180, + "node0": { + "blocks": 243, + "daa": 243 + }, + "listing_lines_on_node_0": 0, + "eight_outbound_at_s": null, + "last": { + "t": 382.1, + "outbound": 1, + "inbound": 0, + "blocks": 420, + "daa": 420, + "drawn": 0, + "connected_from_directory": 0 + }, + "checks": { + "listing_lines_on_node_0": false, + "fresh_synced": true, + "fresh_reached_eight_outbound": false, + "fresh_connected_from_directory": false, + "fresh_held_one_outbound": true, + "no_directory_line_on_fresh": true + }, + "failed_checks": [ + "listing_lines_on_node_0", + "fresh_reached_eight_outbound", + "fresh_connected_from_directory" + ], + "samples": [ + { + "t": 206.7, + "outbound": 1, + "inbound": 0, + "blocks": 250, + "daa": 250, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 211.7, + "outbound": 1, + "inbound": 0, + "blocks": 255, + "daa": 255, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 216.7, + "outbound": 1, + "inbound": 0, + "blocks": 258, + "daa": 258, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 221.7, + "outbound": 1, + "inbound": 0, + "blocks": 264, + "daa": 264, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 226.7, + "outbound": 1, + "inbound": 0, + "blocks": 271, + "daa": 271, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 231.7, + "outbound": 1, + "inbound": 0, + "blocks": 272, + "daa": 272, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 236.7, + "outbound": 1, + "inbound": 0, + "blocks": 276, + "daa": 276, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 241.8, + "outbound": 1, + "inbound": 0, + "blocks": 284, + "daa": 284, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 246.8, + "outbound": 1, + "inbound": 0, + "blocks": 289, + "daa": 289, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 251.8, + "outbound": 1, + "inbound": 0, + "blocks": 292, + "daa": 292, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 256.8, + "outbound": 1, + "inbound": 0, + "blocks": 302, + "daa": 302, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 261.8, + "outbound": 1, + "inbound": 0, + "blocks": 314, + "daa": 314, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 266.8, + "outbound": 1, + "inbound": 0, + "blocks": 317, + "daa": 317, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 271.8, + "outbound": 1, + "inbound": 0, + "blocks": 321, + "daa": 321, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 276.9, + "outbound": 1, + "inbound": 0, + "blocks": 322, + "daa": 322, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 281.9, + "outbound": 1, + "inbound": 0, + "blocks": 326, + "daa": 326, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 286.9, + "outbound": 1, + "inbound": 0, + "blocks": 331, + "daa": 331, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 291.9, + "outbound": 1, + "inbound": 0, + "blocks": 332, + "daa": 332, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 296.9, + "outbound": 1, + "inbound": 0, + "blocks": 338, + "daa": 338, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 301.9, + "outbound": 1, + "inbound": 0, + "blocks": 341, + "daa": 341, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 306.9, + "outbound": 1, + "inbound": 0, + "blocks": 344, + "daa": 344, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 311.9, + "outbound": 1, + "inbound": 0, + "blocks": 349, + "daa": 349, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 317, + "outbound": 1, + "inbound": 0, + "blocks": 355, + "daa": 355, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 322, + "outbound": 1, + "inbound": 0, + "blocks": 359, + "daa": 359, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 327, + "outbound": 1, + "inbound": 0, + "blocks": 361, + "daa": 361, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 332, + "outbound": 1, + "inbound": 0, + "blocks": 369, + "daa": 369, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 337, + "outbound": 1, + "inbound": 0, + "blocks": 371, + "daa": 371, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 342, + "outbound": 1, + "inbound": 0, + "blocks": 374, + "daa": 374, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 347, + "outbound": 1, + "inbound": 0, + "blocks": 378, + "daa": 378, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 352, + "outbound": 1, + "inbound": 0, + "blocks": 379, + "daa": 379, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 357.1, + "outbound": 1, + "inbound": 0, + "blocks": 389, + "daa": 389, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 362.1, + "outbound": 1, + "inbound": 0, + "blocks": 400, + "daa": 400, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 367.1, + "outbound": 1, + "inbound": 0, + "blocks": 406, + "daa": 406, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 372.1, + "outbound": 1, + "inbound": 0, + "blocks": 410, + "daa": 410, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 377.1, + "outbound": 1, + "inbound": 0, + "blocks": 416, + "daa": 416, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 382.1, + "outbound": 1, + "inbound": 0, + "blocks": 420, + "daa": 420, + "drawn": 0, + "connected_from_directory": 0 + } + ], + "node": "/srv/builds/igneum-wt-peer-directory/vendor/igneum-node-pd/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-peer-directory/vendor/igneum-node-pd/target/release/igneum-miner", + "slot": 1, + "ports": { + "base": 31290, + "suffix": 976 + } +} \ No newline at end of file diff --git a/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-one.json b/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-one.json new file mode 100644 index 00000000..48d4e328 --- /dev/null +++ b/docs/plans/mission-item-12-gate/peer-directory-switch-off-expect-one.json @@ -0,0 +1,366 @@ +{ + "pass": true, + "expect": "one", + "case": "switch-off-expect-one", + "switch": "off", + "listing": 10, + "joint": 200, + "watch": 180, + "node0": { + "blocks": 250, + "daa": 250 + }, + "listing_lines_on_node_0": 0, + "eight_outbound_at_s": null, + "last": { + "t": 382.1, + "outbound": 1, + "inbound": 0, + "blocks": 448, + "daa": 448, + "drawn": 0, + "connected_from_directory": 0 + }, + "checks": { + "listing_lines_on_node_0": false, + "fresh_synced": true, + "fresh_reached_eight_outbound": false, + "fresh_connected_from_directory": false, + "fresh_held_one_outbound": true, + "no_directory_line_on_fresh": true + }, + "failed_checks": [], + "samples": [ + { + "t": 206.7, + "outbound": 1, + "inbound": 0, + "blocks": 261, + "daa": 261, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 211.7, + "outbound": 1, + "inbound": 0, + "blocks": 271, + "daa": 271, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 216.7, + "outbound": 1, + "inbound": 0, + "blocks": 276, + "daa": 276, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 221.7, + "outbound": 1, + "inbound": 0, + "blocks": 278, + "daa": 278, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 226.7, + "outbound": 1, + "inbound": 0, + "blocks": 282, + "daa": 282, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 231.7, + "outbound": 1, + "inbound": 0, + "blocks": 288, + "daa": 288, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 236.8, + "outbound": 1, + "inbound": 0, + "blocks": 294, + "daa": 294, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 241.8, + "outbound": 1, + "inbound": 0, + "blocks": 296, + "daa": 296, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 246.8, + "outbound": 1, + "inbound": 0, + "blocks": 303, + "daa": 303, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 251.8, + "outbound": 1, + "inbound": 0, + "blocks": 305, + "daa": 305, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 256.8, + "outbound": 1, + "inbound": 0, + "blocks": 307, + "daa": 307, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 261.8, + "outbound": 1, + "inbound": 0, + "blocks": 308, + "daa": 308, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 266.8, + "outbound": 1, + "inbound": 0, + "blocks": 311, + "daa": 311, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 271.8, + "outbound": 1, + "inbound": 0, + "blocks": 315, + "daa": 315, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 276.9, + "outbound": 1, + "inbound": 0, + "blocks": 322, + "daa": 322, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 281.9, + "outbound": 1, + "inbound": 0, + "blocks": 331, + "daa": 331, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 286.9, + "outbound": 1, + "inbound": 0, + "blocks": 341, + "daa": 341, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 291.9, + "outbound": 1, + "inbound": 0, + "blocks": 349, + "daa": 349, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 296.9, + "outbound": 1, + "inbound": 0, + "blocks": 357, + "daa": 357, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 301.9, + "outbound": 1, + "inbound": 0, + "blocks": 364, + "daa": 364, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 306.9, + "outbound": 1, + "inbound": 0, + "blocks": 369, + "daa": 369, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 311.9, + "outbound": 1, + "inbound": 0, + "blocks": 372, + "daa": 372, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 317, + "outbound": 1, + "inbound": 0, + "blocks": 374, + "daa": 374, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 322, + "outbound": 1, + "inbound": 0, + "blocks": 377, + "daa": 377, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 327, + "outbound": 1, + "inbound": 0, + "blocks": 384, + "daa": 384, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 332, + "outbound": 1, + "inbound": 0, + "blocks": 393, + "daa": 393, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 337, + "outbound": 1, + "inbound": 0, + "blocks": 396, + "daa": 396, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 342, + "outbound": 1, + "inbound": 0, + "blocks": 397, + "daa": 397, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 347, + "outbound": 1, + "inbound": 0, + "blocks": 402, + "daa": 402, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 352, + "outbound": 1, + "inbound": 0, + "blocks": 405, + "daa": 405, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 357.1, + "outbound": 1, + "inbound": 0, + "blocks": 413, + "daa": 413, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 362.1, + "outbound": 1, + "inbound": 0, + "blocks": 422, + "daa": 422, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 367.1, + "outbound": 1, + "inbound": 0, + "blocks": 428, + "daa": 428, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 372.1, + "outbound": 1, + "inbound": 0, + "blocks": 433, + "daa": 433, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 377.1, + "outbound": 1, + "inbound": 0, + "blocks": 440, + "daa": 440, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 382.1, + "outbound": 1, + "inbound": 0, + "blocks": 448, + "daa": 448, + "drawn": 0, + "connected_from_directory": 0 + } + ], + "node": "/srv/builds/igneum-wt-peer-directory/vendor/igneum-node-pd/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-peer-directory/vendor/igneum-node-pd/target/release/igneum-miner", + "slot": 0, + "ports": { + "base": 31090, + "suffix": 975 + } +} \ No newline at end of file diff --git a/docs/plans/mission-item-12-gate/peer-directory-switch-on-expect-eight.json b/docs/plans/mission-item-12-gate/peer-directory-switch-on-expect-eight.json new file mode 100644 index 00000000..1579a4f7 --- /dev/null +++ b/docs/plans/mission-item-12-gate/peer-directory-switch-on-expect-eight.json @@ -0,0 +1,366 @@ +{ + "pass": true, + "expect": "eight", + "case": "switch-on-expect-eight", + "switch": "on", + "listing": 10, + "joint": 200, + "watch": 180, + "node0": { + "blocks": 233, + "daa": 233 + }, + "listing_lines_on_node_0": 10, + "eight_outbound_at_s": 231.7, + "last": { + "t": 382.1, + "outbound": 10, + "inbound": 0, + "blocks": 414, + "daa": 414, + "drawn": 1, + "connected_from_directory": 9 + }, + "checks": { + "listing_lines_on_node_0": true, + "fresh_synced": true, + "fresh_reached_eight_outbound": true, + "fresh_connected_from_directory": true, + "fresh_held_one_outbound": false, + "no_directory_line_on_fresh": false + }, + "failed_checks": [], + "samples": [ + { + "t": 206.7, + "outbound": 1, + "inbound": 0, + "blocks": 242, + "daa": 242, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 211.7, + "outbound": 1, + "inbound": 0, + "blocks": 246, + "daa": 246, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 216.7, + "outbound": 1, + "inbound": 0, + "blocks": 253, + "daa": 253, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 221.7, + "outbound": 1, + "inbound": 0, + "blocks": 256, + "daa": 256, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 226.7, + "outbound": 1, + "inbound": 0, + "blocks": 260, + "daa": 260, + "drawn": 0, + "connected_from_directory": 0 + }, + { + "t": 231.7, + "outbound": 10, + "inbound": 0, + "blocks": 262, + "daa": 262, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 236.7, + "outbound": 10, + "inbound": 0, + "blocks": 269, + "daa": 269, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 241.7, + "outbound": 10, + "inbound": 0, + "blocks": 277, + "daa": 277, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 246.8, + "outbound": 10, + "inbound": 0, + "blocks": 280, + "daa": 280, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 251.8, + "outbound": 10, + "inbound": 0, + "blocks": 283, + "daa": 283, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 256.8, + "outbound": 10, + "inbound": 0, + "blocks": 286, + "daa": 286, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 261.8, + "outbound": 10, + "inbound": 0, + "blocks": 290, + "daa": 290, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 266.8, + "outbound": 10, + "inbound": 0, + "blocks": 298, + "daa": 298, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 271.8, + "outbound": 10, + "inbound": 0, + "blocks": 303, + "daa": 303, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 276.8, + "outbound": 10, + "inbound": 0, + "blocks": 311, + "daa": 311, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 281.8, + "outbound": 10, + "inbound": 0, + "blocks": 316, + "daa": 316, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 286.9, + "outbound": 10, + "inbound": 0, + "blocks": 317, + "daa": 317, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 291.9, + "outbound": 10, + "inbound": 0, + "blocks": 323, + "daa": 323, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 296.9, + "outbound": 10, + "inbound": 0, + "blocks": 334, + "daa": 334, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 301.9, + "outbound": 10, + "inbound": 0, + "blocks": 337, + "daa": 337, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 306.9, + "outbound": 10, + "inbound": 0, + "blocks": 342, + "daa": 342, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 311.9, + "outbound": 10, + "inbound": 0, + "blocks": 348, + "daa": 348, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 316.9, + "outbound": 10, + "inbound": 0, + "blocks": 350, + "daa": 350, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 322, + "outbound": 10, + "inbound": 0, + "blocks": 357, + "daa": 357, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 327, + "outbound": 10, + "inbound": 0, + "blocks": 359, + "daa": 359, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 332, + "outbound": 10, + "inbound": 0, + "blocks": 362, + "daa": 362, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 337, + "outbound": 10, + "inbound": 0, + "blocks": 364, + "daa": 364, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 342, + "outbound": 10, + "inbound": 0, + "blocks": 368, + "daa": 368, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 347, + "outbound": 10, + "inbound": 0, + "blocks": 380, + "daa": 380, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 352, + "outbound": 10, + "inbound": 0, + "blocks": 391, + "daa": 391, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 357.1, + "outbound": 10, + "inbound": 0, + "blocks": 393, + "daa": 393, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 362.1, + "outbound": 10, + "inbound": 0, + "blocks": 399, + "daa": 399, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 367.1, + "outbound": 10, + "inbound": 0, + "blocks": 401, + "daa": 401, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 372.1, + "outbound": 10, + "inbound": 0, + "blocks": 403, + "daa": 403, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 377.1, + "outbound": 10, + "inbound": 0, + "blocks": 409, + "daa": 409, + "drawn": 1, + "connected_from_directory": 9 + }, + { + "t": 382.1, + "outbound": 10, + "inbound": 0, + "blocks": 414, + "daa": 414, + "drawn": 1, + "connected_from_directory": 9 + } + ], + "node": "/srv/builds/igneum-wt-peer-directory/vendor/igneum-node-pd/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-peer-directory/vendor/igneum-node-pd/target/release/igneum-miner", + "slot": 2, + "ports": { + "base": 31490, + "suffix": 977 + } +} \ No newline at end of file diff --git a/docs/plans/mission-item-12-peer-directory.md b/docs/plans/mission-item-12-peer-directory.md new file mode 100644 index 00000000..52048a8e --- /dev/null +++ b/docs/plans/mission-item-12-peer-directory.md @@ -0,0 +1,112 @@ +# Mission item 12: the weight-backed peer directory, prototype (status log) + +Lane: horizon (mission items 4 and 12), 7 October 2026, after item 4's gate line. Branches: `peer-directory` (this repo, on +master) and `peer-directory-node` (the fork, on release-0.3.20-node dc141409; targets 0.3.21). Times UK (BST) unless marked Z. + +The item (mission.md 2.12, invent.md 7.1): a coinbase section where a key above dust may publish its node's address; a fresh +node dials from that list weighted by 30-day weight, beside the DNS seeds. Gate: a fresh node with genesis peers only reaches 8 +outbound from the directory; a 34 percent attacker eclipses under 0.1 percent of 1,000 fresh starts (simulation is fine); the NAT +fraction measured on the fleet (owed to the fleet lane, asked 7 October 13:0x UK; nothing rented). Dropped if the NAT fraction +makes the list useless: this lane reports, it does not decide. + +## 1. What exists to build on (read before writing) + +| Where | What | Used how | +|---|---|---| +| fork `consensus/core/src/finality.rs` `FinalityItem` (tags 1 vote, 2 certificate, 3 evidence, 4 leave), `encode_section` / `decode_section` (`items || len || "IGNF"` at the end of the coinbase payload), `Leave` (W7: `daa || pubkey || signature`, signed by the vote key, carried LAST so a decoder from before its tag stops at it) | the section codec and the item shape to copy | the address item is tag 5 with the same carriage rule: last, after leaves, and only once its switch is on | +| fork `consensus/src/processes/finality.rs` `ingest_leave` (block-carried, dated by the lowest carrier), `template_candidates` / `section_from` (what a template carries), `leave_active` (switch by DAA), `FinalityState.leaves` (persisted) | the ingest, the carriage and the switch pattern | the directory is a map key hash to (address, carrier DAA), persisted in the state the same way | +| fork `components/connectionmanager/src/lib.rs` `handle_outbound_connections` | dials from the address manager's prioritised random iterator, then the DNS seeders when connections are still missing | the directory draw goes between the two: addresses drawn by weight from the directory are fed to the address manager and dialled before the seeders are asked | +| fork `components/addressmanager/src/lib.rs` `add_address`, `iterate_prioritized_random_addresses` (weighted by failure count and prefix bucket) | the store a dialled address lives in | directory addresses enter it like seeder answers; the weight decides which enter, the store's own rule decides the order | +| fork `consensus/core/src/config/params.rs` `consensus_digest` (a switch at never is outside the digest; set, it is in) | the activation pattern every 0.3.16 switch follows | `peer_directory_activation_daa`, never on every network | + +## 2. Design, as built (prototype; fork branch peer-directory-node on release-0.3.20-node dc141409, commits 0cad5106 and db28d331 (tests); repo branch peer-directory on master 819d536b, commits 9a64d18c and 3e0dfa17 (gate), pushed to origin) + +| Item | Rule | +|---|---| +| Wire | `AddressAnnounce { daa, ip: [u8; 16], port, pubkey, signature }` (core `finality.rs`), 171 B, signed by the vote key the header names under `IGNEUM_ADDR_V1` over `"igneum-addr-v1/" || chain_id || 0 || daa || ip || port` | +| Carriage | in the MINER's extra data as `IGNP || hex(body)`, the key reveal's form (`IGNA` is already the EVM payout tag), never in the finality section: no switch for carriage, a node without the tag never meets it; `igneum-miner mine --announce ` puts one in every template of every identity (`announced`, dated at the sink's DAA score when the run began) | +| Reading | `FinalityManager::on_block_body` at or above `peer_directory_activation_daa`: the announcement must be by the block's own key, verify, and name a routable-in-form address; one node-local entry per key, the newest carrier wins (not persisted: a restarted node refills it from the blocks it sees; a prototype's gap) | +| Report | `ConsensusApi::peer_directory()` rows with each key's weight at the latest determined checkpoint (0 under dust); entries older than a weight window dropped on the way | +| Draw | `ConsensusApi::peer_directory_draw(n, exclude)`: without replacement, proportional to weight, keys under dust never drawn | +| Dialling | `ConnectionManager::handle_outbound_connections`: after the address store's own iterator and before the DNS seeders, when connections are still missing, 2 x missing addresses from the draw enter the address store and are dialled at once (`DirectoryDraw` closure wired in `protocol/flows/src/service.rs` through the consensus's blocking session) | +| Switch | `peer_directory_activation_daa`, never on every network (the four network constants), in the digest once set, in `OverrideParams` and the 60x file | +| Not done | the RPC that lists the directory (the harness reads `getConnectedPeerInfo` and the node log instead); persistence across restarts; Ember and the phone's use of the list (invent.md 7.1's third hour) | + +## 3. Gate plan + +| Gate | How | +|---|---| +| a fresh node with genesis peers only reaches 8 outbound from the directory | fast-time network of 10 listing nodes (each announcing its loopback address) plus one fresh node started with `--outpeers=8`, `--nodnsseed` and one `--addpeer` to a genesis peer that serves blocks only; the fresh node's `getConnectedPeerInfo` shows 8 outbound within 5 min, all from the directory | +| a 34 percent attacker eclipses under 0.1 percent of 1,000 fresh starts | `sim/peer-directory/eclipse.py`: the draw as implemented (weighted, without replacement, 8 peers) over a table where the attacker's keys hold 34 percent of the weight and list 34 percent of the addresses; 1,000 starts; expected 1.8e-4 at 8 peers (invent.md model E); also 16 peers and the honest-majority-of-peers reading | +| the NAT fraction | RECEIVED from the fleet lane (ac055d60427caab99) at 13:1x UK, read at 12:06Z from each standing live-devnet node's own log, nothing rented: reachable from outside 2 of 14 (hub-1, RunPod, 26611 mapped: 2,844 inbound peer connections against 86 outbound; pool-1, RunPod, mapped 4463: 1,692 against 99); not reachable 12 of 14 (every Vast box: 0 inbound peer connections each, 96 to 542 outbound, no `--externalip`, no mapped port). So 86 percent of the fleet's nodes sit behind NAT and hold their 4 to 5 peers by dialling out; the two reachable nodes carry every inbound connection. Caveat (theirs): a rented fleet overstates the NAT share for datacentre operators and understates it for home miners; a fair read for "a node started with the defaults". Left out: the four Devnet 2 pods and the Hetzner seed. The marker was "Connected to incoming peer" against "Connected to outgoing peer" (the RPC server's local accepts are not peers). | + +## 4. Runs + +### The eclipse simulation (`sim/peer-directory/eclipse.py`, box 2, nice 10, 13:5x to 14:0x UK) + +The draw as implemented (without replacement, proportional to weight at the latest checkpoint), 200 honest keys with Zipf +weights, the attacker at 34 percent of the weight split over `m` keys of equal weight, seed 7. + +| starts | peers | attacker keys | eclipsed | rate | model E a^n | attacker majority of the peers | +|---|---|---|---|---|---|---| +| 1,000 | 8 | 8 | 0 | 0 | 1.79e-4 | 4.0 percent | +| 1,000 | 8 | 64 | 1 | 1.0e-3 | 1.79e-4 | 9.8 percent | +| 1,000 | 8 | 1,000 | 0 | 0 | 1.79e-4 | 10.7 percent | +| 1,000 | 16 | 8, 64, 1,000 | 0, 0, 0 | 0 | 3.19e-8 | 0, 9.2, 9.2 percent | +| 100,000 | 8 | 8 | 0 | 0 | 1.79e-4 | 4.8 percent | +| 100,000 | 8 | 64 | 14 | 1.4e-4 | 1.79e-4 | 10.7 percent | +| 100,000 | 8 | 1,000 | 22 | 2.2e-4 | 1.79e-4 | 11.6 percent | + +The gate's line (under 0.1 percent of 1,000 fresh starts) is met at 100,000 starts: 1.4e-4 and 2.2e-4, where 1,000 starts +cannot resolve it (1 in 1,000 is exactly the line). Two readings beyond model E: with fewer attacker keys than peers an eclipse +is impossible under the draw without replacement (the dust threshold, 100 blocks a window on mainnet, prices each attacker +key at 100 blocks), and the attacker holds a MAJORITY of a fresh node's peers in about 11 percent of starts at 8 peers, which +is the number that matters for a relay-level attack rather than a full eclipse; 16 peers takes that to 9 percent and the +eclipse to zero in 1,000. + +### Unit tests (box 2) + +| Test | Result | +|---|---| +| core `address_announce_round_trips_and_verifies_under_its_key_only` | 1 of 1 | +| node `the_peer_directory_lists_a_blocks_own_key_at_its_newest_address_only_when_switched_on` (known-failed first: the switch at never lists nothing) | 1 of 1 | +| `cargo check -p kaspad -p igneum-miner --features kaspad/igneum-pow` on the branch | ok | + +### The fast-time gate (box 2, `tools/fast-time-remote.sh --box 2`, binary of peer-directory-node 0cad5106, 13:27 to 13:34 UK) + +`infra/fast-time/peer-directory.mjs`: ten listing nodes at one CPU thread each, every miner announcing its node's loopback +p2p address, every node advertising an unroutable external ip (10.255.0.0/16) so ordinary address gossip hands a fresh node +dead addresses only; after 200 s a fresh node starts with `--outpeers=8` and one `--addpeer` to node 0 and is watched 180 s. + +| Case | Must | Got | Numbers | +|---|---|---|---| +| switch off, expect one (the known-failed case) | PASS | PASS | node 0 logged 0 listings; the fresh node held 1 outbound (node 0) for the whole watch, 0 draw lines, synced 448 blocks | +| switch off, expect eight (the harness's own failed shape) | FAIL | FAIL | 1 outbound, 0 from the directory | +| switch on, expect eight (THE GATE LINE) | PASS | PASS | node 0 logged 10 listings; the fresh node reached 8 outbound at 231.7 s (about 30 s after it started), 9 connections from the directory in one draw, synced 414 blocks | + +Three harness faults on the way, each fixed: the log directory missing on the box (every case died at the redirect); the +peer count read `isOutbound` where the fork's `RpcPeerInfo` is `is_outbound`; and the wrapper's first run checking the +worktree root out on the box (fixed on horizon, 10140f9f, carried here). + +## 5. Verdict line for main + +The prototype does what invent.md 7.1 asked, on the numbers: a fresh node with one genesis peer and dead gossip reached 8 +outbound from the directory in about 30 s; the eclipse by a 34 percent attacker is 1.4e-4 to 2.2e-4 at 8 peers over 100,000 +starts (under the 0.1 percent line; 0 with 8 or fewer attacker keys, since the draw is without replacement), and the attacker +holds a majority of a fresh node's peers in about 11 percent of starts, which is the number to watch. The NAT reading (2 of 14 +standing nodes reachable, 86 percent behind NAT with no inbound path) makes the list a SEED SUPPLEMENT, not a replacement: +today it would list the two reachable fleet nodes beside the seeds, and a home miner's node (the 12-of-14 class unless the app +maps a port) is a reader of the list, never a listing. Per tier: a home miner's node gains weight-backed peers beside the seeds +at no cost and lists nothing by default; a rig or a pool node with a mapped port opts in with `--announce` and 171 bytes a block; +the phone and Ember verify mode are not wired (not done). Listed as useful or dropped is main's and the project lead's call; this lane's +reading is "keep as a seed supplement behind its switch", which costs 1.7 MB a day per node at 10,000 listing keys (approximate, +from the item size) and nothing while the switch is never. + +Open: an RPC that lists the directory; persistence across restarts; Ember and the phone; the testnet object and every network +file carry no `peer_directory` field (the switch stays never until a cut sets it). + +## 6. Rebase for 0.3.21 (14:0x UK, the shipper's order) + +peer-directory-node rebased onto release-0.3.20-node c4459193 in one round, no conflict: tip 2e32d5f6, on both box mirrors under its name. Suite on build-2 at 2e32d5f6: igneum-miner 19 of 19, connectionmanager 0 tests, consensus lib 116 of 117 (the ban flake only; cargo stopped before consensus-core's target). Digest on tools/fleet/override.json: 7bd98cc4..., the same as the pin's binary. Handed to the node lane a283f5f0d364ceef0. + +Digest on the file hub-1 runs (/root/fleet/override.json, sixteen fields, the copy at /tmp/igneum-devnet/override-v3-live.json on build-1): eada4bda8aa8368c2b2c3d17744bc7a70a0ff0e996dad681884d3ac5de1207eb, the shipper's string, read 14:1x UK from the branch binary on build-2; 7bd98cc4 was master's tools/fleet/override.json, another file. The live digest is unchanged by this branch. diff --git a/docs/plans/mission-item-4-fork-gate.md b/docs/plans/mission-item-4-fork-gate.md new file mode 100644 index 00000000..c8bf763a --- /dev/null +++ b/docs/plans/mission-item-4-fork-gate.md @@ -0,0 +1,142 @@ +# Mission item 4: weight-gated deep fork choice, the gate (status log) + +Lane: horizon (mission items 4 and 12), started 7 October 2026, 12:41 UK, on main's brief. Branches: `horizon` (this repo, on master +d1285cef) and `horizon-node` (the fork, on release-0.3.20-node dc141409, the 0.3.20 line; this work targets 0.3.21). Worktrees +`igneum-wt-horizon` and `igneum-wt-horizon/vendor/igneum-node-horizon`. Times are UK (BST) unless marked Z. + +The item (mission.md 2.4): a tip whose fork point is older than D (10 min of past-median time) is a fork-choice candidate only +if the keys that built it hold at least a third of the weight table at the fork point. Gate, fast time: a 51 percent fresh-key +fork from 15 min back is refused by every honest node; a one-third-weight fork is accepted; partition heal unchanged. Known-failed +cases first. + +## 1. What already existed (read before writing anything) + +| Where | What | State | +|---|---|---| +| fork `consensus/src/processes/finality.rs` `deep_fork_refusal`, asked by `sink_search_algorithm` for every popped candidate | the rule, behind `fork_gate_activation_daa` (never on every network; in the digest once set) with `fork_gate_window_daa` 600 s; the fork point is the highest chain ancestor of the candidate on the sink's chain; depth = the larger of sink minus fork and candidate minus fork; builders = the vote keys of every block of the candidate's chain since the fork (chain blocks and mergesets); the table = `voters_at(fork)`; refused under `3 x weight < total`; node-local memo per refused block | on the 0.3.20 line since 61b22057 (6 October), fixes 3301cf32 (depth along both chains) and aa0182aa (no extension shortcut) | +| fork unit tests | `without_the_fork_gate_a_minor_keys_deep_fork_wins` (known-failed), `the_fork_gate_refuses_a_deep_fork_under_a_third_and_passes_the_rest` (25 percent refused, 75 percent passes, inside the window passes) | green on that line | +| `infra/fast-time/fork-gate.mjs` on branch ca3-v4-node (never on master) | a TWO-node harness: A at 75 percent, B at 25 percent, A IDLE through the split; cases gate-on hold (PASS 23:45Z 6 Oct), gate-off reorg (PASS), gate-off hold (FAIL as it must); run on the Mac; a `pkill -f` on the devnet suffix | the record in `docs/plans/counter-asic-3-node.md` 7.5 | +| the live devnet and Devnet 2 override files, the testnet object | no `fork_gate` field anywhere: the switch is never on every network | unchanged by this lane | + +What the mission gate asks beyond that record: a FRESH key (0 of the table, not 25 percent), the honest side MINING through the +split (the record idled it), EVERY honest node (two, not one), the one-third case accepted, and the partition heal shown unchanged +with the gate on and off. Nothing in the rule needed to change for any of these; this lane adds the proof. + +## 2. What this lane added + +| Piece | Where | What | +|---|---|---| +| Fresh-key unit test | fork `a_fresh_keys_deep_fork_wins_only_with_the_gate_off` | known-failed first: at never a key with no block in the table wins by blue work; at 0 it is refused with weight 0 of the table | +| One-third line unit test | fork `the_gate_passes_at_one_third_of_the_table_and_refuses_under_it` | eight (honest mix, fork height) pairs; each outcome equals `3 x weight >= total` read from the table the gate reads; both sides seen | +| Three-node harness | `infra/fast-time/fork-gate.mjs` (new on master's line) | H1 and H2 honest and mining through every phase, B the third node; modes attack (B fresh, 3 of 5 threads), third (B at about half of the table), partition (H1 against H2); a reorg is read from the chain (`getVirtualChainFromBlock` of the pre-cut tip lists removed blocks), never from a key; blue work compared as BigInt; leftovers stopped by pid file | +| The six-case runner | `infra/fast-time/fork-gate-gate.mjs` | known-failed cases first, then the gate line, the one-third case, the two partition heals; GREEN only when every case gives the verdict it must and the two heals agree | +| Box wrapper | `tools/fast-time-remote.sh` (whole-body block; listed in `tools/ci/whole-body-check.sh`) | runs a harness on a box under a slot with a holder line and a JSONL row, the node binaries from a fork worktree's target on the box, results fetched back | + +## 2a. The hole the known-failed cases found (13:1x to 13:3x UK) + +The one-third unit test failed on box 2 at its second pair: B on every fourth block, fork at height 50, B holding 12 of 49 at +the fork, and the private tip WON. A probe test (temporary, since removed) read the gate's own answer at fork heights 40, 45, +48, 50, 55, 60 and 65: refused at 40, 48 and 60; let through at 45, 50 and 55 (65 is inside the window, a legitimate pass). +The let-through rows read "keys 2, signed 44 of 44": the honest key A was in the attacker's builders. The pattern is the fork +block's own key: heights that are multiples of 4 sit on B's blocks and were refused; the others sit on A's blocks and passed. + +Cause: `collect_builders` took each chain block's mergeset (blues and reds) and GHOSTDAG's `mergeset_blues[0]` is the block's +selected parent, so the first private block above the fork carried the FORK block into the builders, and the fork block was +A's. A 25 percent key forking right after a 75 percent key's block walked through the gate with A's weight on its side. The +same reading let a private chain that merges honest blocks as side parents inherit every merged key. The 6 October harness +PASS (23:45Z) was luck: its pre-cut sink was B-built, so the leaked key was B's own. + +Fix (fork, `collect_builders(block, sink, keys)`): a builder is the key of a block the sink does NOT have (not a DAG ancestor +of the sink, the sink itself included). The fork block is the sink's; honest blocks the attacker merged are the sink's; a +partition side's own blocks are not, so a heal is unchanged. New unit test, known-failed shape first: +`a_deep_fork_counts_only_the_blocks_the_sink_lacks_as_builders` (B from A's block at 45 refused; a private chain merging +honest blocks 46 to 80 wins at never and is refused at 0). + +Also seen: `ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list` died with `UnexpectedDifficulty` in the +full crate run (box 2 under load 65) and passed alone (1 of 1, 13:1x UK); not this lane's change, noted for the suite count. + +## 3. Runs + +### Commits + +| Repo | Branch | Commit | What | +|---|---|---|---| +| fork | horizon-node (on release-0.3.20-node dc141409) | eb32d2e0 | the builders fix (`collect_builders` skips every block the sink has) and the fork-gate tests on the two-instance lab | +| fork | horizon-node | a6a71ac2 | the lab inserts into the judge first and rebuilds a block refused on `UnexpectedDifficulty` (the suite's flake class) | +| repo | horizon (on master d1285cef) | 0dc2adff | the three-node harness, the six-case runner, the box wrapper, the whole-body check row | + +### Suites (box 2, igneum-build-2, nice 10 on 32 cores) + +| Run (UK) | Command | Result | +|---|---|---| +| 12:5x | `-- test --release -p kaspa-consensus` (the first test version, no fix) | 111 of 113: my one-third test FAIL (the hole), `ban_is_decided_by_the_carrying_block...` FAIL on `UnexpectedDifficulty` (load 65; passes alone 13:1x, 1 of 1) | +| 13:2x | `-- test --release -p kaspa-consensus --lib processes::finality::tests` (the fix, the lab) | 24 of 24 | +| 13:3x | `-- test --release -p kaspa-consensus` (eb32d2e0 content) | 112 of 114: two lab tests FAIL on `UnexpectedDifficulty` (the same flake class, now reachable by the lab's second instance) | +| 13:3x | `-- test --release -p kaspa-consensus` at a6a71ac2, 0dcaf4c5, ca7acb99 (the lab's rebuild, a pause between rebuilds, salted hashes) | 111 or 112 of 114 each: the two labs whose instances share one config still FAIL at block 61 under load; the probes showed `UnexpectedDifficulty` thirty times over 7.5 s, so neither clock nor hash memo | +| 13:38 | `-- test --release -p kaspa-consensus` at 6eb21fc9 (the lab on `DifficultyRule::KaspaSampled`, DAG-only bits) | 113 of 114 in the lib target, 3 ignored; the one FAIL is the pre-existing `ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list` (the same class: the dual rule's template bits and header stamp disagree at block 61, the first retarget, under load; passes alone). The lib target failing stops cargo before the integration targets. | + +Fork commits after eb32d2e0, test-only: a6a71ac2, 0dcaf4c5, ca7acb99, f225ed9f, 6eb21fc9 (the lab inserts into the judge first and rebuilds on the flake; a pause between rebuilds; every lab its own hash words; the DAG-only difficulty rule; the import). The binary content of kaspad and igneum-miner is the same from eb32d2e0 on; the gate binary carries 6eb21fc9. + +### Build (box 1, igneum-build-1) + +| Run (UK) | Command | Result | +|---|---|---| +| (pending) | `tools/build-remote.sh --no-fetch -- build --release -p kaspad -p igneum-miner --features kaspad/igneum-pow` from the fork worktree at a6a71ac2 (igneum-pow at 8c728ca3 through an untracked paths override to `igneum-pow-amend`, the 0.3.20 pairing); two earlier submissions of the uncommitted tree were stopped by pid so the gate binary carries the commit | | + +### Tree checks (the Mac, checks only) + +`tools/ci/pre-push.sh --ci` on horizon 0dc2adff: GREEN, 43 checks in 31 s (13:3x UK). + +### The gate (box 2, igneum-build-2, by main's word at 13:4x UK: box 1's slots stay with the 0.3.20 pin) + +Binary: `igneumd` and `igneum-miner` of horizon-node 6eb21fc9 (igneum-pow 8c728ca3), built on box 2 at 13:5x UK +(`tools/build-remote.sh --box 2`, 113 s); run through `tools/fast-time-remote.sh --box 2` (one slot, the bounded class, 583 s +for the six cases side by side), case summaries and logs in `docs/plans/mission-item-4-gate/`. Window 60 DAA, joint 240 s, +split 180 s, watch 150 s; honest nodes H1 and H2 at one CPU thread each through every phase; the attacker at 3 threads in +the split (60 percent of the CPU hash: the refusal reads weight, not how much heavier the chain is). + +| Case | Must | Got | Side 2 at the fork | Fork depth (DAA) | Blue work at the heal, side 2 against H1 | Honest nodes after the heal | +|---|---|---|---|---|---|---| +| attack, gate off, expect reorg (the rule's known-failed case) | PASS | PASS | 0 bps (fresh key) | 191 | 17,470,131 against 14,893,198 | H1 and H2 reorged at 510 s, 0 refusal lines | +| attack, gate off, expect hold (the harness's own failed shape) | FAIL | FAIL | 0 bps | 179 | 19,683,187 against 17,459,678 | H1 and H2 reorged at 480 s, 0 refusal lines | +| attack, gate on, expect hold (THE GATE LINE) | PASS | PASS | 0 bps | 197 | 20,297,242 against 14,807,915 | H1 and H2 HELD for the whole watch, 177 refusal lines each, both know side 2's tip; side 2 kept its chain | +| third, gate on, expect reorg (a one-third-weight fork accepted) | PASS | PASS | 6,000 bps | 166 | 28,969,222 against 24,628,833 | H1 and H2 reorged at 477 s, 0 refusal lines | +| partition, gate on, expect reorg | PASS | PASS | 3,719 bps | 194 | 18,089,683 against 11,490,863 | H1 reorged at 507 s, 0 refusal lines; H2 kept its chain | +| partition, gate off, expect reorg (the same outcome) | PASS | PASS | 5,583 bps | 191 | 19,576,159 against 12,270,631 | H1 reorged at 507 s, 0 refusal lines; H2 kept its chain | + +GATE GREEN, 13:58 UK: 6 of 6 cases gave the verdict they must; the partition heal is the same with the gate on and off +(both reorg H1 onto the heavier side, 0 refusals). Reading "15 min back" at fast time: the devnet window is 600 s and the +mission's 15 min is one and a half windows; the harness keeps the window at 60 DAA and the split at 180 s, three windows +deep, so the refusal was asked from 61 s of the split on and held for its whole second half. + +## 4. Consequences per tier + +One sentence: with the fix, a renter's or a chain-splitter's deep reorg is bounded by weight for every tier alike, and an +honest key's own blocks are never refused. + +| Tier | What the number means | +|---|---| +| Home miner (one card, any size, Windows, Linux or macOS, any vendor) | its node refuses the same tips a rig's or a pool's node refuses; a fresh-key chain from more than ten minutes back never becomes its sink while the key that built it holds under a third of the window; nothing to configure, nothing to pay; the memo costs one mergeset per refused block | +| Rig | the same; a rig's own blocks after a connectivity gap are built by its own keys and pass on share | +| Pool user | the pool's node holds the chain the pool mined; a renter cannot reorganise the pool's payouts past ten minutes without a third of the weight | +| Exchange and holder | a 12-hour double spend during a pause or in the first month (51-percent.md section 5 rank 2, USD 146 at 1 GH/s) is gone: the deep fork is refused at every honest node, lock or no lock | +| The rule's cost | none for certificates; a partition side under a third cannot reorg the other past the window (the intended outcome, unchanged by the fix) | + +Before the fix the bound held only when the fork sat on a block of a small key; a renter forking right after a large +miner's block, or merging honest blocks into its chain, walked through on every tier. + +## 5. Open + +| Item | Owner | +|---|---| +| Merge: horizon-node is on release-0.3.20-node dc141409; main's word is to rebase onto the 0.3.20 pin once named (c4459193 the candidate) for 0.3.21; never a push to a release branch | this lane, when main names the pin | +| The difficulty red: `ban_is_decided_by_the_carrying_block...` and, before the lab moved to the DAG-only rule, two lab tests, on `UnexpectedDifficulty` at block 61 (the first retarget) under the full suite's load; the dual rule's template bits come from a virtual resolved at one instant and the header is stamped at a later one | the node lane for 0.3.21 (main's word: logged, not fixed here) | +| The fork's test block builder asks the gate (it runs the sink search from the parents it is given): any future test that builds a private chain on a gated instance builds it on the fork block instead; the lab's two-instance shape is the pattern | the node lane; a note in `consensus/src/consensus/test_consensus.rs` is owed | +| `tools/box` named in the brief does not exist; the box tooling is `tools/build-remote.sh` on `infra/build-server/lib.sh`, which `tools/fast-time-remote.sh` uses; the wrapper's first run checked the worktree root out on box 2 and took the fork sources with it (fixed the same hour: overlay only, 10140f9f) | main's reading | +| The devnet, Devnet 2 and the testnet object carry no `fork_gate` field: the switch stays never everywhere until a cut sets it (in the digest once set) | the shipper and the project lead | + +## 6. Rebase for 0.3.21 (14:0x UK, the shipper's order) + +horizon-node rebased onto release-0.3.20-node c4459193 (the 0.3.20 pin) in one round, no conflict: tip 437f0438, on both box mirrors under its name. Suite on build-2 at 437f0438: `-p kaspa-consensus` lib 117 of 119, 3 ignored (the ban difficulty flake and `a_chain_that_misses_an_adopted_lock_never_locks_here`, which passes alone 1 of 1 and passed in every earlier full run; load 113). Digest on tools/fleet/override.json (origin/master): 7bd98cc4..., the same as the pin's own binary on that file. Handed to the node lane a283f5f0d364ceef0 for the 0.3.21 merge after 55768f88, miner-reliability-20 and pool-finish-node. + +Digest on the file hub-1 runs (/root/fleet/override.json, sixteen fields, the copy at /tmp/igneum-devnet/override-v3-live.json on build-1): eada4bda8aa8368c2b2c3d17744bc7a70a0ff0e996dad681884d3ac5de1207eb, the shipper's string, read 14:1x UK from the branch binary on build-2; 7bd98cc4 was master's tools/fleet/override.json, another file. The live digest is unchanged by this branch. diff --git a/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.json b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.json new file mode 100644 index 00000000..b7604565 --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.json @@ -0,0 +1,933 @@ +{ + "pass": false, + "expect": "hold", + "case": "attack-gate-off-expect-hold", + "mode": "attack", + "gate": "off", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 0 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 0, + "others": 120, + "side2_bps": 0 + }, + "fork_daa": 247, + "fork_depth_daa_at_heal": 179, + "sinks": { + "joint": { + "h1": { + "hash": "0535d8ae67287238ee528bae5ab1f366273bd1c65c6a94342ec3879a40b81c88", + "blocks": 248, + "daa": 247, + "blue": 248, + "blueWork": "11209205", + "key": "8da9ddee…" + }, + "h2": { + "hash": "0535d8ae67287238ee528bae5ab1f366273bd1c65c6a94342ec3879a40b81c88", + "blocks": 248, + "daa": 247, + "blue": 248, + "blueWork": "11209205", + "key": "8da9ddee…" + }, + "side2": { + "hash": "0535d8ae67287238ee528bae5ab1f366273bd1c65c6a94342ec3879a40b81c88", + "blocks": 248, + "daa": 247, + "blue": 248, + "blueWork": "11209205", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "d5347d2cd3468901fda8e5a1caffe0be55d45eb12739577fadb0141d2291c2ba", + "blocks": 412, + "daa": 411, + "blue": 412, + "blueWork": "17459678", + "key": "8da9ddee…" + }, + "h2": { + "hash": "d5347d2cd3468901fda8e5a1caffe0be55d45eb12739577fadb0141d2291c2ba", + "blocks": 412, + "daa": 411, + "blue": 412, + "blueWork": "17459678", + "key": "8da9ddee…" + }, + "side2": { + "hash": "bfdb75e384417228a85f4098f8f2bb65d40c271ce674bea2d1cc8a3c6c335f53", + "blocks": 427, + "daa": 426, + "blue": 427, + "blueWork": "19683187", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 480.3, + "knows_side2_tip": true, + "refusal_lines": 0 + }, + "h2": { + "held": false, + "reorged": true, + "reorg_at_s": 480.3, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": true, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [ + "every_honest_node_held", + "every_honest_node_logged_a_refusal" + ], + "refusal_example": null, + "samples": [ + { + "t": 425.2, + "h1": { + "blocks": 416, + "sink": "7b85c0879ec1a3f0", + "daa": 414, + "blue": 415, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 416, + "sink": "7b85c0879ec1a3f0", + "daa": 414, + "blue": 415, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 435, + "sink": "8bb7e69cea95ecaa", + "blue": 435, + "reorged": false + } + }, + { + "t": 430.2, + "h1": { + "blocks": 423, + "sink": "44ee221996bf6519", + "daa": 422, + "blue": 423, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 423, + "sink": "44ee221996bf6519", + "daa": 422, + "blue": 423, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 441, + "sink": "46ee56ca78abcfa4", + "blue": 441, + "reorged": false + } + }, + { + "t": 435.2, + "h1": { + "blocks": 430, + "sink": "fe81d0b598b34760", + "daa": 429, + "blue": 430, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 430, + "sink": "fe81d0b598b34760", + "daa": 429, + "blue": 430, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 445, + "sink": "bf71c714df908384", + "blue": 445, + "reorged": false + } + }, + { + "t": 440.2, + "h1": { + "blocks": 440, + "sink": "acab21ca95900afc", + "daa": 439, + "blue": 440, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 440, + "sink": "acab21ca95900afc", + "daa": 439, + "blue": 440, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 448, + "sink": "b8fccb90e479e8a5", + "blue": 448, + "reorged": false + } + }, + { + "t": 445.3, + "h1": { + "blocks": 443, + "sink": "d9051d6139ae8afa", + "daa": 442, + "blue": 443, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 443, + "sink": "d9051d6139ae8afa", + "daa": 442, + "blue": 443, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 456, + "sink": "2cc48c7a2084d5e4", + "blue": 456, + "reorged": false + } + }, + { + "t": 450.3, + "h1": { + "blocks": 450, + "sink": "cea4dc9c673bd13a", + "daa": 449, + "blue": 450, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 450, + "sink": "cea4dc9c673bd13a", + "daa": 449, + "blue": 450, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 466, + "sink": "4f46263c45d1d32a", + "blue": 466, + "reorged": false + } + }, + { + "t": 455.3, + "h1": { + "blocks": 452, + "sink": "1a8679962a368c21", + "daa": 451, + "blue": 452, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 452, + "sink": "1a8679962a368c21", + "daa": 451, + "blue": 452, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 472, + "sink": "12dcc825edc2fa17", + "blue": 472, + "reorged": false + } + }, + { + "t": 460.3, + "h1": { + "blocks": 454, + "sink": "2a7c0240cfe56042", + "daa": 453, + "blue": 454, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 454, + "sink": "2a7c0240cfe56042", + "daa": 453, + "blue": 454, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 480, + "sink": "bbb6cf12cfd7419f", + "blue": 480, + "reorged": false + } + }, + { + "t": 465.3, + "h1": { + "blocks": 454, + "sink": "2a7c0240cfe56042", + "daa": 453, + "blue": 454, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 454, + "sink": "2a7c0240cfe56042", + "daa": 453, + "blue": 454, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 488, + "sink": "f443140c40db1ff4", + "blue": 488, + "reorged": false + } + }, + { + "t": 470.3, + "h1": { + "blocks": 456, + "sink": "2c2bf05b3992cb6b", + "daa": 455, + "blue": 456, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 456, + "sink": "2c2bf05b3992cb6b", + "daa": 455, + "blue": 456, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 493, + "sink": "0dd0e90fa5bb4330", + "blue": 493, + "reorged": false + } + }, + { + "t": 475.3, + "h1": { + "blocks": 458, + "sink": "cde3915508aeb008", + "daa": 457, + "blue": 458, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 458, + "sink": "cde3915508aeb008", + "daa": 457, + "blue": 458, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 496, + "sink": "7adc2714fa7a10c9", + "blue": 496, + "reorged": false + } + }, + { + "t": 480.3, + "h1": { + "blocks": 505, + "sink": "f08f99c6711510d7", + "daa": 504, + "blue": 505, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 505, + "sink": "f08f99c6711510d7", + "daa": 504, + "blue": 505, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 505, + "sink": "f08f99c6711510d7", + "blue": 505, + "reorged": false + } + }, + { + "t": 485.3, + "h1": { + "blocks": 509, + "sink": "9dfb826d38e1f6a4", + "daa": 508, + "blue": 509, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 509, + "sink": "9dfb826d38e1f6a4", + "daa": 508, + "blue": 509, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 509, + "sink": "9dfb826d38e1f6a4", + "blue": 509, + "reorged": false + } + }, + { + "t": 490.4, + "h1": { + "blocks": 511, + "sink": "a9bdeeb2148190f1", + "daa": 510, + "blue": 511, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 511, + "sink": "a9bdeeb2148190f1", + "daa": 510, + "blue": 511, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 511, + "sink": "a9bdeeb2148190f1", + "blue": 511, + "reorged": false + } + }, + { + "t": 495.4, + "h1": { + "blocks": 522, + "sink": "fa5aefefc31e1c4c", + "daa": 521, + "blue": 522, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 522, + "sink": "fa5aefefc31e1c4c", + "daa": 521, + "blue": 522, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 522, + "sink": "fa5aefefc31e1c4c", + "blue": 522, + "reorged": false + } + }, + { + "t": 500.4, + "h1": { + "blocks": 525, + "sink": "3f659b8355cf6fb8", + "daa": 524, + "blue": 525, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 525, + "sink": "3f659b8355cf6fb8", + "daa": 524, + "blue": 525, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 525, + "sink": "3f659b8355cf6fb8", + "blue": 525, + "reorged": false + } + }, + { + "t": 505.4, + "h1": { + "blocks": 528, + "sink": "2b00a2431aecf64d", + "daa": 527, + "blue": 528, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 528, + "sink": "2b00a2431aecf64d", + "daa": 527, + "blue": 528, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 528, + "sink": "2b00a2431aecf64d", + "blue": 528, + "reorged": false + } + }, + { + "t": 510.4, + "h1": { + "blocks": 534, + "sink": "f10f202f1b8adf79", + "daa": 533, + "blue": 534, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 534, + "sink": "f10f202f1b8adf79", + "daa": 533, + "blue": 534, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 534, + "sink": "f10f202f1b8adf79", + "blue": 534, + "reorged": false + } + }, + { + "t": 515.4, + "h1": { + "blocks": 541, + "sink": "d70cd34944d6d565", + "daa": 540, + "blue": 541, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 541, + "sink": "d70cd34944d6d565", + "daa": 540, + "blue": 541, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 541, + "sink": "d70cd34944d6d565", + "blue": 541, + "reorged": false + } + }, + { + "t": 520.4, + "h1": { + "blocks": 546, + "sink": "35d62b928d603bac", + "daa": 545, + "blue": 546, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 546, + "sink": "35d62b928d603bac", + "daa": 545, + "blue": 546, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 546, + "sink": "35d62b928d603bac", + "blue": 546, + "reorged": false + } + }, + { + "t": 525.4, + "h1": { + "blocks": 552, + "sink": "11ee723145434436", + "daa": 551, + "blue": 552, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 552, + "sink": "11ee723145434436", + "daa": 551, + "blue": 552, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 552, + "sink": "11ee723145434436", + "blue": 552, + "reorged": false + } + }, + { + "t": 530.4, + "h1": { + "blocks": 561, + "sink": "096fe4e02ba023a4", + "daa": 560, + "blue": 561, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 561, + "sink": "096fe4e02ba023a4", + "daa": 560, + "blue": 561, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 561, + "sink": "096fe4e02ba023a4", + "blue": 561, + "reorged": false + } + }, + { + "t": 535.4, + "h1": { + "blocks": 566, + "sink": "58b6d24c4920da55", + "daa": 565, + "blue": 566, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 566, + "sink": "58b6d24c4920da55", + "daa": 565, + "blue": 566, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 566, + "sink": "58b6d24c4920da55", + "blue": 566, + "reorged": false + } + }, + { + "t": 540.4, + "h1": { + "blocks": 567, + "sink": "3a757d2721963b97", + "daa": 566, + "blue": 567, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 567, + "sink": "3a757d2721963b97", + "daa": 566, + "blue": 567, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 567, + "sink": "3a757d2721963b97", + "blue": 567, + "reorged": false + } + }, + { + "t": 545.4, + "h1": { + "blocks": 572, + "sink": "40cb1b5ff6ffa6e2", + "daa": 571, + "blue": 572, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 572, + "sink": "40cb1b5ff6ffa6e2", + "daa": 571, + "blue": 572, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 572, + "sink": "40cb1b5ff6ffa6e2", + "blue": 572, + "reorged": false + } + }, + { + "t": 550.4, + "h1": { + "blocks": 577, + "sink": "e3f1416a5521d05a", + "daa": 576, + "blue": 577, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 577, + "sink": "e3f1416a5521d05a", + "daa": 576, + "blue": 577, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 577, + "sink": "e3f1416a5521d05a", + "blue": 577, + "reorged": false + } + }, + { + "t": 555.5, + "h1": { + "blocks": 584, + "sink": "38b6a8056ad74b9d", + "daa": 583, + "blue": 584, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 584, + "sink": "38b6a8056ad74b9d", + "daa": 583, + "blue": 584, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 584, + "sink": "38b6a8056ad74b9d", + "blue": 584, + "reorged": false + } + }, + { + "t": 560.5, + "h1": { + "blocks": 589, + "sink": "69c3e39a47332124", + "daa": 588, + "blue": 589, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 589, + "sink": "69c3e39a47332124", + "daa": 588, + "blue": 589, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 589, + "sink": "69c3e39a47332124", + "blue": 589, + "reorged": false + } + }, + { + "t": 565.5, + "h1": { + "blocks": 592, + "sink": "6fe943b09aa71ffa", + "daa": 591, + "blue": 592, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 592, + "sink": "6fe943b09aa71ffa", + "daa": 591, + "blue": 592, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 592, + "sink": "6fe943b09aa71ffa", + "blue": 592, + "reorged": false + } + }, + { + "t": 570.5, + "h1": { + "blocks": 595, + "sink": "b5217027de64f1a2", + "daa": 594, + "blue": 595, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 595, + "sink": "b5217027de64f1a2", + "daa": 594, + "blue": 595, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 595, + "sink": "b5217027de64f1a2", + "blue": 595, + "reorged": false + } + } + ], + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 1, + "ports": { + "base": 30730, + "suffix": 981 + } +} diff --git a/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.log b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.log new file mode 100644 index 00000000..4890bb9c --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.log @@ -0,0 +1,18 @@ +12:48:26.701 fg1 case attack-gate-off-expect-hold: mode attack, gate off (window 60 DAA), joint 240 s, split 180 s, watch 150 s, honest 1 thread(s) each, attacker 3 (joint 0), expect hold +12:48:28.281 fg1 h1 up pid 480222 json 30732 p2p 30731 +12:48:29.791 fg1 h2 up pid 481550 json 30742 p2p 30741 addpeer 30731 +12:48:31.307 fg1 b up pid 482808 json 30752 p2p 30751 addpeer 30761,30762 +12:52:34.325 fg1 phase 1 done at 240.0 s: H1 248 blocks sink 0535d8ae daa 247; H2 248 sink 0535d8ae; side 2 (b) 248 sink 0535d8ae; keys H1 8da9ddee H2 eda9cde4 side2 fresh (none yet) +12:52:34.384 fg1 weight at the fork (last 120 blue blocks of H1's chain): side 2 0, others 120, side 2 0 bps +12:52:34.387 fg1 links cut at 240.1 s; side 2 (b) now mines with 3 thread(s), the honest side with 1 each +12:55:34.491 fg1 phase 2 done at 420.2 s: H1 412 blocks sink d5347d2c daa 411 blue 412 work 17459678; side 2 427 sink bfdb75e3 daa 426 blue 427 work 19683187 (side 2 heavier: true); fork depth 179 DAA against window 60 +12:55:34.491 fg1 links restored at 420.2 s; watching H1 and H2 for 150 s +12:56:04.581 fg1 t=450.3 s H1 450 blocks sink cea4dc9c held; H2 450 blocks sink cea4dc9c held; side 2 466 blocks sink 4f46263c +12:56:34.656 fg1 H1 left its pre-cut chain at 480.3 s: sink f08f99c6711510d7 by 0e2c6fe2 +12:56:34.659 fg1 H2 left its pre-cut chain at 480.3 s: sink f08f99c6711510d7 by 0e2c6fe2 +12:56:34.661 fg1 t=480.3 s H1 505 blocks sink f08f99c6 REORGED; H2 505 blocks sink f08f99c6 REORGED; side 2 505 blocks sink f08f99c6 +12:57:04.702 fg1 t=510.4 s H1 534 blocks sink f10f202f REORGED; H2 534 blocks sink f10f202f REORGED; side 2 534 blocks sink f10f202f +12:57:34.751 fg1 t=540.4 s H1 567 blocks sink 3a757d27 REORGED; H2 567 blocks sink 3a757d27 REORGED; side 2 567 blocks sink 3a757d27 +12:58:04.813 fg1 t=570.5 s H1 595 blocks sink b5217027 REORGED; H2 595 blocks sink b5217027 REORGED; side 2 595 blocks sink b5217027 +12:58:04.825 fg1 SUMMARY FAIL (attack-gate-off-expect-hold): side 2 held 0 bps of the blue blocks at the fork; fork depth 179 DAA against window 60; side 2 blue work 19683187 against H1 17459678 at the heal; H1 reorged at 480.3 s (0 refusal lines, knows side 2's tip: true); H2 reorged at 480.3 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true; FAILED CHECK every_honest_node_held, every_honest_node_logged_a_refusal +12:58:04.825 fg1 summary: /srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.json diff --git a/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.json b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.json new file mode 100644 index 00000000..b45a58da --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.json @@ -0,0 +1,930 @@ +{ + "pass": true, + "expect": "reorg", + "case": "attack-gate-off-expect-reorg", + "mode": "attack", + "gate": "off", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 0 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 0, + "others": 120, + "side2_bps": 0 + }, + "fork_daa": 240, + "fork_depth_daa_at_heal": 191, + "sinks": { + "joint": { + "h1": { + "hash": "e66998c63f8f5d2f3f9108a5c61730f3d5ee06a0553f47e3bce314a0e4d7228e", + "blocks": 242, + "daa": 240, + "blue": 241, + "blueWork": "8689541", + "key": "8da9ddee…" + }, + "h2": { + "hash": "e66998c63f8f5d2f3f9108a5c61730f3d5ee06a0553f47e3bce314a0e4d7228e", + "blocks": 242, + "daa": 240, + "blue": 241, + "blueWork": "8689541", + "key": "8da9ddee…" + }, + "side2": { + "hash": "e66998c63f8f5d2f3f9108a5c61730f3d5ee06a0553f47e3bce314a0e4d7228e", + "blocks": 242, + "daa": 240, + "blue": 241, + "blueWork": "8689541", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "6e932c389f2ad01a39873317f9549f0a336e66a7c840669dd5bcb44a979a19ad", + "blocks": 421, + "daa": 420, + "blue": 421, + "blueWork": "14893198", + "key": "8da9ddee…" + }, + "h2": { + "hash": "6e932c389f2ad01a39873317f9549f0a336e66a7c840669dd5bcb44a979a19ad", + "blocks": 421, + "daa": 420, + "blue": 421, + "blueWork": "14893198", + "key": "8da9ddee…" + }, + "side2": { + "hash": "d93a1238a397f68337f4bc28d6197a61a32fbca176f3e7f4248b6b330e239cc8", + "blocks": 432, + "daa": 431, + "blue": 432, + "blueWork": "17470131", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 510.4, + "knows_side2_tip": true, + "refusal_lines": 0 + }, + "h2": { + "held": false, + "reorged": true, + "reorg_at_s": 510.4, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": true, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "samples": [ + { + "t": 425.2, + "h1": { + "blocks": 426, + "sink": "719c3c11c14e54ed", + "daa": 425, + "blue": 426, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 426, + "sink": "719c3c11c14e54ed", + "daa": 425, + "blue": 426, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 438, + "sink": "c704e731f479e045", + "blue": 438, + "reorged": false + } + }, + { + "t": 430.2, + "h1": { + "blocks": 432, + "sink": "fe308e06a3529e00", + "daa": 431, + "blue": 432, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 432, + "sink": "fe308e06a3529e00", + "daa": 431, + "blue": 432, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 442, + "sink": "7ca72d6ee8a28b46", + "blue": 442, + "reorged": false + } + }, + { + "t": 435.2, + "h1": { + "blocks": 436, + "sink": "ba7e8b5f41caf493", + "daa": 435, + "blue": 436, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 436, + "sink": "ba7e8b5f41caf493", + "daa": 435, + "blue": 436, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 446, + "sink": "5459e40a1e9137e0", + "blue": 446, + "reorged": false + } + }, + { + "t": 440.2, + "h1": { + "blocks": 438, + "sink": "19432a8a37b593ad", + "daa": 437, + "blue": 438, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 438, + "sink": "19432a8a37b593ad", + "daa": 437, + "blue": 438, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 455, + "sink": "5fdf67fc248f6500", + "blue": 455, + "reorged": false + } + }, + { + "t": 445.3, + "h1": { + "blocks": 446, + "sink": "aada7bf1e3d16b25", + "daa": 445, + "blue": 446, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 446, + "sink": "aada7bf1e3d16b25", + "daa": 445, + "blue": 446, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 466, + "sink": "85ccafa8a9d39de0", + "blue": 466, + "reorged": false + } + }, + { + "t": 450.3, + "h1": { + "blocks": 447, + "sink": "1761d6112c00d161", + "daa": 446, + "blue": 447, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 447, + "sink": "1761d6112c00d161", + "daa": 446, + "blue": 447, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 475, + "sink": "594fe7ff929c559f", + "blue": 475, + "reorged": false + } + }, + { + "t": 455.3, + "h1": { + "blocks": 455, + "sink": "3d694806975e096e", + "daa": 454, + "blue": 455, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 455, + "sink": "3d694806975e096e", + "daa": 454, + "blue": 455, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 480, + "sink": "bf92fbb2a472d205", + "blue": 480, + "reorged": false + } + }, + { + "t": 460.3, + "h1": { + "blocks": 461, + "sink": "4c2da8fcb362f14d", + "daa": 460, + "blue": 461, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 461, + "sink": "4c2da8fcb362f14d", + "daa": 460, + "blue": 461, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 482, + "sink": "90cc4fd0fac9bef2", + "blue": 482, + "reorged": false + } + }, + { + "t": 465.3, + "h1": { + "blocks": 467, + "sink": "4cd5d4fda0703837", + "daa": 466, + "blue": 467, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 467, + "sink": "4cd5d4fda0703837", + "daa": 466, + "blue": 467, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 484, + "sink": "8d822c253a2939d6", + "blue": 484, + "reorged": false + } + }, + { + "t": 470.3, + "h1": { + "blocks": 473, + "sink": "beeb70fa234a9a4b", + "daa": 472, + "blue": 473, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 473, + "sink": "beeb70fa234a9a4b", + "daa": 472, + "blue": 473, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 487, + "sink": "ed057653dec1d416", + "blue": 487, + "reorged": false + } + }, + { + "t": 475.3, + "h1": { + "blocks": 480, + "sink": "47c9ab35c01f2f7d", + "daa": 479, + "blue": 480, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 480, + "sink": "47c9ab35c01f2f7d", + "daa": 479, + "blue": 480, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 495, + "sink": "072c31cf3c13877b", + "blue": 495, + "reorged": false + } + }, + { + "t": 480.3, + "h1": { + "blocks": 486, + "sink": "918c05c7a79ce8ed", + "daa": 485, + "blue": 486, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 486, + "sink": "918c05c7a79ce8ed", + "daa": 485, + "blue": 486, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 504, + "sink": "6ab8526912a92786", + "blue": 504, + "reorged": false + } + }, + { + "t": 485.4, + "h1": { + "blocks": 491, + "sink": "5b94825a96af8031", + "daa": 490, + "blue": 491, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 491, + "sink": "5b94825a96af8031", + "daa": 490, + "blue": 491, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 511, + "sink": "e5d2d2cf5ca14138", + "blue": 511, + "reorged": false + } + }, + { + "t": 490.4, + "h1": { + "blocks": 494, + "sink": "7d0fd0b857ad553d", + "daa": 493, + "blue": 494, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 494, + "sink": "7d0fd0b857ad553d", + "daa": 493, + "blue": 494, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 518, + "sink": "6acadef70d9d2b7e", + "blue": 518, + "reorged": false + } + }, + { + "t": 495.4, + "h1": { + "blocks": 500, + "sink": "4e35f238846e9802", + "daa": 499, + "blue": 500, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 500, + "sink": "4e35f238846e9802", + "daa": 499, + "blue": 500, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 524, + "sink": "a0e5e0544388677b", + "blue": 524, + "reorged": false + } + }, + { + "t": 500.4, + "h1": { + "blocks": 502, + "sink": "1f3cf87f97e6661c", + "daa": 501, + "blue": 502, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 502, + "sink": "1f3cf87f97e6661c", + "daa": 501, + "blue": 502, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 530, + "sink": "f0ba9826edcf48e7", + "blue": 530, + "reorged": false + } + }, + { + "t": 505.4, + "h1": { + "blocks": 509, + "sink": "532a873c7ad783c5", + "daa": 508, + "blue": 509, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 509, + "sink": "532a873c7ad783c5", + "daa": 508, + "blue": 509, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 537, + "sink": "b138a9d8ba0b3454", + "blue": 537, + "reorged": false + } + }, + { + "t": 510.4, + "h1": { + "blocks": 545, + "sink": "b878077d471c2a73", + "daa": 544, + "blue": 545, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 545, + "sink": "b878077d471c2a73", + "daa": 544, + "blue": 545, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 545, + "sink": "b878077d471c2a73", + "blue": 545, + "reorged": false + } + }, + { + "t": 515.4, + "h1": { + "blocks": 556, + "sink": "95bd60b5bf755ef1", + "daa": 555, + "blue": 556, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 556, + "sink": "95bd60b5bf755ef1", + "daa": 555, + "blue": 556, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 556, + "sink": "95bd60b5bf755ef1", + "blue": 556, + "reorged": false + } + }, + { + "t": 520.4, + "h1": { + "blocks": 569, + "sink": "258f2c477b49756d", + "daa": 568, + "blue": 569, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 569, + "sink": "258f2c477b49756d", + "daa": 568, + "blue": 569, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 569, + "sink": "258f2c477b49756d", + "blue": 569, + "reorged": false + } + }, + { + "t": 525.4, + "h1": { + "blocks": 571, + "sink": "e8cc9969d5d1dc10", + "daa": 570, + "blue": 571, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 571, + "sink": "e8cc9969d5d1dc10", + "daa": 570, + "blue": 571, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 571, + "sink": "e8cc9969d5d1dc10", + "blue": 571, + "reorged": false + } + }, + { + "t": 530.5, + "h1": { + "blocks": 573, + "sink": "da3da53755578a2d", + "daa": 572, + "blue": 573, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 573, + "sink": "da3da53755578a2d", + "daa": 572, + "blue": 573, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 573, + "sink": "da3da53755578a2d", + "blue": 573, + "reorged": false + } + }, + { + "t": 535.5, + "h1": { + "blocks": 576, + "sink": "65ba87e325c66754", + "daa": 575, + "blue": 576, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 576, + "sink": "65ba87e325c66754", + "daa": 575, + "blue": 576, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 576, + "sink": "65ba87e325c66754", + "blue": 576, + "reorged": false + } + }, + { + "t": 540.5, + "h1": { + "blocks": 580, + "sink": "11e564345e74f2cb", + "daa": 579, + "blue": 580, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 580, + "sink": "11e564345e74f2cb", + "daa": 579, + "blue": 580, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 580, + "sink": "11e564345e74f2cb", + "blue": 580, + "reorged": false + } + }, + { + "t": 545.5, + "h1": { + "blocks": 585, + "sink": "b1d2689648b6d765", + "daa": 584, + "blue": 585, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 585, + "sink": "b1d2689648b6d765", + "daa": 584, + "blue": 585, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 585, + "sink": "b1d2689648b6d765", + "blue": 585, + "reorged": false + } + }, + { + "t": 550.5, + "h1": { + "blocks": 594, + "sink": "0856bc8c348725e9", + "daa": 593, + "blue": 594, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 594, + "sink": "0856bc8c348725e9", + "daa": 593, + "blue": 594, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 594, + "sink": "0856bc8c348725e9", + "blue": 594, + "reorged": false + } + }, + { + "t": 555.5, + "h1": { + "blocks": 597, + "sink": "b0b25422dae4fab7", + "daa": 596, + "blue": 597, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 597, + "sink": "b0b25422dae4fab7", + "daa": 596, + "blue": 597, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 597, + "sink": "b0b25422dae4fab7", + "blue": 597, + "reorged": false + } + }, + { + "t": 560.5, + "h1": { + "blocks": 606, + "sink": "733de568ec588157", + "daa": 605, + "blue": 606, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 606, + "sink": "733de568ec588157", + "daa": 605, + "blue": 606, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 606, + "sink": "733de568ec588157", + "blue": 606, + "reorged": false + } + }, + { + "t": 565.5, + "h1": { + "blocks": 608, + "sink": "ad3c86d071a93e75", + "daa": 607, + "blue": 608, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 608, + "sink": "ad3c86d071a93e75", + "daa": 607, + "blue": 608, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 608, + "sink": "ad3c86d071a93e75", + "blue": 608, + "reorged": false + } + }, + { + "t": 570.5, + "h1": { + "blocks": 613, + "sink": "a38c3c8af9f6290d", + "daa": 612, + "blue": 613, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 613, + "sink": "a38c3c8af9f6290d", + "daa": 612, + "blue": 613, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 613, + "sink": "a38c3c8af9f6290d", + "blue": 613, + "reorged": false + } + } + ], + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 0, + "ports": { + "base": 30690, + "suffix": 980 + } +} diff --git a/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.log b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.log new file mode 100644 index 00000000..6d4ea6cb --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.log @@ -0,0 +1,18 @@ +12:48:26.701 fg0 case attack-gate-off-expect-reorg: mode attack, gate off (window 60 DAA), joint 240 s, split 180 s, watch 150 s, honest 1 thread(s) each, attacker 3 (joint 0), expect reorg +12:48:28.258 fg0 h1 up pid 480223 json 30692 p2p 30691 +12:48:29.769 fg0 h2 up pid 481517 json 30702 p2p 30701 addpeer 30691 +12:48:31.285 fg0 b up pid 482726 json 30712 p2p 30711 addpeer 30721,30722 +12:52:34.300 fg0 phase 1 done at 240.0 s: H1 242 blocks sink e66998c6 daa 240; H2 242 sink e66998c6; side 2 (b) 242 sink e66998c6; keys H1 8da9ddee H2 eda9cde4 side2 fresh (none yet) +12:52:34.368 fg0 weight at the fork (last 120 blue blocks of H1's chain): side 2 0, others 120, side 2 0 bps +12:52:34.370 fg0 links cut at 240.1 s; side 2 (b) now mines with 3 thread(s), the honest side with 1 each +12:55:34.480 fg0 phase 2 done at 420.2 s: H1 421 blocks sink 6e932c38 daa 420 blue 421 work 14893198; side 2 432 sink d93a1238 daa 431 blue 432 work 17470131 (side 2 heavier: true); fork depth 191 DAA against window 60 +12:55:34.481 fg0 links restored at 420.2 s; watching H1 and H2 for 150 s +12:56:04.569 fg0 t=450.3 s H1 447 blocks sink 1761d611 held; H2 447 blocks sink 1761d611 held; side 2 475 blocks sink 594fe7ff +12:56:34.644 fg0 t=480.4 s H1 486 blocks sink 918c05c7 held; H2 486 blocks sink 918c05c7 held; side 2 504 blocks sink 6ab85269 +12:57:04.714 fg0 H1 left its pre-cut chain at 510.4 s: sink b878077d471c2a73 by eda9cde4 +12:57:04.717 fg0 H2 left its pre-cut chain at 510.4 s: sink b878077d471c2a73 by eda9cde4 +12:57:04.719 fg0 t=510.4 s H1 545 blocks sink b878077d REORGED; H2 545 blocks sink b878077d REORGED; side 2 545 blocks sink b878077d +12:57:34.769 fg0 t=540.5 s H1 580 blocks sink 11e56434 REORGED; H2 580 blocks sink 11e56434 REORGED; side 2 580 blocks sink 11e56434 +12:58:04.814 fg0 t=570.5 s H1 613 blocks sink a38c3c8a REORGED; H2 613 blocks sink a38c3c8a REORGED; side 2 613 blocks sink a38c3c8a +12:58:04.822 fg0 SUMMARY PASS (attack-gate-off-expect-reorg): side 2 held 0 bps of the blue blocks at the fork; fork depth 191 DAA against window 60; side 2 blue work 17470131 against H1 14893198 at the heal; H1 reorged at 510.4 s (0 refusal lines, knows side 2's tip: true); H2 reorged at 510.4 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true +12:58:04.822 fg0 summary: /srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.json diff --git a/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.json b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.json new file mode 100644 index 00000000..546ae42c --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.json @@ -0,0 +1,930 @@ +{ + "pass": true, + "expect": "hold", + "case": "attack-gate-on-expect-hold", + "mode": "attack", + "gate": "on", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 0 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 0, + "others": 121, + "side2_bps": 0 + }, + "fork_daa": 233, + "fork_depth_daa_at_heal": 197, + "sinks": { + "joint": { + "h1": { + "hash": "7ed68743f22e711490406bd380cf66fff94579fcc981344c317a46c18cbc61bb", + "blocks": 234, + "daa": 233, + "blue": 234, + "blueWork": "8862250", + "key": "eda9cde4…" + }, + "h2": { + "hash": "7ed68743f22e711490406bd380cf66fff94579fcc981344c317a46c18cbc61bb", + "blocks": 234, + "daa": 233, + "blue": 234, + "blueWork": "8862250", + "key": "eda9cde4…" + }, + "side2": { + "hash": "7ed68743f22e711490406bd380cf66fff94579fcc981344c317a46c18cbc61bb", + "blocks": 234, + "daa": 233, + "blue": 234, + "blueWork": "8862250", + "key": "eda9cde4…" + } + }, + "split": { + "h1": { + "hash": "036cfe568f3d403351b338ea41b7069ad4eae0ce95308436a25b6c7aa4c1372a", + "blocks": 396, + "daa": 395, + "blue": 396, + "blueWork": "14807915", + "key": "8da9ddee…" + }, + "h2": { + "hash": "036cfe568f3d403351b338ea41b7069ad4eae0ce95308436a25b6c7aa4c1372a", + "blocks": 396, + "daa": 395, + "blue": 396, + "blueWork": "14807915", + "key": "8da9ddee…" + }, + "side2": { + "hash": "abb93c2318f6c2ebdbd4e14a50b3d73ba7f483b8b06b18666e1015d038d4011a", + "blocks": 431, + "daa": 430, + "blue": 431, + "blueWork": "20297242", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": true, + "reorged": false, + "reorg_at_s": null, + "knows_side2_tip": true, + "refusal_lines": 177 + }, + "h2": { + "held": true, + "reorged": false, + "reorg_at_s": null, + "knows_side2_tip": true, + "refusal_lines": 177 + } + }, + "checks": { + "side2_under_a_third_at_fork": true, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": true, + "every_honest_node_reorged": false, + "every_honest_node_logged_a_refusal": true, + "no_honest_node_logged_a_refusal": false, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": "Fork choice: block 41225a00fb38b6394540a5707443bd70e678484cbd20aa3fa8e807bb24df8d4a forks 252 DAA back from the sink's chain and its builders hold 0.00% of the weight table at the fork (under one third); not a sink candidate (ledger 51-percent rank 2)", + "samples": [ + { + "t": 425.2, + "h1": { + "blocks": 407, + "sink": "b9b5fef0daea5b74", + "daa": 406, + "blue": 407, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 407, + "sink": "b9b5fef0daea5b74", + "daa": 406, + "blue": 407, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 436, + "sink": "b87c6327c3fc8298", + "blue": 436, + "reorged": false + } + }, + { + "t": 430.2, + "h1": { + "blocks": 412, + "sink": "cd9991f248c9bf46", + "daa": 411, + "blue": 412, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 412, + "sink": "cd9991f248c9bf46", + "daa": 411, + "blue": 412, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 439, + "sink": "4c1b609fad53a391", + "blue": 439, + "reorged": false + } + }, + { + "t": 435.2, + "h1": { + "blocks": 417, + "sink": "b2bb0dc00c197917", + "daa": 416, + "blue": 417, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 417, + "sink": "b2bb0dc00c197917", + "daa": 416, + "blue": 417, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 444, + "sink": "e382cbd3ac4dcf26", + "blue": 444, + "reorged": false + } + }, + { + "t": 440.2, + "h1": { + "blocks": 422, + "sink": "b711c4c23605870d", + "daa": 421, + "blue": 422, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 422, + "sink": "b711c4c23605870d", + "daa": 421, + "blue": 422, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 446, + "sink": "c35dab954cd4acf4", + "blue": 446, + "reorged": false + } + }, + { + "t": 445.2, + "h1": { + "blocks": 428, + "sink": "f99b9d3dbc93d6c8", + "daa": 427, + "blue": 428, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 428, + "sink": "f99b9d3dbc93d6c8", + "daa": 427, + "blue": 428, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 449, + "sink": "d92f53e2d140db35", + "blue": 449, + "reorged": false + } + }, + { + "t": 450.3, + "h1": { + "blocks": 431, + "sink": "1e9a17dfc27a2670", + "daa": 430, + "blue": 431, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 431, + "sink": "1e9a17dfc27a2670", + "daa": 430, + "blue": 431, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 456, + "sink": "162c5de6d4f74ea9", + "blue": 456, + "reorged": false + } + }, + { + "t": 455.3, + "h1": { + "blocks": 438, + "sink": "65be332f457b64e0", + "daa": 437, + "blue": 438, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 438, + "sink": "65be332f457b64e0", + "daa": 437, + "blue": 438, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 461, + "sink": "6b7998086b33a85d", + "blue": 461, + "reorged": false + } + }, + { + "t": 460.3, + "h1": { + "blocks": 446, + "sink": "5ee05b91ff342422", + "daa": 445, + "blue": 446, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 446, + "sink": "5ee05b91ff342422", + "daa": 445, + "blue": 446, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 468, + "sink": "2ef3594b2514a766", + "blue": 468, + "reorged": false + } + }, + { + "t": 465.3, + "h1": { + "blocks": 451, + "sink": "faad0b35cf941017", + "daa": 450, + "blue": 451, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 451, + "sink": "faad0b35cf941017", + "daa": 450, + "blue": 451, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 471, + "sink": "e57eb146c13fa041", + "blue": 471, + "reorged": false + } + }, + { + "t": 470.3, + "h1": { + "blocks": 454, + "sink": "b5f88fdf5097139b", + "daa": 453, + "blue": 454, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 454, + "sink": "b5f88fdf5097139b", + "daa": 453, + "blue": 454, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 479, + "sink": "bac0a7b389fb2418", + "blue": 479, + "reorged": false + } + }, + { + "t": 475.3, + "h1": { + "blocks": 463, + "sink": "e93acb17237cc9b3", + "daa": 462, + "blue": 463, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 463, + "sink": "e93acb17237cc9b3", + "daa": 462, + "blue": 463, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 481, + "sink": "7a533b847de36a0c", + "blue": 481, + "reorged": false + } + }, + { + "t": 480.3, + "h1": { + "blocks": 467, + "sink": "ea2b7270dba4deba", + "daa": 466, + "blue": 467, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 467, + "sink": "ea2b7270dba4deba", + "daa": 466, + "blue": 467, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 485, + "sink": "5f36be5a27dc4f1f", + "blue": 485, + "reorged": false + } + }, + { + "t": 485.3, + "h1": { + "blocks": 470, + "sink": "caab7c55e1185c44", + "daa": 469, + "blue": 470, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 470, + "sink": "caab7c55e1185c44", + "daa": 469, + "blue": 470, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 490, + "sink": "9b058d11e4a8a864", + "blue": 490, + "reorged": false + } + }, + { + "t": 490.4, + "h1": { + "blocks": 472, + "sink": "19057874449c22ea", + "daa": 471, + "blue": 472, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 472, + "sink": "19057874449c22ea", + "daa": 471, + "blue": 472, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 493, + "sink": "422c79a9ec4780dd", + "blue": 493, + "reorged": false + } + }, + { + "t": 495.4, + "h1": { + "blocks": 475, + "sink": "b6f0161d81faa3e9", + "daa": 474, + "blue": 475, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 475, + "sink": "b6f0161d81faa3e9", + "daa": 474, + "blue": 475, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 497, + "sink": "33c53267da1c7bd5", + "blue": 497, + "reorged": false + } + }, + { + "t": 500.4, + "h1": { + "blocks": 482, + "sink": "6e821ff35e24b700", + "daa": 481, + "blue": 482, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 482, + "sink": "6e821ff35e24b700", + "daa": 481, + "blue": 482, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 501, + "sink": "6536fa666794da92", + "blue": 501, + "reorged": false + } + }, + { + "t": 505.4, + "h1": { + "blocks": 486, + "sink": "bee5af11ed677228", + "daa": 485, + "blue": 486, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 486, + "sink": "bee5af11ed677228", + "daa": 485, + "blue": 486, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 510, + "sink": "be1419603638e1fb", + "blue": 510, + "reorged": false + } + }, + { + "t": 510.4, + "h1": { + "blocks": 491, + "sink": "ed71ec00678a9e10", + "daa": 490, + "blue": 491, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 491, + "sink": "ed71ec00678a9e10", + "daa": 490, + "blue": 491, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 515, + "sink": "7b32f850c803ef02", + "blue": 515, + "reorged": false + } + }, + { + "t": 515.4, + "h1": { + "blocks": 499, + "sink": "ed904ccbc28c9980", + "daa": 498, + "blue": 499, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 499, + "sink": "ed904ccbc28c9980", + "daa": 498, + "blue": 499, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 519, + "sink": "a26ebf100dcba0c2", + "blue": 519, + "reorged": false + } + }, + { + "t": 520.4, + "h1": { + "blocks": 503, + "sink": "462b0c2c35c67c54", + "daa": 502, + "blue": 503, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 503, + "sink": "462b0c2c35c67c54", + "daa": 502, + "blue": 503, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 526, + "sink": "aaaebc1389fe11fd", + "blue": 526, + "reorged": false + } + }, + { + "t": 525.4, + "h1": { + "blocks": 504, + "sink": "87f25e6a386a8165", + "daa": 503, + "blue": 504, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 504, + "sink": "87f25e6a386a8165", + "daa": 503, + "blue": 504, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 529, + "sink": "c096bda65c99e6f8", + "blue": 529, + "reorged": false + } + }, + { + "t": 530.4, + "h1": { + "blocks": 510, + "sink": "6c5d1398a7445010", + "daa": 509, + "blue": 510, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 510, + "sink": "6c5d1398a7445010", + "daa": 509, + "blue": 510, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 533, + "sink": "3341a65b2b284f17", + "blue": 533, + "reorged": false + } + }, + { + "t": 535.4, + "h1": { + "blocks": 514, + "sink": "0d661c0b8cc34ab8", + "daa": 513, + "blue": 514, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 514, + "sink": "0d661c0b8cc34ab8", + "daa": 513, + "blue": 514, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 542, + "sink": "7c3a8038df112ee7", + "blue": 542, + "reorged": false + } + }, + { + "t": 540.4, + "h1": { + "blocks": 525, + "sink": "f2b83fc149654b8d", + "daa": 524, + "blue": 525, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 525, + "sink": "f2b83fc149654b8d", + "daa": 524, + "blue": 525, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 545, + "sink": "36e6ba6e49e7c6f2", + "blue": 545, + "reorged": false + } + }, + { + "t": 545.5, + "h1": { + "blocks": 533, + "sink": "8f1d9ad77edf47d0", + "daa": 532, + "blue": 533, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 533, + "sink": "8f1d9ad77edf47d0", + "daa": 532, + "blue": 533, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 554, + "sink": "857f2b7d99ddcba6", + "blue": 554, + "reorged": false + } + }, + { + "t": 550.5, + "h1": { + "blocks": 537, + "sink": "4cd35471c65af8ff", + "daa": 536, + "blue": 537, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 537, + "sink": "4cd35471c65af8ff", + "daa": 536, + "blue": 537, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 560, + "sink": "5ed4bc501713930a", + "blue": 560, + "reorged": false + } + }, + { + "t": 555.5, + "h1": { + "blocks": 544, + "sink": "1174f796fda59e3e", + "daa": 543, + "blue": 544, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 544, + "sink": "1174f796fda59e3e", + "daa": 543, + "blue": 544, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 565, + "sink": "f7d136350536fa6b", + "blue": 565, + "reorged": false + } + }, + { + "t": 560.5, + "h1": { + "blocks": 548, + "sink": "f6ed678d1b0a96f8", + "daa": 547, + "blue": 548, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 548, + "sink": "f6ed678d1b0a96f8", + "daa": 547, + "blue": 548, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 568, + "sink": "37ac0328bf8f53e4", + "blue": 568, + "reorged": false + } + }, + { + "t": 565.5, + "h1": { + "blocks": 556, + "sink": "86f4c28c6ba82275", + "daa": 555, + "blue": 556, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 556, + "sink": "86f4c28c6ba82275", + "daa": 555, + "blue": 556, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 572, + "sink": "9d9ec576b2742464", + "blue": 572, + "reorged": false + } + }, + { + "t": 570.5, + "h1": { + "blocks": 560, + "sink": "3210de1f85cbfc76", + "daa": 559, + "blue": 560, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "h2": { + "blocks": 560, + "sink": "3210de1f85cbfc76", + "daa": 559, + "blue": 560, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": true + }, + "side2": { + "blocks": 574, + "sink": "3496b576346db4bb", + "blue": 574, + "reorged": false + } + } + ], + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 2, + "ports": { + "base": 30770, + "suffix": 982 + } +} diff --git a/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.log b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.log new file mode 100644 index 00000000..fb2480ae --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.log @@ -0,0 +1,16 @@ +12:48:26.709 fg2 case attack-gate-on-expect-hold: mode attack, gate on (window 60 DAA), joint 240 s, split 180 s, watch 150 s, honest 1 thread(s) each, attacker 3 (joint 0), expect hold +12:48:28.273 fg2 h1 up pid 480230 json 30772 p2p 30771 +12:48:29.784 fg2 h2 up pid 481529 json 30782 p2p 30781 addpeer 30771 +12:48:31.299 fg2 b up pid 482751 json 30792 p2p 30791 addpeer 30801,30802 +12:52:34.314 fg2 phase 1 done at 240.0 s: H1 234 blocks sink 7ed68743 daa 233; H2 234 sink 7ed68743; side 2 (b) 234 sink 7ed68743; keys H1 8da9ddee H2 eda9cde4 side2 fresh (none yet) +12:52:34.371 fg2 weight at the fork (last 121 blue blocks of H1's chain): side 2 0, others 121, side 2 0 bps +12:52:34.375 fg2 links cut at 240.1 s; side 2 (b) now mines with 3 thread(s), the honest side with 1 each +12:55:34.483 fg2 phase 2 done at 420.2 s: H1 396 blocks sink 036cfe56 daa 395 blue 396 work 14807915; side 2 431 sink abb93c23 daa 430 blue 431 work 20297242 (side 2 heavier: true); fork depth 197 DAA against window 60 +12:55:34.484 fg2 links restored at 420.2 s; watching H1 and H2 for 150 s +12:56:04.568 fg2 t=450.3 s H1 431 blocks sink 1e9a17df held; H2 431 blocks sink 1e9a17df held; side 2 456 blocks sink 162c5de6 +12:56:34.640 fg2 t=480.3 s H1 467 blocks sink ea2b7270 held; H2 467 blocks sink ea2b7270 held; side 2 485 blocks sink 5f36be5a +12:57:04.717 fg2 t=510.4 s H1 491 blocks sink ed71ec00 held; H2 491 blocks sink ed71ec00 held; side 2 515 blocks sink 7b32f850 +12:57:34.757 fg2 t=540.5 s H1 525 blocks sink f2b83fc1 held; H2 525 blocks sink f2b83fc1 held; side 2 545 blocks sink 36e6ba6e +12:58:04.809 fg2 t=570.5 s H1 560 blocks sink 3210de1f held; H2 560 blocks sink 3210de1f held; side 2 574 blocks sink 3496b576 +12:58:04.822 fg2 SUMMARY PASS (attack-gate-on-expect-hold): side 2 held 0 bps of the blue blocks at the fork; fork depth 197 DAA against window 60; side 2 blue work 20297242 against H1 14807915 at the heal; H1 held (177 refusal lines, knows side 2's tip: true); H2 held (177 refusal lines, knows side 2's tip: true); side 2 kept its chain: true +12:58:04.822 fg2 summary: /srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.json diff --git a/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.json b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.json new file mode 100644 index 00000000..7787b6d2 --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.json @@ -0,0 +1,653 @@ +{ + "pass": true, + "expect": "reorg", + "case": "partition-gate-off-expect-reorg", + "mode": "partition", + "gate": "off", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 1 + }, + "keys": { + "h1": "8da9ddee…", + "h2": null, + "side2": "eda9cde4…" + }, + "share_at_fork": { + "side2": 67, + "others": 53, + "side2_bps": 5583 + }, + "fork_daa": 244, + "fork_depth_daa_at_heal": 191, + "sinks": { + "joint": { + "h1": { + "hash": "58126c351aa6324a992a47fa66cca22369450c9835d312772c87d3e1aeb409a0", + "blocks": 245, + "daa": 244, + "blue": 245, + "blueWork": "9558440", + "key": "8da9ddee…" + }, + "h2": { + "hash": "58126c351aa6324a992a47fa66cca22369450c9835d312772c87d3e1aeb409a0", + "blocks": 245, + "daa": 244, + "blue": 245, + "blueWork": "9558440", + "key": "8da9ddee…" + }, + "side2": { + "hash": "58126c351aa6324a992a47fa66cca22369450c9835d312772c87d3e1aeb409a0", + "blocks": 245, + "daa": 244, + "blue": 245, + "blueWork": "9558440", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "a27a341c694aacf22b1a78f44d433e4104f58b23533afb73b7ee6fb9aa37afe4", + "blocks": 405, + "daa": 404, + "blue": 405, + "blueWork": "12270631", + "key": "8da9ddee…" + }, + "h2": { + "hash": "f9181a06c0db716fe4ed200f6f0046c9cb8fae2eb57dd7da4697a268c434a232", + "blocks": 436, + "daa": 435, + "blue": 436, + "blueWork": "19576159", + "key": "eda9cde4…" + }, + "side2": { + "hash": "f9181a06c0db716fe4ed200f6f0046c9cb8fae2eb57dd7da4697a268c434a232", + "blocks": 436, + "daa": 435, + "blue": 436, + "blueWork": "19576159", + "key": "eda9cde4…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 507.4, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": false, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "samples": [ + { + "t": 427.2, + "h1": { + "blocks": 411, + "sink": "d783538ac11687a9", + "daa": 410, + "blue": 411, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 439, + "sink": "aa3da0091db61498", + "blue": 439, + "reorged": false + } + }, + { + "t": 432.2, + "h1": { + "blocks": 416, + "sink": "5084ccaac5b21e34", + "daa": 415, + "blue": 416, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 448, + "sink": "c98585f0a1f24913", + "blue": 448, + "reorged": false + } + }, + { + "t": 437.2, + "h1": { + "blocks": 421, + "sink": "950f8b1c7d4cac21", + "daa": 420, + "blue": 421, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 452, + "sink": "c4ad3925b38e9285", + "blue": 452, + "reorged": false + } + }, + { + "t": 442.2, + "h1": { + "blocks": 424, + "sink": "767cbc91083a48b0", + "daa": 423, + "blue": 424, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 455, + "sink": "c91b500a6d256eb3", + "blue": 455, + "reorged": false + } + }, + { + "t": 447.3, + "h1": { + "blocks": 429, + "sink": "d36268f977a04b6a", + "daa": 428, + "blue": 429, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 465, + "sink": "c5a91c0c5352b0d6", + "blue": 465, + "reorged": false + } + }, + { + "t": 452.3, + "h1": { + "blocks": 438, + "sink": "a7ecf244074b481d", + "daa": 437, + "blue": 438, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 468, + "sink": "cd8cfb427f0c78e4", + "blue": 468, + "reorged": false + } + }, + { + "t": 457.3, + "h1": { + "blocks": 441, + "sink": "29f8733c4ec6fa4b", + "daa": 440, + "blue": 441, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 473, + "sink": "277bfdb7682804f9", + "blue": 473, + "reorged": false + } + }, + { + "t": 462.3, + "h1": { + "blocks": 451, + "sink": "ae072b1106d34635", + "daa": 450, + "blue": 451, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 476, + "sink": "d0f88a7c220ff170", + "blue": 476, + "reorged": false + } + }, + { + "t": 467.3, + "h1": { + "blocks": 458, + "sink": "9fcfa1edabf60dd7", + "daa": 457, + "blue": 458, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 486, + "sink": "9f66b943e3b972b7", + "blue": 486, + "reorged": false + } + }, + { + "t": 472.3, + "h1": { + "blocks": 462, + "sink": "8dcef0d603690a6e", + "daa": 461, + "blue": 462, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 493, + "sink": "a70a07e96280ab1e", + "blue": 493, + "reorged": false + } + }, + { + "t": 477.3, + "h1": { + "blocks": 464, + "sink": "c6dceb1dfe662639", + "daa": 463, + "blue": 464, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 495, + "sink": "1b6074e848285a01", + "blue": 495, + "reorged": false + } + }, + { + "t": 482.4, + "h1": { + "blocks": 468, + "sink": "97b7a7a0a8248207", + "daa": 467, + "blue": 468, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 500, + "sink": "a4045188d0e6fb97", + "blue": 500, + "reorged": false + } + }, + { + "t": 487.4, + "h1": { + "blocks": 472, + "sink": "2326f1a0ffea21d8", + "daa": 471, + "blue": 472, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 504, + "sink": "813c0c0f3fe0d62b", + "blue": 504, + "reorged": false + } + }, + { + "t": 492.4, + "h1": { + "blocks": 476, + "sink": "2e8644b1907a9120", + "daa": 475, + "blue": 476, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 508, + "sink": "9345acb132973ee6", + "blue": 508, + "reorged": false + } + }, + { + "t": 497.4, + "h1": { + "blocks": 481, + "sink": "04a443536671ab8f", + "daa": 480, + "blue": 481, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 512, + "sink": "0db73c40f531667d", + "blue": 512, + "reorged": false + } + }, + { + "t": 502.4, + "h1": { + "blocks": 487, + "sink": "9afd673d306dc43c", + "daa": 486, + "blue": 487, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 519, + "sink": "e749191f14932323", + "blue": 519, + "reorged": false + } + }, + { + "t": 507.4, + "h1": { + "blocks": 527, + "sink": "afed1d222ea7304d", + "daa": 526, + "blue": 527, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 527, + "sink": "afed1d222ea7304d", + "blue": 527, + "reorged": false + } + }, + { + "t": 512.4, + "h1": { + "blocks": 538, + "sink": "54deb8450401f863", + "daa": 537, + "blue": 538, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 538, + "sink": "54deb8450401f863", + "blue": 538, + "reorged": false + } + }, + { + "t": 517.4, + "h1": { + "blocks": 543, + "sink": "089737446a988ecf", + "daa": 542, + "blue": 543, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 543, + "sink": "089737446a988ecf", + "blue": 543, + "reorged": false + } + }, + { + "t": 522.4, + "h1": { + "blocks": 547, + "sink": "fddba72379711067", + "daa": 546, + "blue": 547, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 547, + "sink": "fddba72379711067", + "blue": 547, + "reorged": false + } + }, + { + "t": 527.4, + "h1": { + "blocks": 553, + "sink": "d090e72490be6b7a", + "daa": 552, + "blue": 553, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 553, + "sink": "d090e72490be6b7a", + "blue": 553, + "reorged": false + } + }, + { + "t": 532.4, + "h1": { + "blocks": 561, + "sink": "1caf40533f6a2857", + "daa": 560, + "blue": 561, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 561, + "sink": "1caf40533f6a2857", + "blue": 561, + "reorged": false + } + }, + { + "t": 537.4, + "h1": { + "blocks": 573, + "sink": "e5b85c33b2b6aa09", + "daa": 572, + "blue": 573, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 573, + "sink": "e5b85c33b2b6aa09", + "blue": 573, + "reorged": false + } + }, + { + "t": 542.4, + "h1": { + "blocks": 578, + "sink": "317e329b8505cf1e", + "daa": 577, + "blue": 578, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 578, + "sink": "317e329b8505cf1e", + "blue": 578, + "reorged": false + } + }, + { + "t": 547.5, + "h1": { + "blocks": 581, + "sink": "e19cd0330c3cdf25", + "daa": 580, + "blue": 581, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 581, + "sink": "e19cd0330c3cdf25", + "blue": 581, + "reorged": false + } + }, + { + "t": 552.5, + "h1": { + "blocks": 586, + "sink": "38f228d7ffc3d0c1", + "daa": 585, + "blue": 586, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 586, + "sink": "38f228d7ffc3d0c1", + "blue": 586, + "reorged": false + } + }, + { + "t": 557.5, + "h1": { + "blocks": 592, + "sink": "ae515bf3d13e4865", + "daa": 591, + "blue": 592, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 592, + "sink": "ae515bf3d13e4865", + "blue": 592, + "reorged": false + } + }, + { + "t": 562.5, + "h1": { + "blocks": 595, + "sink": "eeade53e9149c05a", + "daa": 594, + "blue": 595, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 595, + "sink": "eeade53e9149c05a", + "blue": 595, + "reorged": false + } + }, + { + "t": 567.5, + "h1": { + "blocks": 597, + "sink": "a939e8caebf875d6", + "daa": 596, + "blue": 597, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 597, + "sink": "a939e8caebf875d6", + "blue": 597, + "reorged": false + } + }, + { + "t": 572.5, + "h1": { + "blocks": 605, + "sink": "1e585f80dc1050fa", + "daa": 604, + "blue": 605, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 605, + "sink": "1e585f80dc1050fa", + "blue": 605, + "reorged": false + } + } + ], + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 5, + "ports": { + "base": 30890, + "suffix": 985 + } +} diff --git a/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.log b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.log new file mode 100644 index 00000000..63e1e20c --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.log @@ -0,0 +1,16 @@ +12:48:26.732 fg5 case partition-gate-off-expect-reorg: mode partition, gate off (window 60 DAA), joint 240 s, split 180 s, watch 150 s, honest 1 thread(s) each, attacker 3 (joint 1), expect reorg +12:48:28.310 fg5 h1 up pid 480280 json 30892 p2p 30891 +12:48:29.828 fg5 h2 up pid 481840 json 30902 p2p 30901 addpeer 30921 +12:52:32.849 fg5 phase 1 done at 240.0 s: H1 245 blocks sink 58126c35 daa 244; H2 245 sink 58126c35; side 2 (h2) 245 sink 58126c35; keys H1 8da9ddee H2 undefined side2 eda9cde4 +12:52:32.909 fg5 weight at the fork (last 120 blue blocks of H1's chain): side 2 67, others 53, side 2 5583 bps +12:52:34.922 fg5 links cut at 242.1 s; side 2 (h2) now mines with 3 thread(s), the honest side with 1 each +12:55:35.025 fg5 phase 2 done at 422.2 s: H1 405 blocks sink a27a341c daa 404 blue 405 work 12270631; side 2 436 sink f9181a06 daa 435 blue 436 work 19576159 (side 2 heavier: true); fork depth 191 DAA against window 60 +12:55:35.026 fg5 links restored at 422.2 s; watching H1 for 150 s +12:56:05.117 fg5 t=452.3 s H1 438 blocks sink a7ecf244 held; side 2 468 blocks sink cd8cfb42 +12:56:35.193 fg5 t=482.4 s H1 468 blocks sink 97b7a7a0 held; side 2 500 blocks sink a4045188 +12:57:00.247 fg5 H1 left its pre-cut chain at 507.4 s: sink afed1d222ea7304d by eda9cde4 +12:57:05.255 fg5 t=512.4 s H1 538 blocks sink 54deb845 REORGED; side 2 538 blocks sink 54deb845 +12:57:35.285 fg5 t=542.5 s H1 578 blocks sink 317e329b REORGED; side 2 578 blocks sink 317e329b +12:58:05.313 fg5 t=572.5 s H1 605 blocks sink 1e585f80 REORGED; side 2 605 blocks sink 1e585f80 +12:58:05.317 fg5 SUMMARY PASS (partition-gate-off-expect-reorg): side 2 held 5583 bps of the blue blocks at the fork; fork depth 191 DAA against window 60; side 2 blue work 19576159 against H1 12270631 at the heal; H1 reorged at 507.4 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true +12:58:05.318 fg5 summary: /srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.json diff --git a/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.json b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.json new file mode 100644 index 00000000..016c39fe --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.json @@ -0,0 +1,653 @@ +{ + "pass": true, + "expect": "reorg", + "case": "partition-gate-on-expect-reorg", + "mode": "partition", + "gate": "on", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 1 + }, + "keys": { + "h1": "8da9ddee…", + "h2": null, + "side2": "eda9cde4…" + }, + "share_at_fork": { + "side2": 45, + "others": 76, + "side2_bps": 3719 + }, + "fork_daa": 245, + "fork_depth_daa_at_heal": 194, + "sinks": { + "joint": { + "h1": { + "hash": "5c4cb584dc015892ddff89337412ed0883d9f97b4e791e7af2f7f64764f4f1e8", + "blocks": 246, + "daa": 245, + "blue": 246, + "blueWork": "8723556", + "key": "8da9ddee…" + }, + "h2": { + "hash": "5c4cb584dc015892ddff89337412ed0883d9f97b4e791e7af2f7f64764f4f1e8", + "blocks": 246, + "daa": 245, + "blue": 246, + "blueWork": "8723556", + "key": "8da9ddee…" + }, + "side2": { + "hash": "5c4cb584dc015892ddff89337412ed0883d9f97b4e791e7af2f7f64764f4f1e8", + "blocks": 246, + "daa": 245, + "blue": 246, + "blueWork": "8723556", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "753507c15705f4ea8ed19bc2697a11c489a052a45f28c64f9ac3d8400fa66647", + "blocks": 412, + "daa": 411, + "blue": 412, + "blueWork": "11490863", + "key": "8da9ddee…" + }, + "h2": { + "hash": "32b7c1757fa288eed0a8ab709e49fd86f72be531db19c58e63d0aeca7a34c4f6", + "blocks": 440, + "daa": 439, + "blue": 440, + "blueWork": "18089683", + "key": "eda9cde4…" + }, + "side2": { + "hash": "32b7c1757fa288eed0a8ab709e49fd86f72be531db19c58e63d0aeca7a34c4f6", + "blocks": 440, + "daa": 439, + "blue": 440, + "blueWork": "18089683", + "key": "eda9cde4…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 507.4, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": false, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "samples": [ + { + "t": 427.2, + "h1": { + "blocks": 420, + "sink": "3c08068c8a93e490", + "daa": 419, + "blue": 420, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 443, + "sink": "5058df4580954747", + "blue": 443, + "reorged": false + } + }, + { + "t": 432.2, + "h1": { + "blocks": 424, + "sink": "de896377901e94a8", + "daa": 423, + "blue": 424, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 455, + "sink": "a07d00aee9d3376d", + "blue": 455, + "reorged": false + } + }, + { + "t": 437.2, + "h1": { + "blocks": 435, + "sink": "eaff2cb616a46c0e", + "daa": 434, + "blue": 435, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 461, + "sink": "4783198d038613db", + "blue": 461, + "reorged": false + } + }, + { + "t": 442.2, + "h1": { + "blocks": 439, + "sink": "103fa3b3ea629ad7", + "daa": 438, + "blue": 439, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 465, + "sink": "91ba868ec4f84eef", + "blue": 465, + "reorged": false + } + }, + { + "t": 447.3, + "h1": { + "blocks": 448, + "sink": "8437327aa78561ba", + "daa": 447, + "blue": 448, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 474, + "sink": "bb9ac90349a213e3", + "blue": 474, + "reorged": false + } + }, + { + "t": 452.3, + "h1": { + "blocks": 450, + "sink": "03bd0f5a924e03ee", + "daa": 449, + "blue": 450, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 478, + "sink": "eca80f2c1a2106d5", + "blue": 478, + "reorged": false + } + }, + { + "t": 457.3, + "h1": { + "blocks": 461, + "sink": "3fc505f8af71ea5f", + "daa": 460, + "blue": 461, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 481, + "sink": "017216a3976533dd", + "blue": 481, + "reorged": false + } + }, + { + "t": 462.3, + "h1": { + "blocks": 463, + "sink": "a1b1d645d944446d", + "daa": 462, + "blue": 463, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 488, + "sink": "3ade2bb97b8e7548", + "blue": 488, + "reorged": false + } + }, + { + "t": 467.3, + "h1": { + "blocks": 466, + "sink": "5b046e8c04baa74e", + "daa": 465, + "blue": 466, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 494, + "sink": "179ad98b8bcc4ea5", + "blue": 494, + "reorged": false + } + }, + { + "t": 472.3, + "h1": { + "blocks": 470, + "sink": "aaf64f90ccac9c8a", + "daa": 469, + "blue": 470, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 498, + "sink": "1970740c1d9b0f6c", + "blue": 498, + "reorged": false + } + }, + { + "t": 477.3, + "h1": { + "blocks": 473, + "sink": "b557fc4c16174c35", + "daa": 472, + "blue": 473, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 506, + "sink": "078df046b3a9953f", + "blue": 506, + "reorged": false + } + }, + { + "t": 482.3, + "h1": { + "blocks": 480, + "sink": "7d7d5f6734e2c727", + "daa": 479, + "blue": 480, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 510, + "sink": "9e0f40b6766308e8", + "blue": 510, + "reorged": false + } + }, + { + "t": 487.4, + "h1": { + "blocks": 485, + "sink": "6d3ff10f4556a1ca", + "daa": 484, + "blue": 485, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 512, + "sink": "aecf9f8ea6485764", + "blue": 512, + "reorged": false + } + }, + { + "t": 492.4, + "h1": { + "blocks": 489, + "sink": "1196cd92a2989963", + "daa": 488, + "blue": 489, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 518, + "sink": "0a3a90068c2d74c0", + "blue": 518, + "reorged": false + } + }, + { + "t": 497.4, + "h1": { + "blocks": 494, + "sink": "27ca83564fbe47ce", + "daa": 493, + "blue": 494, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 524, + "sink": "42b2b2dc9f1e4be2", + "blue": 524, + "reorged": false + } + }, + { + "t": 502.4, + "h1": { + "blocks": 498, + "sink": "3f2c6e34b36b890e", + "daa": 497, + "blue": 498, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 531, + "sink": "d19320eebc86c66d", + "blue": 531, + "reorged": false + } + }, + { + "t": 507.4, + "h1": { + "blocks": 535, + "sink": "126029df2f9caa4a", + "daa": 534, + "blue": 535, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 535, + "sink": "126029df2f9caa4a", + "blue": 535, + "reorged": false + } + }, + { + "t": 512.4, + "h1": { + "blocks": 543, + "sink": "533898421902f564", + "daa": 542, + "blue": 543, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 543, + "sink": "533898421902f564", + "blue": 543, + "reorged": false + } + }, + { + "t": 517.4, + "h1": { + "blocks": 546, + "sink": "85a43553233cf34b", + "daa": 545, + "blue": 546, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 546, + "sink": "85a43553233cf34b", + "blue": 546, + "reorged": false + } + }, + { + "t": 522.4, + "h1": { + "blocks": 554, + "sink": "bed61271f9a8252d", + "daa": 553, + "blue": 554, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 554, + "sink": "bed61271f9a8252d", + "blue": 554, + "reorged": false + } + }, + { + "t": 527.4, + "h1": { + "blocks": 560, + "sink": "9e91960a30057229", + "daa": 559, + "blue": 560, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 560, + "sink": "9e91960a30057229", + "blue": 560, + "reorged": false + } + }, + { + "t": 532.4, + "h1": { + "blocks": 564, + "sink": "cd6d1240dc30d2e4", + "daa": 563, + "blue": 564, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 564, + "sink": "cd6d1240dc30d2e4", + "blue": 564, + "reorged": false + } + }, + { + "t": 537.4, + "h1": { + "blocks": 570, + "sink": "0208b9cbd8adfa78", + "daa": 569, + "blue": 570, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 570, + "sink": "0208b9cbd8adfa78", + "blue": 570, + "reorged": false + } + }, + { + "t": 542.4, + "h1": { + "blocks": 573, + "sink": "627692d65f09e879", + "daa": 572, + "blue": 573, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 573, + "sink": "627692d65f09e879", + "blue": 573, + "reorged": false + } + }, + { + "t": 547.5, + "h1": { + "blocks": 576, + "sink": "84b34763f034804b", + "daa": 575, + "blue": 576, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 576, + "sink": "84b34763f034804b", + "blue": 576, + "reorged": false + } + }, + { + "t": 552.5, + "h1": { + "blocks": 580, + "sink": "4ce7dce8da22296a", + "daa": 579, + "blue": 580, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 580, + "sink": "4ce7dce8da22296a", + "blue": 580, + "reorged": false + } + }, + { + "t": 557.5, + "h1": { + "blocks": 585, + "sink": "f8c7fb1089532dde", + "daa": 584, + "blue": 585, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 585, + "sink": "f8c7fb1089532dde", + "blue": 585, + "reorged": false + } + }, + { + "t": 562.5, + "h1": { + "blocks": 590, + "sink": "07d408946584e422", + "daa": 589, + "blue": 590, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 590, + "sink": "07d408946584e422", + "blue": 590, + "reorged": false + } + }, + { + "t": 567.5, + "h1": { + "blocks": 598, + "sink": "3ffc006b66a221b9", + "daa": 597, + "blue": 598, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 598, + "sink": "3ffc006b66a221b9", + "blue": 598, + "reorged": false + } + }, + { + "t": 572.5, + "h1": { + "blocks": 602, + "sink": "b3827232c44b06d2", + "daa": 601, + "blue": 602, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 602, + "sink": "b3827232c44b06d2", + "blue": 602, + "reorged": false + } + } + ], + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 4, + "ports": { + "base": 30850, + "suffix": 984 + } +} diff --git a/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.log b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.log new file mode 100644 index 00000000..6f32860a --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.log @@ -0,0 +1,16 @@ +12:48:26.723 fg4 case partition-gate-on-expect-reorg: mode partition, gate on (window 60 DAA), joint 240 s, split 180 s, watch 150 s, honest 1 thread(s) each, attacker 3 (joint 1), expect reorg +12:48:28.322 fg4 h1 up pid 480248 json 30852 p2p 30851 +12:48:29.844 fg4 h2 up pid 481994 json 30862 p2p 30861 addpeer 30881 +12:52:32.858 fg4 phase 1 done at 240.0 s: H1 246 blocks sink 5c4cb584 daa 245; H2 246 sink 5c4cb584; side 2 (h2) 246 sink 5c4cb584; keys H1 8da9ddee H2 undefined side2 eda9cde4 +12:52:32.918 fg4 weight at the fork (last 121 blue blocks of H1's chain): side 2 45, others 76, side 2 3719 bps +12:52:34.929 fg4 links cut at 242.1 s; side 2 (h2) now mines with 3 thread(s), the honest side with 1 each +12:55:35.033 fg4 phase 2 done at 422.2 s: H1 412 blocks sink 753507c1 daa 411 blue 412 work 11490863; side 2 440 sink 32b7c175 daa 439 blue 440 work 18089683 (side 2 heavier: true); fork depth 194 DAA against window 60 +12:55:35.035 fg4 links restored at 422.2 s; watching H1 for 150 s +12:56:05.124 fg4 t=452.3 s H1 450 blocks sink 03bd0f5a held; side 2 478 blocks sink eca80f2c +12:56:35.198 fg4 t=482.4 s H1 480 blocks sink 7d7d5f67 held; side 2 510 blocks sink 9e0f40b6 +12:57:00.246 fg4 H1 left its pre-cut chain at 507.4 s: sink 126029df2f9caa4a by eda9cde4 +12:57:05.255 fg4 t=512.4 s H1 543 blocks sink 53389842 REORGED; side 2 543 blocks sink 53389842 +12:57:35.298 fg4 t=542.5 s H1 573 blocks sink 627692d6 REORGED; side 2 573 blocks sink 627692d6 +12:58:05.330 fg4 t=572.5 s H1 602 blocks sink b3827232 REORGED; side 2 602 blocks sink b3827232 +12:58:05.334 fg4 SUMMARY PASS (partition-gate-on-expect-reorg): side 2 held 3719 bps of the blue blocks at the fork; fork depth 194 DAA against window 60; side 2 blue work 18089683 against H1 11490863 at the heal; H1 reorged at 507.4 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true +12:58:05.334 fg4 summary: /srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.json diff --git a/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.json b/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.json new file mode 100644 index 00000000..72840c79 --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.json @@ -0,0 +1,930 @@ +{ + "pass": true, + "expect": "reorg", + "case": "third-gate-on-expect-reorg", + "mode": "third", + "gate": "on", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 2 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 72, + "others": 48, + "side2_bps": 6000 + }, + "fork_daa": 268, + "fork_depth_daa_at_heal": 166, + "sinks": { + "joint": { + "h1": { + "hash": "037edd2a2976af7aec3f6b00d0532706f2c4bc48a2ace2d4e92f027492aa42af", + "blocks": 269, + "daa": 268, + "blue": 269, + "blueWork": "17483286", + "key": "0e2c6fe2…" + }, + "h2": { + "hash": "037edd2a2976af7aec3f6b00d0532706f2c4bc48a2ace2d4e92f027492aa42af", + "blocks": 269, + "daa": 268, + "blue": 269, + "blueWork": "17483286", + "key": "0e2c6fe2…" + }, + "side2": { + "hash": "037edd2a2976af7aec3f6b00d0532706f2c4bc48a2ace2d4e92f027492aa42af", + "blocks": 269, + "daa": 268, + "blue": 269, + "blueWork": "17483286", + "key": "0e2c6fe2…" + } + }, + "split": { + "h1": { + "hash": "06f666ba3c449f2fab804e75612a00c748a8d56568806c30a7006aae175bb27d", + "blocks": 426, + "daa": 425, + "blue": 426, + "blueWork": "24628833", + "key": "8da9ddee…" + }, + "h2": { + "hash": "06f666ba3c449f2fab804e75612a00c748a8d56568806c30a7006aae175bb27d", + "blocks": 426, + "daa": 425, + "blue": 426, + "blueWork": "24628833", + "key": "8da9ddee…" + }, + "side2": { + "hash": "71396cf73521295ad0fbeb320de980989ea0788dbc859129d8972a9e091e0a3c", + "blocks": 435, + "daa": 434, + "blue": 435, + "blueWork": "28969222", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 477.3, + "knows_side2_tip": true, + "refusal_lines": 0 + }, + "h2": { + "held": false, + "reorged": true, + "reorg_at_s": 477.3, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": false, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "samples": [ + { + "t": 427.2, + "h1": { + "blocks": 431, + "sink": "9a61020b8d49143a", + "daa": 430, + "blue": 431, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 431, + "sink": "9a61020b8d49143a", + "daa": 430, + "blue": 431, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 441, + "sink": "05e6f9d4ef677d31", + "blue": 441, + "reorged": false + } + }, + { + "t": 432.2, + "h1": { + "blocks": 439, + "sink": "a4130e66a3d4a3df", + "daa": 438, + "blue": 439, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 439, + "sink": "a4130e66a3d4a3df", + "daa": 438, + "blue": 439, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 449, + "sink": "f7d08aee6cf90b41", + "blue": 449, + "reorged": false + } + }, + { + "t": 437.2, + "h1": { + "blocks": 442, + "sink": "e1cc039c584559d7", + "daa": 441, + "blue": 442, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 442, + "sink": "e1cc039c584559d7", + "daa": 441, + "blue": 442, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 455, + "sink": "fa56a0ac4e5fb99c", + "blue": 455, + "reorged": false + } + }, + { + "t": 442.2, + "h1": { + "blocks": 444, + "sink": "6904c2a75c7344fe", + "daa": 443, + "blue": 444, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 444, + "sink": "6904c2a75c7344fe", + "daa": 443, + "blue": 444, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 459, + "sink": "04b09f8a190c4051", + "blue": 459, + "reorged": false + } + }, + { + "t": 447.2, + "h1": { + "blocks": 449, + "sink": "d55f8f3f03247788", + "daa": 448, + "blue": 449, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 449, + "sink": "d55f8f3f03247788", + "daa": 448, + "blue": 449, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 462, + "sink": "a6fa74e0833a3e0c", + "blue": 462, + "reorged": false + } + }, + { + "t": 452.2, + "h1": { + "blocks": 454, + "sink": "feb2905b292ab9c7", + "daa": 453, + "blue": 454, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 454, + "sink": "feb2905b292ab9c7", + "daa": 453, + "blue": 454, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 464, + "sink": "093014496d558f65", + "blue": 464, + "reorged": false + } + }, + { + "t": 457.3, + "h1": { + "blocks": 462, + "sink": "b10ed98591f50ec6", + "daa": 461, + "blue": 462, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 462, + "sink": "b10ed98591f50ec6", + "daa": 461, + "blue": 462, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 469, + "sink": "7a00df10d8b78e18", + "blue": 469, + "reorged": false + } + }, + { + "t": 462.3, + "h1": { + "blocks": 467, + "sink": "ebf8c4bd560f2ccf", + "daa": 466, + "blue": 467, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 467, + "sink": "ebf8c4bd560f2ccf", + "daa": 466, + "blue": 467, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 474, + "sink": "ade976380c06a8d8", + "blue": 474, + "reorged": false + } + }, + { + "t": 467.3, + "h1": { + "blocks": 471, + "sink": "311bf74ecfb1cb33", + "daa": 470, + "blue": 471, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 471, + "sink": "311bf74ecfb1cb33", + "daa": 470, + "blue": 471, + "key": "8da9ddee", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 482, + "sink": "a1dc4abe41431122", + "blue": 482, + "reorged": false + } + }, + { + "t": 472.3, + "h1": { + "blocks": 476, + "sink": "0fc8726976801d2b", + "daa": 475, + "blue": 476, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "h2": { + "blocks": 476, + "sink": "0fc8726976801d2b", + "daa": 475, + "blue": 476, + "key": "eda9cde4", + "reorged": false, + "knows_side2_tip": false + }, + "side2": { + "blocks": 487, + "sink": "c2c737c0d473f009", + "blue": 487, + "reorged": false + } + }, + { + "t": 477.3, + "h1": { + "blocks": 492, + "sink": "df2ecca49796b69c", + "daa": 491, + "blue": 492, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 492, + "sink": "df2ecca49796b69c", + "daa": 491, + "blue": 492, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 492, + "sink": "df2ecca49796b69c", + "blue": 492, + "reorged": false + } + }, + { + "t": 482.3, + "h1": { + "blocks": 498, + "sink": "33ab64dbbd41433e", + "daa": 497, + "blue": 498, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 498, + "sink": "33ab64dbbd41433e", + "daa": 497, + "blue": 498, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 498, + "sink": "33ab64dbbd41433e", + "blue": 498, + "reorged": false + } + }, + { + "t": 487.3, + "h1": { + "blocks": 506, + "sink": "4fa4f31a124990c1", + "daa": 505, + "blue": 506, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 506, + "sink": "4fa4f31a124990c1", + "daa": 505, + "blue": 506, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 506, + "sink": "4fa4f31a124990c1", + "blue": 506, + "reorged": false + } + }, + { + "t": 492.3, + "h1": { + "blocks": 510, + "sink": "4121ec5f7e04b3a2", + "daa": 509, + "blue": 510, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 510, + "sink": "4121ec5f7e04b3a2", + "daa": 509, + "blue": 510, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 510, + "sink": "4121ec5f7e04b3a2", + "blue": 510, + "reorged": false + } + }, + { + "t": 497.3, + "h1": { + "blocks": 518, + "sink": "217d584ac3d48f32", + "daa": 517, + "blue": 518, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 518, + "sink": "217d584ac3d48f32", + "daa": 517, + "blue": 518, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 518, + "sink": "217d584ac3d48f32", + "blue": 518, + "reorged": false + } + }, + { + "t": 502.3, + "h1": { + "blocks": 527, + "sink": "d14ed2e5f11c7df7", + "daa": 526, + "blue": 527, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 527, + "sink": "d14ed2e5f11c7df7", + "daa": 526, + "blue": 527, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 527, + "sink": "d14ed2e5f11c7df7", + "blue": 527, + "reorged": false + } + }, + { + "t": 507.3, + "h1": { + "blocks": 533, + "sink": "23cf4405d058110e", + "daa": 532, + "blue": 533, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 533, + "sink": "23cf4405d058110e", + "daa": 532, + "blue": 533, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 533, + "sink": "23cf4405d058110e", + "blue": 533, + "reorged": false + } + }, + { + "t": 512.4, + "h1": { + "blocks": 537, + "sink": "ec6ff75c8617a6c0", + "daa": 535, + "blue": 536, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 537, + "sink": "ec6ff75c8617a6c0", + "daa": 535, + "blue": 536, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 537, + "sink": "ec6ff75c8617a6c0", + "blue": 536, + "reorged": false + } + }, + { + "t": 517.4, + "h1": { + "blocks": 542, + "sink": "53152f1d8342a7ba", + "daa": 541, + "blue": 542, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 542, + "sink": "53152f1d8342a7ba", + "daa": 541, + "blue": 542, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 542, + "sink": "53152f1d8342a7ba", + "blue": 542, + "reorged": false + } + }, + { + "t": 522.4, + "h1": { + "blocks": 548, + "sink": "1425827f8f967320", + "daa": 547, + "blue": 548, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 548, + "sink": "1425827f8f967320", + "daa": 547, + "blue": 548, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 548, + "sink": "1425827f8f967320", + "blue": 548, + "reorged": false + } + }, + { + "t": 527.4, + "h1": { + "blocks": 554, + "sink": "12bc21c9e6549a42", + "daa": 553, + "blue": 554, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 554, + "sink": "12bc21c9e6549a42", + "daa": 553, + "blue": 554, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 554, + "sink": "12bc21c9e6549a42", + "blue": 554, + "reorged": false + } + }, + { + "t": 532.4, + "h1": { + "blocks": 559, + "sink": "b17be188847a071b", + "daa": 558, + "blue": 559, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 559, + "sink": "b17be188847a071b", + "daa": 558, + "blue": 559, + "key": "8da9ddee", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 559, + "sink": "b17be188847a071b", + "blue": 559, + "reorged": false + } + }, + { + "t": 537.4, + "h1": { + "blocks": 564, + "sink": "bcf3066ae7329fb1", + "daa": 563, + "blue": 564, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 564, + "sink": "bcf3066ae7329fb1", + "daa": 563, + "blue": 564, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 564, + "sink": "bcf3066ae7329fb1", + "blue": 564, + "reorged": false + } + }, + { + "t": 542.4, + "h1": { + "blocks": 571, + "sink": "3c8486f382c004a4", + "daa": 570, + "blue": 571, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 571, + "sink": "3c8486f382c004a4", + "daa": 570, + "blue": 571, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 571, + "sink": "3c8486f382c004a4", + "blue": 571, + "reorged": false + } + }, + { + "t": 547.4, + "h1": { + "blocks": 573, + "sink": "55eb5bc461792e81", + "daa": 572, + "blue": 573, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 573, + "sink": "55eb5bc461792e81", + "daa": 572, + "blue": 573, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 573, + "sink": "55eb5bc461792e81", + "blue": 573, + "reorged": false + } + }, + { + "t": 552.4, + "h1": { + "blocks": 577, + "sink": "c5812db6a85bdadb", + "daa": 576, + "blue": 577, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 577, + "sink": "c5812db6a85bdadb", + "daa": 576, + "blue": 577, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 577, + "sink": "c5812db6a85bdadb", + "blue": 577, + "reorged": false + } + }, + { + "t": 557.4, + "h1": { + "blocks": 579, + "sink": "a43cb662dec21b79", + "daa": 578, + "blue": 579, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 579, + "sink": "a43cb662dec21b79", + "daa": 578, + "blue": 579, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 579, + "sink": "a43cb662dec21b79", + "blue": 579, + "reorged": false + } + }, + { + "t": 562.4, + "h1": { + "blocks": 586, + "sink": "a5490f8482cfcac1", + "daa": 585, + "blue": 586, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 586, + "sink": "a5490f8482cfcac1", + "daa": 585, + "blue": 586, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 586, + "sink": "a5490f8482cfcac1", + "blue": 586, + "reorged": false + } + }, + { + "t": 567.5, + "h1": { + "blocks": 590, + "sink": "85ff280e3c193276", + "daa": 589, + "blue": 590, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 590, + "sink": "85ff280e3c193276", + "daa": 589, + "blue": 590, + "key": "eda9cde4", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 590, + "sink": "85ff280e3c193276", + "blue": 590, + "reorged": false + } + }, + { + "t": 572.5, + "h1": { + "blocks": 591, + "sink": "eb3dbbc60e30ebba", + "daa": 590, + "blue": 591, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "h2": { + "blocks": 591, + "sink": "eb3dbbc60e30ebba", + "daa": 590, + "blue": 591, + "key": "0e2c6fe2", + "reorged": true, + "knows_side2_tip": true + }, + "side2": { + "blocks": 591, + "sink": "eb3dbbc60e30ebba", + "blue": 591, + "reorged": false + } + } + ], + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 3, + "ports": { + "base": 30810, + "suffix": 983 + } +} diff --git a/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.log b/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.log new file mode 100644 index 00000000..72eac7f7 --- /dev/null +++ b/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.log @@ -0,0 +1,18 @@ +12:48:26.802 fg3 case third-gate-on-expect-reorg: mode third, gate on (window 60 DAA), joint 240 s, split 180 s, watch 150 s, honest 1 thread(s) each, attacker 3 (joint 2), expect reorg +12:48:28.386 fg3 h1 up pid 480989 json 30812 p2p 30811 +12:48:29.896 fg3 h2 up pid 482351 json 30822 p2p 30821 addpeer 30811 +12:48:31.410 fg3 b up pid 483327 json 30832 p2p 30831 addpeer 30841,30842 +12:52:34.426 fg3 phase 1 done at 240.0 s: H1 269 blocks sink 037edd2a daa 268; H2 269 sink 037edd2a; side 2 (b) 269 sink 037edd2a; keys H1 8da9ddee H2 eda9cde4 side2 0e2c6fe2 +12:52:34.451 fg3 weight at the fork (last 120 blue blocks of H1's chain): side 2 72, others 48, side 2 6000 bps +12:52:36.465 fg3 links cut at 242.1 s; side 2 (b) now mines with 3 thread(s), the honest side with 1 each +12:55:36.572 fg3 phase 2 done at 422.2 s: H1 426 blocks sink 06f666ba daa 425 blue 426 work 24628833; side 2 435 sink 71396cf7 daa 434 blue 435 work 28969222 (side 2 heavier: true); fork depth 166 DAA against window 60 +12:55:36.573 fg3 links restored at 422.2 s; watching H1 and H2 for 150 s +12:56:06.662 fg3 t=452.2 s H1 454 blocks sink feb2905b held; H2 454 blocks sink feb2905b held; side 2 464 blocks sink 09301449 +12:56:31.716 fg3 H1 left its pre-cut chain at 477.3 s: sink df2ecca49796b69c by 0e2c6fe2 +12:56:31.720 fg3 H2 left its pre-cut chain at 477.3 s: sink df2ecca49796b69c by 0e2c6fe2 +12:56:36.729 fg3 t=482.3 s H1 498 blocks sink 33ab64db REORGED; H2 498 blocks sink 33ab64db REORGED; side 2 498 blocks sink 33ab64db +12:57:06.776 fg3 t=512.4 s H1 537 blocks sink ec6ff75c REORGED; H2 537 blocks sink ec6ff75c REORGED; side 2 537 blocks sink ec6ff75c +12:57:36.826 fg3 t=542.4 s H1 571 blocks sink 3c8486f3 REORGED; H2 571 blocks sink 3c8486f3 REORGED; side 2 571 blocks sink 3c8486f3 +12:58:06.880 fg3 t=572.5 s H1 591 blocks sink eb3dbbc6 REORGED; H2 591 blocks sink eb3dbbc6 REORGED; side 2 591 blocks sink eb3dbbc6 +12:58:06.890 fg3 SUMMARY PASS (third-gate-on-expect-reorg): side 2 held 6000 bps of the blue blocks at the fork; fork depth 166 DAA against window 60; side 2 blue work 28969222 against H1 24628833 at the heal; H1 reorged at 477.3 s (0 refusal lines, knows side 2's tip: true); H2 reorged at 477.3 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true +12:58:06.890 fg3 summary: /srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.json diff --git a/docs/plans/mission-item-4-gate/summary.json b/docs/plans/mission-item-4-gate/summary.json new file mode 100644 index 00000000..3ee33a51 --- /dev/null +++ b/docs/plans/mission-item-4-gate/summary.json @@ -0,0 +1,796 @@ +{ + "green": true, + "at": "2026-10-07T12:58:08.407Z", + "heal_unchanged": true, + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "cases": [ + { + "mode": "attack", + "gate": "off", + "expect": "reorg", + "must": "PASS", + "line": "the rule's known-failed case: without the gate a fresh key's heavier deep fork wins on every honest node", + "slot": 0, + "name": "attack-gate-off-expect-reorg", + "verdict": "PASS", + "as_it_must": true, + "secs": 581, + "exit": 0, + "summary_line": "SUMMARY PASS (attack-gate-off-expect-reorg): side 2 held 0 bps of the blue blocks at the fork; fork depth 191 DAA against window 60; side 2 blue work 17470131 against H1 14893198 at the heal; H1 reorged at 510.4 s (0 refusal lines, knows side 2's tip: true); H2 reorged at 510.4 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true", + "summary": { + "pass": true, + "expect": "reorg", + "case": "attack-gate-off-expect-reorg", + "mode": "attack", + "gate": "off", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 0 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 0, + "others": 120, + "side2_bps": 0 + }, + "fork_daa": 240, + "fork_depth_daa_at_heal": 191, + "sinks": { + "joint": { + "h1": { + "hash": "e66998c63f8f5d2f3f9108a5c61730f3d5ee06a0553f47e3bce314a0e4d7228e", + "blocks": 242, + "daa": 240, + "blue": 241, + "blueWork": "8689541", + "key": "8da9ddee…" + }, + "h2": { + "hash": "e66998c63f8f5d2f3f9108a5c61730f3d5ee06a0553f47e3bce314a0e4d7228e", + "blocks": 242, + "daa": 240, + "blue": 241, + "blueWork": "8689541", + "key": "8da9ddee…" + }, + "side2": { + "hash": "e66998c63f8f5d2f3f9108a5c61730f3d5ee06a0553f47e3bce314a0e4d7228e", + "blocks": 242, + "daa": 240, + "blue": 241, + "blueWork": "8689541", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "6e932c389f2ad01a39873317f9549f0a336e66a7c840669dd5bcb44a979a19ad", + "blocks": 421, + "daa": 420, + "blue": 421, + "blueWork": "14893198", + "key": "8da9ddee…" + }, + "h2": { + "hash": "6e932c389f2ad01a39873317f9549f0a336e66a7c840669dd5bcb44a979a19ad", + "blocks": 421, + "daa": 420, + "blue": 421, + "blueWork": "14893198", + "key": "8da9ddee…" + }, + "side2": { + "hash": "d93a1238a397f68337f4bc28d6197a61a32fbca176f3e7f4248b6b330e239cc8", + "blocks": 432, + "daa": 431, + "blue": 432, + "blueWork": "17470131", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 510.4, + "knows_side2_tip": true, + "refusal_lines": 0 + }, + "h2": { + "held": false, + "reorged": true, + "reorg_at_s": 510.4, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": true, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 0, + "ports": { + "base": 30690, + "suffix": 980 + } + }, + "log": "/srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-reorg.log" + }, + { + "mode": "attack", + "gate": "off", + "expect": "hold", + "must": "FAIL", + "line": "the harness's own failed shape: with the gate off it must not report a hold", + "slot": 1, + "name": "attack-gate-off-expect-hold", + "verdict": "FAIL", + "as_it_must": true, + "secs": 581, + "exit": 1, + "summary_line": "SUMMARY FAIL (attack-gate-off-expect-hold): side 2 held 0 bps of the blue blocks at the fork; fork depth 179 DAA against window 60; side 2 blue work 19683187 against H1 17459678 at the heal; H1 reorged at 480.3 s (0 refusal lines, knows side 2's tip: true); H2 reorged at 480.3 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true; FAILED CHECK every_honest_node_held, every_honest_node_logged_a_refusal", + "summary": { + "pass": false, + "expect": "hold", + "case": "attack-gate-off-expect-hold", + "mode": "attack", + "gate": "off", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 0 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 0, + "others": 120, + "side2_bps": 0 + }, + "fork_daa": 247, + "fork_depth_daa_at_heal": 179, + "sinks": { + "joint": { + "h1": { + "hash": "0535d8ae67287238ee528bae5ab1f366273bd1c65c6a94342ec3879a40b81c88", + "blocks": 248, + "daa": 247, + "blue": 248, + "blueWork": "11209205", + "key": "8da9ddee…" + }, + "h2": { + "hash": "0535d8ae67287238ee528bae5ab1f366273bd1c65c6a94342ec3879a40b81c88", + "blocks": 248, + "daa": 247, + "blue": 248, + "blueWork": "11209205", + "key": "8da9ddee…" + }, + "side2": { + "hash": "0535d8ae67287238ee528bae5ab1f366273bd1c65c6a94342ec3879a40b81c88", + "blocks": 248, + "daa": 247, + "blue": 248, + "blueWork": "11209205", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "d5347d2cd3468901fda8e5a1caffe0be55d45eb12739577fadb0141d2291c2ba", + "blocks": 412, + "daa": 411, + "blue": 412, + "blueWork": "17459678", + "key": "8da9ddee…" + }, + "h2": { + "hash": "d5347d2cd3468901fda8e5a1caffe0be55d45eb12739577fadb0141d2291c2ba", + "blocks": 412, + "daa": 411, + "blue": 412, + "blueWork": "17459678", + "key": "8da9ddee…" + }, + "side2": { + "hash": "bfdb75e384417228a85f4098f8f2bb65d40c271ce674bea2d1cc8a3c6c335f53", + "blocks": 427, + "daa": 426, + "blue": 427, + "blueWork": "19683187", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 480.3, + "knows_side2_tip": true, + "refusal_lines": 0 + }, + "h2": { + "held": false, + "reorged": true, + "reorg_at_s": 480.3, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": true, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [ + "every_honest_node_held", + "every_honest_node_logged_a_refusal" + ], + "refusal_example": null, + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 1, + "ports": { + "base": 30730, + "suffix": 981 + } + }, + "log": "/srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-attack-gate-off-expect-hold.log" + }, + { + "mode": "attack", + "gate": "on", + "expect": "hold", + "must": "PASS", + "line": "the gate line: a fresh-key fork from three windows back, heavier by blue work, refused by every honest node", + "slot": 2, + "name": "attack-gate-on-expect-hold", + "verdict": "PASS", + "as_it_must": true, + "secs": 581, + "exit": 0, + "summary_line": "SUMMARY PASS (attack-gate-on-expect-hold): side 2 held 0 bps of the blue blocks at the fork; fork depth 197 DAA against window 60; side 2 blue work 20297242 against H1 14807915 at the heal; H1 held (177 refusal lines, knows side 2's tip: true); H2 held (177 refusal lines, knows side 2's tip: true); side 2 kept its chain: true", + "summary": { + "pass": true, + "expect": "hold", + "case": "attack-gate-on-expect-hold", + "mode": "attack", + "gate": "on", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 0 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 0, + "others": 121, + "side2_bps": 0 + }, + "fork_daa": 233, + "fork_depth_daa_at_heal": 197, + "sinks": { + "joint": { + "h1": { + "hash": "7ed68743f22e711490406bd380cf66fff94579fcc981344c317a46c18cbc61bb", + "blocks": 234, + "daa": 233, + "blue": 234, + "blueWork": "8862250", + "key": "eda9cde4…" + }, + "h2": { + "hash": "7ed68743f22e711490406bd380cf66fff94579fcc981344c317a46c18cbc61bb", + "blocks": 234, + "daa": 233, + "blue": 234, + "blueWork": "8862250", + "key": "eda9cde4…" + }, + "side2": { + "hash": "7ed68743f22e711490406bd380cf66fff94579fcc981344c317a46c18cbc61bb", + "blocks": 234, + "daa": 233, + "blue": 234, + "blueWork": "8862250", + "key": "eda9cde4…" + } + }, + "split": { + "h1": { + "hash": "036cfe568f3d403351b338ea41b7069ad4eae0ce95308436a25b6c7aa4c1372a", + "blocks": 396, + "daa": 395, + "blue": 396, + "blueWork": "14807915", + "key": "8da9ddee…" + }, + "h2": { + "hash": "036cfe568f3d403351b338ea41b7069ad4eae0ce95308436a25b6c7aa4c1372a", + "blocks": 396, + "daa": 395, + "blue": 396, + "blueWork": "14807915", + "key": "8da9ddee…" + }, + "side2": { + "hash": "abb93c2318f6c2ebdbd4e14a50b3d73ba7f483b8b06b18666e1015d038d4011a", + "blocks": 431, + "daa": 430, + "blue": 431, + "blueWork": "20297242", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": true, + "reorged": false, + "reorg_at_s": null, + "knows_side2_tip": true, + "refusal_lines": 177 + }, + "h2": { + "held": true, + "reorged": false, + "reorg_at_s": null, + "knows_side2_tip": true, + "refusal_lines": 177 + } + }, + "checks": { + "side2_under_a_third_at_fork": true, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": true, + "every_honest_node_reorged": false, + "every_honest_node_logged_a_refusal": true, + "no_honest_node_logged_a_refusal": false, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": "Fork choice: block 41225a00fb38b6394540a5707443bd70e678484cbd20aa3fa8e807bb24df8d4a forks 252 DAA back from the sink's chain and its builders hold 0.00% of the weight table at the fork (under one third); not a sink candidate (ledger 51-percent rank 2)", + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 2, + "ports": { + "base": 30770, + "suffix": 982 + } + }, + "log": "/srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-attack-gate-on-expect-hold.log" + }, + { + "mode": "third", + "gate": "on", + "expect": "reorg", + "must": "PASS", + "line": "a fork whose builder holds at least a third of the table at the fork is accepted", + "slot": 3, + "name": "third-gate-on-expect-reorg", + "verdict": "PASS", + "as_it_must": true, + "secs": 583, + "exit": 0, + "summary_line": "SUMMARY PASS (third-gate-on-expect-reorg): side 2 held 6000 bps of the blue blocks at the fork; fork depth 166 DAA against window 60; side 2 blue work 28969222 against H1 24628833 at the heal; H1 reorged at 477.3 s (0 refusal lines, knows side 2's tip: true); H2 reorged at 477.3 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true", + "summary": { + "pass": true, + "expect": "reorg", + "case": "third-gate-on-expect-reorg", + "mode": "third", + "gate": "on", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 2 + }, + "keys": { + "h1": "8da9ddee…", + "h2": "eda9cde4…", + "side2": "0e2c6fe2…" + }, + "share_at_fork": { + "side2": 72, + "others": 48, + "side2_bps": 6000 + }, + "fork_daa": 268, + "fork_depth_daa_at_heal": 166, + "sinks": { + "joint": { + "h1": { + "hash": "037edd2a2976af7aec3f6b00d0532706f2c4bc48a2ace2d4e92f027492aa42af", + "blocks": 269, + "daa": 268, + "blue": 269, + "blueWork": "17483286", + "key": "0e2c6fe2…" + }, + "h2": { + "hash": "037edd2a2976af7aec3f6b00d0532706f2c4bc48a2ace2d4e92f027492aa42af", + "blocks": 269, + "daa": 268, + "blue": 269, + "blueWork": "17483286", + "key": "0e2c6fe2…" + }, + "side2": { + "hash": "037edd2a2976af7aec3f6b00d0532706f2c4bc48a2ace2d4e92f027492aa42af", + "blocks": 269, + "daa": 268, + "blue": 269, + "blueWork": "17483286", + "key": "0e2c6fe2…" + } + }, + "split": { + "h1": { + "hash": "06f666ba3c449f2fab804e75612a00c748a8d56568806c30a7006aae175bb27d", + "blocks": 426, + "daa": 425, + "blue": 426, + "blueWork": "24628833", + "key": "8da9ddee…" + }, + "h2": { + "hash": "06f666ba3c449f2fab804e75612a00c748a8d56568806c30a7006aae175bb27d", + "blocks": 426, + "daa": 425, + "blue": 426, + "blueWork": "24628833", + "key": "8da9ddee…" + }, + "side2": { + "hash": "71396cf73521295ad0fbeb320de980989ea0788dbc859129d8972a9e091e0a3c", + "blocks": 435, + "daa": 434, + "blue": 435, + "blueWork": "28969222", + "key": "0e2c6fe2…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 477.3, + "knows_side2_tip": true, + "refusal_lines": 0 + }, + "h2": { + "held": false, + "reorged": true, + "reorg_at_s": 477.3, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": false, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 3, + "ports": { + "base": 30810, + "suffix": 983 + } + }, + "log": "/srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-third-gate-on-expect-reorg.log" + }, + { + "mode": "partition", + "gate": "on", + "expect": "reorg", + "must": "PASS", + "line": "partition heal with the gate on: the heavier side wins", + "slot": 4, + "name": "partition-gate-on-expect-reorg", + "verdict": "PASS", + "as_it_must": true, + "secs": 581, + "exit": 0, + "summary_line": "SUMMARY PASS (partition-gate-on-expect-reorg): side 2 held 3719 bps of the blue blocks at the fork; fork depth 194 DAA against window 60; side 2 blue work 18089683 against H1 11490863 at the heal; H1 reorged at 507.4 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true", + "summary": { + "pass": true, + "expect": "reorg", + "case": "partition-gate-on-expect-reorg", + "mode": "partition", + "gate": "on", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 1 + }, + "keys": { + "h1": "8da9ddee…", + "h2": null, + "side2": "eda9cde4…" + }, + "share_at_fork": { + "side2": 45, + "others": 76, + "side2_bps": 3719 + }, + "fork_daa": 245, + "fork_depth_daa_at_heal": 194, + "sinks": { + "joint": { + "h1": { + "hash": "5c4cb584dc015892ddff89337412ed0883d9f97b4e791e7af2f7f64764f4f1e8", + "blocks": 246, + "daa": 245, + "blue": 246, + "blueWork": "8723556", + "key": "8da9ddee…" + }, + "h2": { + "hash": "5c4cb584dc015892ddff89337412ed0883d9f97b4e791e7af2f7f64764f4f1e8", + "blocks": 246, + "daa": 245, + "blue": 246, + "blueWork": "8723556", + "key": "8da9ddee…" + }, + "side2": { + "hash": "5c4cb584dc015892ddff89337412ed0883d9f97b4e791e7af2f7f64764f4f1e8", + "blocks": 246, + "daa": 245, + "blue": 246, + "blueWork": "8723556", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "753507c15705f4ea8ed19bc2697a11c489a052a45f28c64f9ac3d8400fa66647", + "blocks": 412, + "daa": 411, + "blue": 412, + "blueWork": "11490863", + "key": "8da9ddee…" + }, + "h2": { + "hash": "32b7c1757fa288eed0a8ab709e49fd86f72be531db19c58e63d0aeca7a34c4f6", + "blocks": 440, + "daa": 439, + "blue": 440, + "blueWork": "18089683", + "key": "eda9cde4…" + }, + "side2": { + "hash": "32b7c1757fa288eed0a8ab709e49fd86f72be531db19c58e63d0aeca7a34c4f6", + "blocks": 440, + "daa": 439, + "blue": 440, + "blueWork": "18089683", + "key": "eda9cde4…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 507.4, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": false, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 4, + "ports": { + "base": 30850, + "suffix": 984 + } + }, + "log": "/srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-partition-gate-on-expect-reorg.log" + }, + { + "mode": "partition", + "gate": "off", + "expect": "reorg", + "must": "PASS", + "line": "partition heal with the gate off: the same outcome, so the heal is unchanged", + "slot": 5, + "name": "partition-gate-off-expect-reorg", + "verdict": "PASS", + "as_it_must": true, + "secs": 581, + "exit": 0, + "summary_line": "SUMMARY PASS (partition-gate-off-expect-reorg): side 2 held 5583 bps of the blue blocks at the fork; fork depth 191 DAA against window 60; side 2 blue work 19576159 against H1 12270631 at the heal; H1 reorged at 507.4 s (0 refusal lines, knows side 2's tip: true); side 2 kept its chain: true", + "summary": { + "pass": true, + "expect": "reorg", + "case": "partition-gate-off-expect-reorg", + "mode": "partition", + "gate": "off", + "window": 60, + "joint": 240, + "split": 180, + "watch": 150, + "threads": { + "honest_each": 1, + "attacker_split": 3, + "attacker_joint": 1 + }, + "keys": { + "h1": "8da9ddee…", + "h2": null, + "side2": "eda9cde4…" + }, + "share_at_fork": { + "side2": 67, + "others": 53, + "side2_bps": 5583 + }, + "fork_daa": 244, + "fork_depth_daa_at_heal": 191, + "sinks": { + "joint": { + "h1": { + "hash": "58126c351aa6324a992a47fa66cca22369450c9835d312772c87d3e1aeb409a0", + "blocks": 245, + "daa": 244, + "blue": 245, + "blueWork": "9558440", + "key": "8da9ddee…" + }, + "h2": { + "hash": "58126c351aa6324a992a47fa66cca22369450c9835d312772c87d3e1aeb409a0", + "blocks": 245, + "daa": 244, + "blue": 245, + "blueWork": "9558440", + "key": "8da9ddee…" + }, + "side2": { + "hash": "58126c351aa6324a992a47fa66cca22369450c9835d312772c87d3e1aeb409a0", + "blocks": 245, + "daa": 244, + "blue": 245, + "blueWork": "9558440", + "key": "8da9ddee…" + } + }, + "split": { + "h1": { + "hash": "a27a341c694aacf22b1a78f44d433e4104f58b23533afb73b7ee6fb9aa37afe4", + "blocks": 405, + "daa": 404, + "blue": 405, + "blueWork": "12270631", + "key": "8da9ddee…" + }, + "h2": { + "hash": "f9181a06c0db716fe4ed200f6f0046c9cb8fae2eb57dd7da4697a268c434a232", + "blocks": 436, + "daa": 435, + "blue": 436, + "blueWork": "19576159", + "key": "eda9cde4…" + }, + "side2": { + "hash": "f9181a06c0db716fe4ed200f6f0046c9cb8fae2eb57dd7da4697a268c434a232", + "blocks": 436, + "daa": 435, + "blue": 436, + "blueWork": "19576159", + "key": "eda9cde4…" + } + } + }, + "per_node": { + "h1": { + "held": false, + "reorged": true, + "reorg_at_s": 507.4, + "knows_side2_tip": true, + "refusal_lines": 0 + } + }, + "checks": { + "side2_under_a_third_at_fork": false, + "fork_deeper_than_window": true, + "side2_heavier_at_heal": true, + "every_honest_node_learned_side2_chain": true, + "every_honest_node_held": false, + "every_honest_node_reorged": true, + "every_honest_node_logged_a_refusal": false, + "no_honest_node_logged_a_refusal": true, + "side2_kept_its_chain": true + }, + "failed_checks": [], + "refusal_example": null, + "node": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneumd", + "miner": "/srv/builds/igneum-wt-horizon/vendor/igneum-node-horizon/target/release/igneum-miner", + "slot": 5, + "ports": { + "base": 30890, + "suffix": 985 + } + }, + "log": "/srv/builds/igneum-wt-horizon/docs/plans/mission-item-4-gate/fork-gate-partition-gate-off-expect-reorg.log" + } + ] +} diff --git a/docs/plans/relay-deploy-2026-10-07.md b/docs/plans/relay-deploy-2026-10-07.md new file mode 100644 index 00000000..fdebbac5 --- /dev/null +++ b/docs/plans/relay-deploy-2026-10-07.md @@ -0,0 +1,16 @@ +# Relay deploy, 7 October 2026 (the X23 tree, MF-11) + +| What | Value | +|---|---| +| Deployed | 2026-10-07 15:38 BST, from branch update-return bd9b4f4e, relay/ | +| Production deployment | https://igneum-relay-iabqarnby-igneum.vercel.app (inspect KHyscUSVKueXueqxvZBRKkaUHwJR), aliased https://relay.igneum.network | +| Previous production | https://igneum-relay-bgy767z40-igneum.vercel.app | +| Env added | RELAY_RUN_PUB (the public half of ~/.config/igneum/relay-run-key, made by `node tools/relay.mjs keygen` the same hour); RELAY_INTAKE_COMPAT unset | +| Read-backs | /wake answers; fn=machines carries the bound field; the console page answers 200 and c/machines carries poll fields; a v1-shaped register by hostname (key tier) answers named:false bound:false; a signed start-app from the Mac answers 200 (item 394); an unsigned run from master's old tool is refused | + +## Rollback + +`cd relay && npx --yes vercel@latest --global-config ~/.config/igneum/vercel --scope igneum rollback https://igneum-relay-bgy767z40-igneum.vercel.app` +(or `vercel promote https://igneum-relay-bgy767z40-igneum.vercel.app`). Seconds; nothing to undo in the database: the X23 code adds relay_machines.secret_hash and the +table relay_wake_seen, both ignored by the old code. What a rollback loses: signed run verification (the old relay never +had it), the start-app kind, the ping; PC 2's new agent registers by hostname on either. diff --git a/docs/plans/release-0.3.20.md b/docs/plans/release-0.3.20.md new file mode 100644 index 00000000..07e94ebc --- /dev/null +++ b/docs/plans/release-0.3.20.md @@ -0,0 +1,555 @@ +# Igneum Miner 0.3.17: the 0.3.17 tree as cut on 7 October 2026 + +The hourly cut after 0.3.16, under the coordinator's rule: every new switch at never on the devnet so the digest does not move; cut what is green and list what waited. Worktree `igneum-wt-ship0317` (release-0.3.17 from release-0.3.15 a9eb58f1), node `release-0.3.17-node` in `vendor/igneum-node-0317` (from f1ea7a38). + +> Renumbered 7 October 2026, 03:3xZ (main): the tree this plan describes is **0.3.18**. Its canary on 12153428 failed on two further faults (the idle-peer guard closes every peer mid headers-proof IBD; a window-below-epoch log flood at 1,900 lines a minute), and tonight's **0.3.17** became the node-only hotfix on the 0.3.16 app tree (f1ea7a38 plus 90aaf38e = b3c228fa; see docs/plans/release-0.3.17.md on release-0.3.17). The version scheme is three-part everywhere, so "0.3.16.1" was not available. Rows below keep "0.3.17" where they were written; read it as this tree. Branches: release-0.3.18 (app), release-0.3.18-node (fork, 12153428). Decimals is 0.3.19. + +> Renumbered again 7 October 2026, 08:2xZ (main): this feature tree is **0.3.19**; **0.3.18** is the app-only cut on the 0.3.17 tree (the engine's clock sample gated on igneum_getExecStatus, ledger N7; docs/plans/release-0.3.18.md on release-0.3.18-app); decimals is 0.3.20. Branches now: release-0.3.19 (app), release-0.3.19-node (fork, the mirror). Rows below keep the "0.3.18" they were written with; read it as this tree. + +> Renumbered a third time, 7 October 2026 10:4x UK (main): this feature tree is **0.3.20** (the dc141409 line plus the class v4 amendment, option A on AP-F8-1, and the proof archive; its canary gate as ordered). **0.3.19** is an app-only cut on the 0.3.18 app tree plus miner-ui-5 on the node pin 5899f603 (docs/plans/release-0.3.19.md on release-0.3.19). Branches: release-0.3.20 (app), release-0.3.20-node (fork, the mirror). Rows below keep the numbers they were written with. + +## 1. The node tree + +| Branch | Tip | In 0.3.17 | Why | +|---|---|---|---| +| ca3-v4-0316 (node lane) | 9a44fcb8 (df787727 the last functional commit: igneum_getNodeInfo; the miner stall guard e6e1fbe2 with exit 45, the idle-peer drop 96619b7d) | yes | the unwrap class, the seven-window rule, the finality cause fields, igneum_getRecentBlocks, difficulty rule v3, the fork gate, vote-or-burn, the signing bonus, the miner's stall exit (every switch absent from the live object = never) | +| ladder-node (ladder lane) | 1591ee1d | yes | the latency ladder behind latency_ladder_activation_daa (never); the receive gate reads header_signals_active (the lane's merge note, applied as c6e12005's parent commit) | +| exec-sync-0313 (proving lane) | 40fd8d8c | yes (merged last, 02d15a87; params.rs both sides kept) | consensus proof verification behind proving_consensus_verify_daa (never), the override's program ids as the statement's ids, sp1 as cfg(not(windows)) dependencies with the host-backed verify on Windows (the first merge of a344fea3 broke the Windows cross-build in sp1-jit; 40fd8d8c fixed it) | +| finality-pause-node-0317 (finality lane) | fdc71bb5, rebased | yes (cherry-picked as d8d1de1a onto the exec-free base) | W7 the departure announcement behind finality_leave_activation_daa (never on the devnet; 0 and leave_delay 3600 in the testnet genesis per the project lead); protocol 17; the devnet digest unchanged by test | +| tail-emission-node-0317 (economy lane) | 5647533f, rebased | yes (cherry-picked as 996b592f, its params hunks without exec-sync's proving fields) | its coinbase table replaces the subsidy table the silence rules build on; the rebase resolves it; no digest move while CURRENT | +| kaspad igneum-pow default feature | 75467244 | yes | the node lane's N5 finding: a bare `cargo build -p kaspad` validated PoW with the kHeavyHash stub; every box reads igneum_getNodeInfo's powEngine "igneum-pow" in the table, "stub" is a FAIL | +| kaspa-testing-integration | cc78a21f | fixed here | compiles again (the block store's evm argument, Header's vote_key_hash, the Params const as a let, the four finality ops in the RPC sanity match); the box suite is to compile every test crate from here | + +Final node tree 02d15a87 (75467244 + exec-sync-0313 40fd8d8c). Digests on the exec-free tree c6e12005 (Mac binary, direct run): the live sixteen-field object eada4bda (unchanged), the thirteen-field file b18ed271, no file c562d70e. A harness note: scratchpad digest.sh printed the no-file digest for a file that reads eada4bda while other nodes held its ports; it now says UNTRUSTED when the override lines are missing. + +## 2. The app tree + +| Branch | Tip | In 0.3.17 | +|---|---|---| +| ladder (repo side) | 7003f9f | yes (igneum-pow's chain_program_shadow, which the fork's kaspa-pow needs) | +| exec-app-0314 | 032f03c | yes (clean; docs as the union) | +| relay | 28c028b | yes (ci.yml on the release side) | +| ember-tune-0317 (rebased on a9eb58f1) | bb37c993 | yes: the release lines kept (job_active, install_asked, the stale-exporter line), live.rs one merged module, publish-manifest.sh Ember's guard | +| miner-ui-4 (rebased on a9eb58f1) | afc331bd | yes: ui/ whole with Ember's finality words, extnode.rs on igneum_getNodeInfo, N4 stall exits, the port-collision check, POST /api/shot, an external node that goes away hands the ports to the app after 60 s; src/live.rs stays Ember's | +| proving-v2 | d8055a7 | NO (its exec content is in c00e608; its extra is the proof-system v2 slot, its own cut, per its owner) | + +App tests on the merged tree: 175 + 28 + 8; UI 41. A whole-file take of a lane's branch on an older base dropped the release tree's own fixes (seen and reverted): the lanes rebase onto the release tree and resolve there; the shipper merges, never substitutes files. + +## 2a. Linux binaries by glibc (main's rule, 7 October 2026, 01:3x UK) + +HiveOS images are Ubuntu 20.04 (glibc 2.31); the canary pods on 22.04 (2.35) refused the box's binaries. From now: the HiveOS package carries the 2.31 zig build (the build-server lane produces and container-tests it; the 0.3.17 HiveOS row stays at 0.3.16 in the index until that package lands, then joins with its own read-back); seeds and generic Linux binaries are the 2.35 build; the fleet's own boxes (Ubuntu 24.04) take the box's native build. The Mac and Windows rows publish on their gates. + +## 2b. Checklist line for every cut (the node lane, 7 October 2026) + +`cargo check -p kaspa-testing-integration --tests` runs in the box suite of every cut and in the fork's CI (the crate had not compiled since the finality fields landed; no integration test ran on any cut until this one). The 0.3.17 box chain carries it as its last step (rebuild-on-fix.sh step_box / the node chain's "integration check"). 0.3.18 node notes: relay pipelining bb397f99 and the sync-request fuzz gate 6cf33d36 on ca3-v4-0318; aa0182aa and 812c3ac2 from ca3-v4-0316. + +## 2c. A kill matches a pid, never a name (main's row, 7 October 2026, 01:xx UK) + +My `pkill -f build-remote.sh` at 00:17 UK (to stop my own chained box builds before a rerun) killed the decimals lane's box run on the same Mac: the pattern matched every build-remote.sh, not mine. Rule: every kill in the ship tooling matches a pid file or the exact command line (the run's log path, the worktree path), never a tool's name; the ship scripts run through tools/ci/pre-push.sh's kill-by-name check before the next cut. Tonight's scratch runbooks hold no pkill by tool name any more (the chains are started with their log path in the command and stopped by that path). + +## 2d. The canary's FAIL (01:37Z): the IBD guard refuses signal-version relay blocks + +c17-1 (02d15a87, the live sixteen-field object) could not join: "IBD with headers proof from was unsuccessful (peer relayed block ... header version mismatch: got 1026, expected 2 at DAA score 237583)", 483 lines in 15 minutes against all four peers, peers 0, blocks 0. Cause: protocol/flows/src/ibd/flow.rs:390 (upstream's Toccata guard, f94053a0) compares the syncer's relay-block version with the plain block version before the pruning proof; under the open window the sink carries legal 1026 signal blocks. The line is on f1ea7a38 too, so the LIVE devnet has refused every fresh join (the headers-proof IBD path) since publish 2 opened the window at 22:43Z; tonight's moves passed because every node had a datadir (the relay path) or began its IBD before the hub moved. Fix (node lane): the comparison gated like the pre-ghostdag rule (block_version_of under header_signals_active), known-failed test first; main decides between 0.3.17 carrying it and a 0.3.16.1 node hotfix. Checklist line from here: the canary's target is a FRESH node joining the LIVE object's chain, which carries signal headers once a window is open; the pre-cut harness (node-compat.mjs) gets a chain with signal-version headers under an open window. + +## 2e. The rebuild on the fix (7 October 2026, 02:3x to 02:4x Z) + +The node lane's IBD-guard fix (ca3-v4-0317-fix 90aaf38e) merged into release-0.3.17-node as 12153428. Every binary rebuilt on it: + +| piece | commit string | sha256 (first 8) | bytes | +|---|---|---|---| +| Linux igneumd, box native (glibc 2.39, the fleet's canary sha) | 12153428 | 5a4a0d68 | 57,347,232 | +| Windows igneumd.exe (cross, box) | 12153428 | 1e0b49ef | 52,367,360 | +| Windows igneum-miner.exe | 12153428 | 7ca9ca01 | | +| Mac igneumd (Apple Silicon) | 12153428 | 7416d4a5 | 47,837,248 | +| Igneum-Miner-0.3.17.dmg (packaged object = the live sixteen-field object, prover pair aboard) | | 916248b8 | 44,244,489 | +| HiveOS igneumd (zig, glibc 2.31) | 12153428 | 378340e4 | 56,022,096 | +| igneum-hive-0.3.17.tar.gz (2.31 node pair + the box's CUDA/OpenCL workers) | | 04fb7d45 | 27,193,392 | + +Suite on 12153428: green (two load flakes pass alone), `cargo check -p kaspa-testing-integration --tests` rc 0. Digests read directly from the rebuilt node: sixteen-field eada4bda (igneum_getNodeInfo powEngine igneum-pow), thirteen-field b18ed271, no file c562d70e: unchanged from 0.3.16. + +Windows inputs pushed 02:37Z (igneumd.exe 1e0b49ef, workers d7a413c7, 6f4bb57f, 0d68d06e, the Linux prover pair), pin b5a16f5b on release-0.3.17, windows.yml run 37562948420 dispatched 02:38Z. + +HiveOS 2.31 smoke in an ubuntu:20.04 container on igneum-build-1 (ldd 2.31): igneumd, igneum-miner, igneum-worker-cuda and igneum-worker-opencl all load and answer. Found on the way: GNU tar materialises the Mac's extended headers as `._` files beside every file in the package (the live 0.3.16 tar has twelve of them; harmless, HiveOS ran it). Fixed in make-hive-package.sh (COPYFILE_DISABLE, no Mac metadata, c5187a70); the 0.3.17 tar extracts clean (10 files, 0 `._`). + +The scratch staging copy (`r0317/dlsite-stage`) had the superseded DMG d25ab372 and installer d1065ac0 removed; the manifest is re-written there once the Windows run's installer is fetched. The live downloads folder holds no 0.3.17 file until the deploy step, which waits on the fleet's second canary line. + +## 2f. Ready at the line (7 October 2026, 02:5x Z) + +- Windows: run 37562948420 green (engine, window host, payload, installer, smoke run), Igneum-Miner-Setup-0.3.17.exe 93e29580, 62,814,273 bytes, fetched into the scratch copy. The scratch manifests (token folder and public) read: version 0.3.17, mac 916248b8, windows 93e29580, consensus.override = the live sixteen-field object (floor 831,600, window 86,400), HiveOS alias held at 0.3.16 until its own row. +- The deploy runbook is `scratchpad/r0317/deploy.sh` (step_preflight, step_manifest = the live folder written and deployed in one step with the same inputs, step_update_now for d937c69d, ae432dc7 and 1ccfe586, step_hive, step_readback). It runs only on the fleet's second canary line. +- Hands and seed: the build-server lane builds the seed's 2.35 pair and the hands' native pair on 12153428 and restarts them LAST on my line (observer, node 1, then the seed), each read back by commit string, digest and powEngine. +- The Discord card is dry-run at `tools/community/out/release_0.3.17.json` (four reader-facing change lines, no em dash); it posts only once the HiveOS row is live, since the card carries every platform. +- The 0.3.16.1 fallback (main's rule: if the retry fails off the IBD-guard fix) is prepared and not pushed: scratch worktree `r0317/fallback-03161-node`, branch release-0.3.16.1-node at b3c228fa = f1ea7a38 plus a hand-port of 90aaf38e (the helper gates on class_signal_active() alone, since f1ea7a38 has no ladder; the ladder assert dropped from the test). `cargo check` on consensus-core, consensus and p2p-flows clean, the unit test green. The node lane confirms it is the same adaptation it made for its 0318 tree (f2b25fdf). +- The node lane's two-daemon window test (10226194 on the fix branch, separable, touches only testing/integration) is NOT in 0.3.17's pin; run on the box against 12153428 plus the commit (worktree vendor/igneum-node-twodaemon, so the path igneum-pow resolves): `a_fresh_node_joins_a_chain_of_signalling_headers_and_no_window_refuses_them ... ok`, 11.46 s, 03:01Z. It rides the next tree. +- Pairing rule (the build-server lane, 02:5xZ): a fork build takes igneum-pow by path from the igneum worktree it sits in; a fork worktree under a master checkout fails in kaspa-pow (`chain_program_shadow` missing). 0.3.17's artefacts paired with release-0.3.17 at a73e400c to 6f8d7a7e, whose igneum-pow is unchanged since 6b30e855. The tool logs the pairing from the next master. + +## 3. Owed + +- exec-sync-0313's consensus verification behind a feature off for Windows (the proving lane), then its two commits. +- finality-pause-node rebased onto the 0.3.17 node (the finality lane). +- decimals (B10 gate), vote-weigh and tail-emission docs: the next cut. +- The fork gate's fast-time line is GREEN on aa0182aa (gate on: a 27.5 percent key's private chain 183 DAA deep refused, 268 refusal lines, the honest node kept its chain; gate off, the known-failed case reorgs), one commit past the 9a44fcb8 this tree carries; the switch is at never on every network, so 9a44fcb8 stands for 0.3.17 (the chains were building) and aa0182aa rides 0.3.18. vote-or-burn and the signing bonus: the replay gate FAILED on 9a44fcb8 (this tree) and PASSES on 812c3ac2 (the silence read as a function of the block's own past), which rides 0.3.18 with aa0182aa; both switches are at never here, so a devnet node behaves the same; the signing bonus is settable at the testnet genesis on the project lead's word, the devnet not a candidate until the longer-span replay passes. +- The canary in the full form before publish (a new node mining beside an old one with a poisoned peer, ten minutes, a mid-window re-sync), the staged-in-scratch rule, every new switch at never. + +## 4. For the 0.3.18 tree (not in 0.3.17) + +- miner-ui-4 past afc331bd: 74c12665 (the merge check: a node whose blocks never merge reads "behind" and the miner is held; src/merge.rs, observer poll, one UI line; 172 box + 42 UI tests green). The UI lane's word, 03:2xZ. +- ca3-v4-0317-fix 10226194: the two-daemon window test (green on 12153428 plus the commit, 03:01Z). +- The node lane's ca3-v4-0318 tree (98c78d9a, f2b25fdf). +- The build-server lane's pairing log line in build-remote.sh (which igneum-pow a fork build paired with). + +## 5. The 0.3.18 cut after the hotfix (main's order, 7 October 2026, 03:5xZ) + +Once "0.3.17 live" (the hotfix) is read back: rebuild release-0.3.18-node on 12153428 plus the node lane's 4f4bb9c9 (ca3-v4-0317-fix: the idle-peer drop counts headers, proof, trusted data and UTXO chunks as deliveries and never fires during a sync; the class-signal missing-history warning once per epoch per process; kaspa-p2p-lib 20, kaspa-p2p-flows 35, class_signal 1 green on the box; the same patch onto ca3-v4-0318 by 05:15 UK), every platform, digests unchanged, suites, the integration check, the window test again on the merged tip; merge the UI lane's list (afc331bd in, then 74c12665, 89501ce8, b7d33e8e, the doc-only d29a8663), ember-tune-0317 c9b31edc; re-stage 0.3.18 in scratch; the fleet's full canary on its pods with the headers-proof fresh join decisive; publish 0.3.18 on its line, whenever that falls, morning included. Ember's PC 1 window ("PC 1 on 0.3.18") and the UI lane's Mac check follow its update-nows. + +Tips (node lane, 03:5xZ): release tree 4f4bb9c9 on ca3-v4-0317-fix (cherry-pick alone onto 12153428); feature tree a3fe9f67 on ca3-v4-0318 (on e1197983, a lockfile-only commit). A follow-up on both is due (the ping flow's `syncing` flag IBD-only; "sink at genesis" broke the peer-drop gate's `--case still` and is redundant for the canary): take it WITH 4f4bb9c9. The hotfix canary (0.3.17, node d712b498) started 03:58Z on c17-1; its clock in UTC: headers through about 04:17, synced 04:40, reads 04:50, cases 05:25. + +**Final node inputs (main, 04:0xZ): the 0.3.18 node tree is ca3-v4-0318 at 6e4ace3f** (a3fe9f67 the fix, b21659e4 the IBD-only follow-up, 6e4ace3f igneum_getNodeInfo's `blockrate` object for the merge check; exec-only, digest untouched; all suites green). The release-branch form (4f4bb9c9 + ddda7d52 on 12153428) is the equivalent and not used. After "0.3.17 live": release-0.3.18-node = 6e4ace3f, every platform rebuilt, then the canary. + +**Dated fault for this tree (the node lane, 05:05Z, found by the Mac's headers-proof join gate, not by a canary):** when the devnet's pruning point first leaves genesis (chain DAA 185,799, about eight hours from 05:00Z at 1 bps), every fresh join by headers proof fails for the next 2,644 DAA (about 45 minutes) with "IBD with headers proof ... unsuccessful (DAA window data has only N entries)": upstream's sampled-window walk (661 samples at rate 4) runs out at a gap in the trusted blocks instead of reaching genesis. Nodes already on the chain are untouched. Fix: joiner-side on the trusted path only, digest-neutral (the walk accepts a window that runs out at origin when the block is younger than the span), coming on ca3-v4-0318 (hash to follow); 0.3.18 carries it. Any fresh-join canary timed inside that 45-minute window FAILS from this, not from the idle-peer fix: time 0.3.18's canary outside it (before about 12:50Z or after about 13:40Z, to be firmed from the live DAA). + +**Main's rule for the 0.3.18 cut (05:1xZ):** it carries the node lane's joiner-side fix for the pruning-point fault (on the 0.3.18 tree the N6 guard would otherwise ban the syncer for ten minutes per retry), and **0.3.18 is live on every node before 13:30 UK (12:30Z)**, ahead of the devnet's first pruning (DAA 185,799, about 14:00 UK). If the full canary cannot close by then, publish 1 goes on the clean form plus the node lane's harness for that case, and the cases follow as confirmation, as with the hotfix. Every new chain, the testnet genesis included, meets the same fault once at its first pruning: the testnet go checklist (docs/plans/testnet-go.md) gets the line. + +**Correction (the node lane, 05:1xZ): the devnet does NOT meet the young-window fault, and the 185,799 clock was wrong** (the canary's 155,700 headers were taken for the chain's DAA; live DAA was 250,809 at 05:00Z, the hub's 39th pruning move was at 03:46Z and the 03:50Z fresh join synced clean). Pruning samples sit at multiples of the finality depth (pruning.rs is_pruning_sample); the devnet's finality depth is 43,200 blocks, so its first non-genesis pruning point was at blue score 43,200, sixteen window spans past genesis, and the walk from any devnet pruning point fills its window. The fault needs a pruning point within 2,644 DAA of genesis, which only a chain with finality depth under 2,644 can have: the fast-time profile (120) where the gate found it. The testnet at the compiled numbers never meets it either. So: no fresh-join window to avoid, the 45-minute rule is dropped, main's "before 13:30 UK" rule for 0.3.18 no longer rests on this fault (main to confirm), and the testnet go line is softened to a note. The fix still rides 0.3.18 (joiner-side, digest-neutral, relaxes the rule only when the walk ended within one sample of genesis, impossible on the devnet; unit test green on the box; hash to follow). + +**Main, 05:2xZ: the 13:30 UK deadline is withdrawn.** 0.3.18 ships on its normal gates with the full canary, no shortcut; the young-window fix stays in the tree as a harness-profile correctness fix. ca3-v4-0318 tip 06:04 UK: e3798a17 (69647bd6 per-path finality timers plus the join bench, test-only plus accounting; e3798a17 the young-window fix, unit test green). The fresh-join cost fix is next on the branch with its own hash and before/after numbers; its "before" figure comes from the 0.3.18 canary's IBD-end line (the new "finality time: bodies ..., virtual ..., weight tables ..., signatures ..., persists ..." line), which I relay verbatim (route (b); a read-only joiner from the box, route (a), is main's word). + +ca3-v4-0318 tip 06:06 UK: **aa49613f** (on e3798a17; carries the IBD-end "finality time" line; p2p-flows and kaspad check clean on the box). The cut takes aa49613f or the later tip the node lane names; the canary's fresh-join IBD-end line goes to the node lane verbatim. + +## 6. The 0.3.18 inputs as of 05:2xZ (main's list) + +- Node: the ca3-v4-0318 tip the node lane names at the cut; now **8220c944** (06:10 UK; on aa49613f): a block's votes BLS-checked across cores before the finality lock, exact by the two-path test. Box, 500-checkpoint chain of 22,221 blocks: join 218 s to 104 s, finality 130 s to 30 s, signatures 97 s to 9 s. Suites at 8220c944 on igneum-build-1: kaspa-consensus lib 110 passed, 0 failed, 3 ignored (the two new finality tests inside); kaspa-p2p-flows 37 passed; kaspad check clean at aa49613f with nothing in kaspad changed since. The real split of the canary's 8 s per checkpoint comes from the IBD-end timers line of the 0.3.18 canary's fresh join, relayed verbatim to the node lane. +- App: miner-ui-4 afc331bd (in), 74c12665, 89501ce8, b7d33e8e, **bac43ac4** (main's row from PC 1's 04:51Z relaunch: the card watchdog judges a miner only while the node is synced; a silence fault from the sync is released when the node syncs and the card starts again with an Activity line; a worker silent from its start is faulted at 60 s; one Activity line per card at its first start; known-failed test from the PC 1 row in release-0.3.17.md; 173 box + 42 UI tests green) plus the doc commits (d29a8663, 0e2e8a31); ember-tune bb37c993 (c9b31edc is job-script only); exec-app 032f03c; relay 28c028b. +- Gates: the same as every cut; the full canary with the fresh join decisive; publish on its line. + +## 7. The node tree is a merge (05:5xZ) + +ca3-v4-0318 (8220c944) does not contain release-0.3.18-node 12153428: their merge-base is 9a44fcb8 (ca3-v4-0316), so the branch lacks the ladder 1591ee1d, exec-sync 40fd8d8c, finality d8d1de1a, tail-emission 996b592f, the kaspad igneum-pow default 75467244, cc78a21f and 90aaf38e (it carries f2b25fdf, its own adaptation of the canary fix). The 0.3.18 node is the merge of 8220c944 (or later) into 12153428. A no-commit test merge conflicts in six files (consensus/core/src/igneum.rs, pre_ghostdag_validation.rs, ibd/flow.rs, v10/blockrelay/flow.rs, the two integration test files): the node lane resolves it, pushes release-0.3.18-node to the mirror, runs the suites and the integration check, and names the tip. The branch stays at 12153428 until then. + +PC 1's 0.3.17 relaunch (section 7 of release-0.3.17.md) adds a node row for this tree: the template RPC blocks under the finality catch-up after a restart on a synced node (every getBlockTemplate timed out at 5 s for 90 s); the app row (bac43ac4) needs its rule changed to "template timeouts while the node reports synced are not a card fault". + +## 8. The app tree assembled (05:4xZ) + +release-0.3.18 at da5c40ba: miner-ui-4 afc331bd (in), 74c12665, 89501ce8, b7d33e8e, d29a8663, 0e2e8a31, bac43ac4, 5d9c55a2 (the UI lane's rule from PC 1's read-back: "template fetch timed out" is the miner's heartbeat, the card reads "waiting for the node to answer block templates", judged again from its last line; 173 box + 42 UI tests on its branch), ember-tune c9b31edc (job script; bb37c993 in), exec-app 032f03c (in), relay 28c028b (in). One merge fix by the shipper: 74c12665's merge view called the three-argument `live::fetch`; this tree's is the four-argument form (e5336dc7 gave it the engine's Shared), so engine.rs:3200 passes `&shared` as server.rs does (da5c40ba). App tests on the Mac: 179 + 28 + 8 passed. The node pin, binaries, inputs and staging wait on the node lane's merged release-0.3.18-node tip. + +UI lane on the merge fix (05:5xZ): correct; the four-argument form wins. Note: Ember's fetch clamps the window to 300 s, so the merge view sees 300 s rather than 600; the check needs a block of ours inside 120 s, so it holds. The merge view, TemplateTimeout and the synced gate are present on origin/release-0.3.18. + +**The node merge, the node lane, 06:0xZ (not yet pushed):** 8220c944 into 12153428 resolved: five conflicts taken as the release side (the ladder's header_signals_active reading, the test fixes), the sixth the relay flow (the pipelined handle_block carries the 0.3.16 IgneumProofMissing retry arm ahead of the N6 arm); one copy of header_version_acceptable kept. Box at the merged tree: kaspad check clean, integration check clean, consensus-core 123, p2p-flows 37, p2p-lib 20. A real finding: kaspa-consensus failed 1 of 112 then 4 of 112 under a box load of 178, every panic WrongBlockVersion(1026 or 32770, 2) in a plain-block test: a test-order race both parents carry (the signal and ladder tables are process-wide statics; two tests install and restore them; a block-building test inside that window reads the installed version; the two load flakes of the 12153428 suite were this). Fix: an install lock the two installers hold; the suite runs twice on the quiet box; if green the merge is pushed as release-0.3.18-node with the lock commit on top (tip about 06:20Z); if a reader still races, the two installing tests run serially as a second pass, said before the push. + +**Suite rule change with the merged node (the node lane, 06:1xZ):** the install lock did not close the row (2 of 112 still WrongBlockVersion(32770, 2) on the quiet box), so the two installing tests (block_template_uses_current_block_version, cheap_checks_run_before_the_pow_engine) move out of the lib unit-test binary into their own target consensus/tests/igneum_installed_signals. From the 0.3.18 node on, the suite runs `cargo test -p kaspa-consensus` without `--lib` (all targets) so both run; a `--lib` run silently skips them. Push with the merged tree once the lib suite is green twice and the new target once, about 06:35Z. + +## 9. The node tree: release-0.3.18-node = 1cf43254 (the node lane, 06:09Z) + +The merge of ca3-v4-0318 (8220c944) into 12153428 with the six resolutions, plus the race fix in the same commit (the two installing tests moved to consensus/tests/igneum_installed_signals.rs and igneum_order_tests.rs; INSTALL_TEST_LOCK for installers sharing a binary). Box at 1cf43254: kaspad check clean, integration check clean, kaspa-consensus lib 110 twice on the quiet box, the two new targets 1 each, consensus-core 123, p2p-flows 37, p2p-lib 20. A second merge may follow within the half hour (PC 1's two node rules: template answers under catch-up, synced reads behind), else the cut is at 1cf43254. The shipper's box and Mac chains started on 1cf43254 at 06:1xZ (scratch only; the pin, inputs and staging wait for the node lane's cut word). + +**Main, 06:1xZ:** the chain runs on 1cf43254 now. The node lane's two PC 1 rules (getBlockTemplate answers inside its timeout during the finality catch-up; isSynced false while the catch-up is behind the sink) land as a second merge with a node rebuild only if they reach the release branch before the inputs push; otherwise they are 0.3.19, said here. Full canary with the fresh join decisive, the IBD-end timers line to the node lane, publish on its line. + +## 10. Builds on 1cf43254 (06:10Z on) + +| piece | commit string | sha256 (first 8) | bytes | note | +|---|---|---|---|---| +| Linux igneumd, box native (the fleet's canary sha) | 1cf43254 | 96858a88 | 57,408,800 | 06:11Z; the fleet has it with GO for the full form | +| Linux igneum-miner, box native | | fac45489 | 10,213,112 | | +| Windows igneumd.exe (cross) | 1cf43254 | c29ee9e5 | 52,340,224 | 06:12Z | +| Windows igneum-miner.exe | | 7ca9ca01 | 11,219,456 | unchanged from the 12153428 build | +| Mac igneumd | 1cf43254 | 25b464b4 | 47,888,704 | | +| Igneum-Miner-0.3.18.dmg | | a3822c4d | 44,248,348 | packaged object = the live sixteen; prover pair aboard; version 0.3.18 | + +Digests on the Mac binary: sixteen eada4bda (igneum_getNodeInfo: powEngine igneum-pow, blockrate {bps 1, finalityDepth 43200, ghostdagK 18, mergeDepth 3600, pruningDepth 108000}), thirteen b18ed271, no file c562d70e (re-read on free ports, 06:15Z). All three unchanged from 0.3.16/0.3.17. + +(suite, integration check, seed, hive, inputs, Windows run, staging, canary: rows as they land) + +## 11. The cut: release-0.3.18-node = ae17ad00 (the node lane's word, 06:14Z) + +1cf43254 plus the second merge of ca3-v4-0318 (e3a00bf0: 4f7c56a0 PC 1's two node rules, getBlockTemplate answers inside its timeout during the finality catch-up and isSynced reads false while the catch-up is behind; e3a00bf0 the installing-tests move on that branch too). Box at ae17ad00: `cargo test -p kaspa-consensus` 111 in the lib plus the two moved targets 1 each, p2p-flows 37, `cargo check -p kaspad -p kaspa-rpc-service -p kaspa-testing-integration --tests` clean. One hand fix in the merge: the W7 leaves block in template_section rides the template snapshot like the other items (newest 32, emitted last under the leave_active gate). The 1cf43254 chain was stopped at its seed step (its suite: see r0318/ae17/box-1cf43254.log) and both chains restarted on ae17ad00 at 06:2xZ. The canary form gains two reads for PC 1's rules: on a restart with a kept datadir, every getBlockTemplate inside 5 s through the catch-up (no "template fetch timed out" lines), and isSynced false while the catch-up holds the finality state, true after. + +**Canary on ae17ad00 started 06:16:47Z** (c18-1, RTX 3070 pod, wiped datadir, node b06c1a97, 57,447,712 bytes, miner fac45489; the 1cf43254 early run stopped by pid; it had read vline 1cf43254, digest eada4bda, igneum_getNodeInfo with blockrate, IBD from 4 peers). Clock: headers through about 06:52Z, synced 07:12Z, mining reads to 07:22Z, the restart reads (isSynced false then true every 10 s; max template_ms, timeout count, template count) to about 07:40Z, then the relay and poison cases with c18-1 as the target. + +## 12. Builds on ae17ad00 (06:15Z on) + +| piece | commit string | sha256 (first 8) | bytes | note | +|---|---|---|---|---| +| Linux igneumd, box native (the canary sha) | ae17ad00 | b06c1a97 | 57,447,712 | 06:16Z; the canary runs on it from 06:16:47Z | +| Linux igneum-miner | | fac45489 | 10,213,112 | unchanged from 1cf43254 | +| Windows igneumd.exe (cross) | ae17ad00 | e4979672 | 52,391,424 | pow link 9 | +| Mac igneumd | ae17ad00 | a56469d7 | 47,905,856 | | +| Igneum-Miner-0.3.18.dmg | | f617b63b | 44,241,681 | packaged object = the live sixteen; prover pair aboard | +| Windows inputs | ae17ad00 | | | pushed 06:19Z (workers d7a413c7 etc, the Linux prover pair), pin 1c8fb76a on release-0.3.18, windows.yml run 37580969266 dispatched 06:20Z | + +Digests on the Mac binary: sixteen eada4bda (igneum_getNodeInfo powEngine igneum-pow, blockrate as before), thirteen b18ed271, no file c562d70e (free ports). All three unchanged. Box suite on ae17ad00 rc 0 (kaspa-consensus without --lib, so the two moved targets ran). Identity grep on the payload UI clean. The 1cf43254 builds (96858a88, c29ee9e5, 25b464b4, DMG a3822c4d) are superseded and not staged. + +| generic Linux igneumd (class seed, glibc 2.35) | ae17ad00 | 99809615 | 56,141,136 | pow link 6; the seed's own build comes from the build-server lane | +|---|---|---|---|---| +| HiveOS igneumd (class hive, glibc 2.31) | ae17ad00 | a2e734d1 | 56,141,776 | pow link 6 | +| igneum-hive-0.3.18.tar.gz | | 21ea06eb | 27,234,062 | 2.31 node pair + the box's workers 193ec36f/7a35ff2a; no `._` entries; ubuntu:20.04 container smoke on the box: all four load (06:23Z) | + +| hands igneumd (box native, the build-server lane, pairs with igneum 1c8fb76a) | ae17ad00 | 17209647 | 57,448,096 | held for the line; OUT_DIR apart from b06c1a97 | +| seed igneumd (class seed, the build-server lane) | ae17ad00 | fa9c2f12 | 56,139,920 | GLIBC_2.34; held for the line | +| hands / seed igneum-miner | | 9adcb707 / 2ebaee58 | 10,213,112 / 10,234,128 | | + +Integration check on ae17ad00 rc 0 (06:18Z). The hands and seed go last on the shipper's line after the miners (observer, node 1, seed), each read back by commit string, digest and igneum_getNodeInfo powEngine with its blockrate object. + +## 13. Staged at the line (06:29Z) + +Windows run 37580969266 green (06:27Z): Igneum-Miner-Setup-0.3.18.exe 2fcaf093, 62,822,510 bytes. Scratch copy r0318/dlsite-stage (fresh from the live folder): manifests at 0.3.18, mac f617b63b, windows 2fcaf093, consensus.override = the live sixteen-field object, HiveOS alias held at 0.3.17 until its own row; the live folder holds no 0.3.18 file. Runbook r0318/deploy.sh (preflight passes; step_manifest, step_update_now, step_hive with the 0.3.18 tar, step_readback with igneum_getNodeInfo). Discord card dry-run (four reader-facing lines, no em dash). Everything waits on the canary's line. + +## 14. The canary (c18-1, ae17ad00 / b06c1a97) + +- 06:34:54Z: headers 47 percent (59,425) in one IBD session since 06:17:32Z, 17 minutes in and 5 past the old guard mark; SendPingsFlow 0, idle-drop lines 0, "completed with error" 0; the class-signal warning is ONE line (49,844 on the hotfix). Headers through about 06:55Z on the 3070, synced about 07:15Z. + +## 15. HOLD on ae17ad00: the exec RPC panic (the node lane, 06:4xZ) + +The Mac's headers-proof join gate killed its joining node mid-IBD on the canary-fix binaries: a panic at igneum/exec/src/rpc.rs ("index out of bounds: the len is 0 but the index is 0") on a tokio worker, and the node's panic hook exits the process. The site: eth_getBlockByNumber reading state.records[n] after resolve_block mapped "latest" to tip_number() = 0 on an exec state with no records (the follower still "waiting for consensus to sync"); a local client polled 127.0.0.1:26790 during the IBD and the node died at 66 percent of the headers stage. Every records index in that file is unchecked on both trees (0.3.17's 5899f603: rpc.rs lines 474, 550, 591 to 629; ae17ad00: 575, 651, 692 to 730), so any fresh or restarting node with the exec RPC bound and a client asking eth_getBlockByNumber("latest") before the follower has a record dies. The shipped app itself calls only eth_blockNumber and igneum_* methods (none index records by block number), so the live 0.3.17 risk is a wallet or third-party client on a fresh node mid-IBD; the fix (every index bounds-checked; "latest" on an empty state answers null; a test on an empty state) goes onto ca3-v4-0318 and into release-0.3.18-node as a third merge. The pin stays at ae17ad00 on origin and nothing is staged further until the third tip; the ae17ad00 canary runs on (nothing attached to its eth_ port) as an early read of the other rows. + +**The 0.3.17.1 question settled (07:0xZ, main's rule: a hotfix only if the shipped app sends the panic class):** no. The dead harness node's site is eth_getBlockByNumber; the shipped app sends eth_blockNumber and eleven igneum_* methods only (grep of the whole 0.3.17 app tree); its two records-indexing polls (igneum_getAssignedShards, igneum_getProofRecords) run only after the node reads synced, when a devnet follower already holds records from the packaged restart block; the two it sends while unsynced index nothing. The wallet app sends eth_getBlockByNumber to its own node. Ledger N7 carries the method map. The public testnet filter now blocks ten eth_ and six igneum_ records-indexing methods (seed1, verified; tree copy committed). + +## 16. The cut moves to release-0.3.18-node = e69e8a39 (the node lane, 06:53Z; the pin released) + +ae17ad00 plus the third merge of ca3-v4-0318 (500ddd66): c6a62e00 (every chain-block read in the exec JSON-RPC bounds-checked; an exec state with no record answers an error instead of indexing; test on the empty state) and 500ddd66 (GetBlockTemplate stage timers: a debug line per request, an info line once per 10 s past 500 ms; the epoch-seed walk and the live sink tally memoised). One hand resolution: the payout parameter on igneum_getProofRecords beside the bounds-checked read. Box at e69e8a39: igneum-exec 26, kaspa-consensus 111 plus the two moved targets, p2p-flows 37, kaspad / rpc-service / testing-integration checks clean. Both chains restarted on it 06:55Z (the ae17ad00 logs kept in r0318/ae17/). The canary form gains two reads: an eth_ client polling the joining node's exec port through the IBD (the node survives), and the first slow "GetBlockTemplate N ms" line on the pool's loaded node after the publish. + +## 17. Builds on e69e8a39, the pin (06:55Z on) + +| piece | commit string | sha256 (first 8) | bytes | note | +|---|---|---|---|---| +| Linux igneumd, box native (the canary sha) | e69e8a39 | 252c8dad | 57,461,600 | the form started from the wipe 07:02:54Z | +| Linux igneum-miner | | fac45489 | 10,213,112 | unchanged | +| Windows igneumd.exe (cross) | e69e8a39 | c1a42970 | 52,379,136 | pow link 9; inputs pushed 07:03Z, pin 0911b00f, windows.yml run 37585128393 dispatched 07:04Z | +| Mac igneumd | e69e8a39 | 066807ae | 47,921,280 | | +| Igneum-Miner-0.3.18.dmg | | cb30080e | 44,247,374 | packaged object = the live sixteen; prover pair aboard; version 0.3.18 | +| generic Linux igneumd (class seed, 2.35) | e69e8a39 | 7d67cb51 | 56,152,400 | | +| HiveOS igneumd (class hive, 2.31) | e69e8a39 | 6293b443 | 56,153,104 | | +| igneum-hive-0.3.18.tar.gz | | 72699158 | 27,236,213 | 20.04 container smoke clean, no `._` entries (07:08Z) | +| hands igneumd / seed igneumd (the build-server lane, pairs with igneum e9ccb3a1) | e69e8a39 | 37610a77 / 63cd49be | 57,461,984 / 56,152,720 | held for the line | + +Digests on the Mac binary (explicit arguments; a zsh loop had not split them on the first pass): sixteen eada4bda, thirteen b18ed271, no file c562d70e. igneum_getNodeInfo: powEngine igneum-pow, blockrate {bps 1, finalityDepth 43200, ghostdagK 18, mergeDepth 3600, pruningDepth 108000}. The N7 class on the Mac binary: eth_getBlockByNumber ["latest", false] on an empty exec state answers {"result": null} and the node lives (the node lane: null is Ethereum's shape for a block that is not there; every other read on an empty or short state answers an error object). The branch tip moved to 2a014bf1 (test-only: all 46 exec RPC methods through the real dispatcher on empty and one-record states, no panic); the pin stays at e69e8a39, whose shipped bytes it equals. + +The chain's own log was lost mid-run (the build-server lane removed scratchpad/r0317 and r0318 whole while dropping its superseded pairs; rule now: no lane removes a scratch directory it did not create; this lane's scratch is r0318-ship); the suite and the integration check are re-run on the box for the record (r0318-ship/suite-e69e8a39.log). + +**Suite on e69e8a39 (the box, 07:08Z, re-run for the record):** igneum-exec 26, kaspa-pow 19, kaspa-consensus 111 (lib) + the two moved targets 1 each, consensus-core 123 + 7, kaspa-p2p-flows 37, igneum-miner 16; 0 failed; rc 0. `cargo check -p kaspa-testing-integration --tests` rc 0. Together with the node lane's own runs at e69e8a39 and 2a014bf1 this is the gate's suite line. + +## 18. Staged at the line (07:1xZ) + +Windows run 37585128393 green (07:10Z): Igneum-Miner-Setup-0.3.18.exe 669d5676, 62832534 bytes. Scratch copy r0318-ship/dlsite-stage (fresh from the live folder): manifests at 0.3.18, mac cb30080e, windows 669d5676, consensus.override = the live sixteen-field object, HiveOS alias held at 0.3.17 until its own row; the live folder holds no 0.3.18 file. Runbook r0318-ship/deploy.sh (preflight passes). Discord card dry-run (five reader-facing lines, no em dash). Everything waits on the canary's cases line. + +**For 0.3.19 (not the pin), the node lane 07:1xZ:** ca3-v4-0318 = fd7de1b4 (the live class-signal tally refreshed off the request path; kaspad check clean, consensus 109). e69e8a39 memoises the tally for 10 s per sink, so the pool's canary should show the "pow epoch" stage near zero on nine requests in ten and the full walk (1 to 1.6 s) on the tenth; if the stage line shows it high on most requests the reading is wrong. fd7de1b4 is the first 0.3.19 node commit (main, 07:1xZ: no four-part numbers, the parser refuses them); 0.3.18 ships as pinned at e69e8a39 on its canary's line. + +## 19. The canary on the pin (c18-1, e69e8a39 / 252c8dad, from the wipe 07:02:54Z) + +- 07:21Z: 17 minutes into one IBD session, headers 37 percent (48,160 at 07:16:45Z), past the old guard mark; SendPingsFlow 0, idle-drop 0, IBD errors 0, the class-signal warning 1 line, node alive; the eth_getBlockByNumber poller at 208 polls, 0 error answers, all null. Headers through about 07:45Z, synced about 08:05Z. + +## 20. PC 1 and PC 2 after the project lead reopened the apps (07:28Z reads, read-only) + +- PC 2 (1ccfe586): back online; its app came back on 0.3.16 and applied 0.3.17 at reopen (update: version 0.3.17, current, updated_from 0.3.16); node 2.1.0 synced at DAA 262,124 with 5 peers; the RTX 5090 mining at 100 MH/s (pid 19620, 11 accepted in its first minutes), no fault lines. The update-now takes it to 0.3.18 directly. +- PC 1 (ae432dc7): app 0.3.17 (reopened, uptime 531 s at the read), node binary 5899f603 (3 marks, pow link 9), digest eada4bda; but the node is in a restart loop: state "restarting", starts 16, igneumd not running at the read; every card "waiting for the node to sync" (mining "waiting", not faulted this time). Cause being read from the engine's node lines and the node logs (read-only job). Rule for the publish: PC 1 and PC 2 take their update-nows first and their workers are read back at their rates as the per-box table's first line. + +**Latency ladder rung 3 re-measured (the node lane, 07:46Z, in the shipper's box window under the measure hold):** reps 88, cold alone 9.04 ms, cold with the SMT sibling loaded 10.85 ms, averages of 50 at 5.95 and 10.11 ms; over the 10 ms gate by 0.85, so rung 3 stays inadmissible and the testnet genesis freezes with 88 false. Rung 2 as the control on the same run: 9.25 ms cold loaded, admissible. + +**PC 1's restart loop IS the N7 class on the shipped kit (07:5xZ, the engine log app-20733-072141.log):** every node start ends 2 to 5 s later with "panicked at igneum/exec/src/rpc.rs:591:41: index out of bounds: the len is 0 but the index is 0" (eth_getBlockByNumber's records[n] in 0.3.17's tree), the app restarts it every 40 s (starts 16 at 07:28Z), the miners are stopped each time. CORRECTED 08:0xZ: the client is the shipped engine itself: `latest_block_time` (update.rs:46) POSTs eth_getBlockByNumber ["latest", false] through curl to the exec port every 9 s as the app's clock sample once the node reports blocks > 0 and peers > 0 (engine.rs:3752); export-pack's lines were its own failure after the node died (igneum-miner's export-pack speaks gRPC only). So every 0.3.17 node with the app attached dies within 9 s of blocks arriving whenever its exec follower has no record: PC 1's loop, and any fresh install's IBD (the hotfix canary had no app attached). Proving-off would change nothing and was not run. c6a62e00 (0.3.18) ends it; the 0.3.18 canary's eth_ poller is the app's own call and the node lives on it. PC 1 takes the 0.3.18 update-now first on the publish line. + +**Main's publish rule (08:0xZ):** 0.3.18 publishes on the canary's synced line plus the poller summary (the decisive reads for the N7 fault, the app's own 9-second call surviving the whole IBD), not the cases line. Order: PC 1's update-now first (it is crash-looping), then PC 2, the Mac, the fleet one box at a time under the lock rule, the hands and the seed by their owner. The restart reads and the cases follow on the same pod as confirmation; a FAIL there is a rebuild, not a rollback of this fix. Then "0.3.18 live" with the per-box table and the card. + +## 21. HOLD on e69e8a39 (the fleet, 08:2xZ): the block stage cannot complete against any peer + +The canary passed its headers proof at 08:00Z (one session, zero guard lines, the app's eth_ poll alive at 918 polls) and froze at 2,728 blocks: every IBD attempt (110 by 08:2xZ, every peer) ends "block f52e64f4... carries 1 proof records whose proofs this peer did not deliver in 20 s". The node lane's reading: exec-sync's daemon installs the proof oracle whatever proving_consensus_verify_daa says (daemon.rs, after the keys branch), so the IBD flow (flow.rs, the 0.3.16 "carried proofs come from the syncer" rule) demands the proof bytes of every record-carrying block before queuing it while the serve flow answers only from a peer's bounded recent pool; block 2,728 is months old, so a fresh node of this tree can join NO network, and a synced one would verify every relayed record natively and refuse blocks its 0.3.17 peers accept (a split in waiting). Fix, joiner-side: the oracle carries its switch (active_from); the body rule, the IBD fetch and the relay retry apply to blocks at or above it only, so at never the node is 0.3.17 on this path. A direct commit on release-0.3.19-node; the pin moves to it; the canary re-runs from the wipe. + +## 22. For the 0.3.19 node: ledger N8 (the project lead's word, 08:5x UK) + +The execution layer credits merged blocks at the chain block's DAA (the UTXO coinbase pays each its own): d840537b on ca3-v4-0318, field `subsidy_per_block_activation_daa` (u64::MAX = never as compiled on every network; in the digest once set). The devnet takes it at an upgrade height carried by 0.3.19 (a DAA score past the rollout's last box under the lock rule, set in DEVNET_PARAMS at the cut; every node must carry it before that height or its EVM state diverges); the testnet from genesis. The node lane names the value when the 0.3.19 cut line is named (its canary's pass). + +**App tree (08:3xZ):** miner-ui-4 taken through 3661dc9e (a2670ace the two site captures; 3661dc9e carries 0e6c1248's exec-record clock gate without its version bumps), on top of the earlier chain; app tests 180 + 28 + 8 green. Ember: c870c383 (job-script only, equals bb37c993 on the app) at the rebuild. + +**The exec lane agrees (08:4xZ):** exec-sync-0313 HEAD carries the same shape (ProofOracle::active_from() = proving_consensus_verify_daa, set by the daemon before the oracle is handed out; the IBD pre-fetch gated on it; the body rule and the relay retry already gated); igneum-exec 23 green. The node lane's direct commit on release-0.3.19-node is the one the pin takes; the shapes reconcile at the next merge; the switch must live on the oracle (one source). Exec lane's 0.3.19 tips: node exec-sync-0313 HEAD, app exec-app-0314 731268a1. Its "0.3.19.1" (the finality-horizon skip) is a four-part number and so 0.3.20 material. + +## 23. The pin: release-0.3.19-node = dc141409 (the node lane, 08:36Z) + +e69e8a39 plus the oracle switch: `ProofOracle::active_from` carries `proving_consensus_verify_daa`; the body rule, the IBD proof fetch and the relay retry apply to blocks at or above it only (one source, on the oracle: igneum/exec/src/proving.rs:1499, read at flow.rs:1024 and body_validation_in_context.rs:47), so at never a node demands no proof of any block; the sink takes the switch from Params through proof_sink (daemon.rs:1018). Box at dc141409: igneum-exec 27, consensus-core 123, kaspa-consensus 111 plus the two moved targets, p2p-flows 37, kaspad and testing-integration checks clean. The exec lane's own commit ac6e32cd on exec-sync-0313 has the same shape and stays as the record (reconciled at the next merge). Both chains restarted on dc141409 at 08:4xZ (scratch r0319-ship); the pairs rebuild by the build-server lane. Canary reads for this tip: the block stage passes 2,728 and every record-carrying block with no "Proofs: asking" line, the IBD-end line with its finality time, the synced line, the app's eth_ poll alive throughout, the restart reads, the cases, and on pool-1 after the publish the first slow "GetBlockTemplate N ms" line. The 0.3.19 cut line is that canary's pass; the node lane then names the devnet DAA for the per-block subsidy height (N8). + +**Hands and seed pairs on dc141409 (the build-server lane, 08:4xZ, pairs with igneum 5010536a):** hands igneumd 8be8a5a5 (57,460,512 B), igneum-miner 92740aea; seed-class igneumd 4910352b (56,154,320 B, GLIBC_2.34), igneum-miner 9d7c4b8a; held for the line after the miners. + +## 24. Builds on dc141409 (08:43Z on) + +| piece | commit string | sha256 (first 8) | bytes | note | +|---|---|---|---|---| +| Linux igneumd, box native (the canary sha) | dc141409 | 3f9aca09 | 57,461,792 | GO sent to the fleet 08:5xZ; the form from the wipe on c18-1 | +| Linux igneum-miner | | fac45489 | 10,213,112 | unchanged | + +(cross, suite, integration check, seed, hive, Mac, DMG, inputs, Windows run, staging: rows as they land; the first chain start on this tip at 08:37Z had picked up the hotfix tree's script copy and was stopped at 08:39Z; its one native build, d712b498, is the 0.3.17 binary again and is not used) + +## 25. The canary on dc141409 (c18-1, from the wipe 08:51:50Z) + +Node 3f9aca09, POLL_EXEC=1 and the exec-status fields; the e69e8a39 node stopped by its kill file (frozen at 2,728 blocks since 08:00Z). The form prints the count of "Proofs: asking" lines and of "carries N proof record" IBD errors beside the IBD-end line. Clock: headers through about 09:27Z, the block stage past 2,728 about 09:35Z, synced about 09:50Z, mining reads to 10:00Z, the restart reads to about 10:15Z, then the relay and poison cases; pool-1's "GetBlockTemplate N ms" line after the publish. + +## 26. Owed to the 0.4.0 cut (the launch-pack lane, 08:5xZ; not this tree) + +- The signing step (docs/plans/launch-pack.md section 2.4 on master 9b98b837, gate LG-3 in docs/plans/testnet-go.md): implemented only once the certificates exist (Windows EV Authenticode and an Apple Developer organisation account, both under Igneum Labs LTD, enrolled the day the entity exists; the owner approved both 7 October 2026). Until then 0.4.0 ships unsigned and the download page says so. The step keeps ship-app.mjs's list and adds: windows.yml signtool through the CA's cloud KSP (two secrets; unsigned and marked so without them), Inno SignTool=; ship-app.mjs fetch osslsigncode verify (CN Igneum Labs LTD, SHA-256, timestamp; unsigned fails); build-dmg.sh codesign Developer ID with runtime and timestamp, notarytool --wait Accepted, stapler on the app and the DMG, no quarantine strip; publish-manifest.sh signed_by and notarized per platform, --public refused without; ship-app.mjs verify osslsigncode and spctl --assess on the live files; the download page and the Discord card say "Signed by Igneum Labs LTD" only when the manifest does; tools/ci/signed-release-check.sh in pre-push. Keys never on igneum-build-1. +- docs/analysis/income-tiers.md regenerated from tools/launch/income-tiers.json at the 0.4.0 cut, the rows re-measured on class v4 (node tools/launch/income-tiers.mjs; --check in pre-push). + Names to build against (the launch-pack lane): GitHub secrets IGNEUM_CODESIGN_ACCOUNT and IGNEUM_CODESIGN_KEY (TOTP seed or API key by the CA; absent on forks and PRs, so unsigned and marked); notary keychain profile igneum-notary (xcrun notarytool store-credentials, once on the Mac); the codesign identity "Developer ID Application: Igneum Labs LTD (TEAMID)" read from one place (an env or a packaged-config field), the team id dropping in without a code change. Values reach the shipper by relay, never the repository (launch-pack.md section 5, items 3 and 4). + +**Branch tip past the pin (the node lane, 09:04Z):** release-0.3.19-node = aea0ca5c on the mirror, on dc141409: the proof archive (ledger N9's second half; every carried record's proof kept under the exec db dir's proofs/ for the pruning window, served to a joiner's IgneumRequestProofRecords past the pool's 600-block window, dropped below the pruning point; no digest field, no behaviour on the devnet at never). Box: igneum-exec 28, p2p-flows 37, kaspad and testing-integration checks clean. **The pin stays at dc141409** (the canary running on it since 08:51Z; a re-pin only on a FAIL); aea0ca5c is 0.3.20's first node commit otherwise. + +**Suite coverage note (the node lane, 09:1xZ):** `processes::pruning_proof::igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds` fails deterministically (MissingEpochSeed(1, _, 109) not matched) on an untouched e69e8a39 worktree with `--features igneum-pow` at any box load; it sits behind `#[cfg(feature = "igneum-pow")]`, so no lane's suite line (`cargo test -p kaspa-consensus` without the feature) compiles it, which is why 111 reads green. Owner: the M20 pruning-proof witness work (the epoch seed table of a proof-synced node). Not a publish blocker by itself (the gated path is what the live binaries run; the red is a test or seed-table reading), but the suite line must either carry the feature or the red must be fixed before "all green" covers it: a row for the 0.3.20 suite rule. + +## 27. miner-ui-5 is the 0.3.19 app (the project lead's word at 13:1x UK: "deploy the miner look") + +Taken onto release-0.3.19 as five cherry-picks on the miner-ui-4 chain: 2b4775b4 (the ladder's engine half: ladder.json, api/ladder chain facts, the block card), 449fb207 (the ladder on every page, the count-up, the block card, Earnings in IGN), b49db57d (the plan, the captures, the first-share runbook, the Discord rules), 3973ff8b (live-dag.js 2.0.1, the site lane's real-data options), e9fe1106 (u04 and u14 reshot); tip a199160d. Gate: app 197 + 28 + 8, UI 47 (notices 8, tune-line 5, update-card 4, view 30), all green. Next: push, windows.yml, the DMG (after the dc141409 Mac chain), staging; the read-back line adds "app miner-ui-5" and the pack's two shas. If the canary slips past 15:00 UK, main decides whether the app ships alone as 0.3.19 on the 5899f603 pin and the feature node becomes 0.3.20. + +## 28. The prover pair (main's order, 09:0xZ): handed over, verified, the CI check in + +The fleet's 14 standing provers had proved nothing since the hotfix: their harness (tools/fleet/box-prover.py) exported igneum_exportSegments from the restart block 27276 to the tip on every claim and replayed 133,000 blocks through 72142, where every port (the 6 October floor exporter, master's 6c3cc8b9 core, the kit's 263bf4ce) computes state root 0x8e1bef4b against the nodes' 0x9851d7e2 (hub-1, p1-5090 and PC 2's 0.3.17 node agree: 27276 0xed27bb2d, 72141 0x103190f4, 72142 0x9851d7e2, 72143 0x212e7703). The shipped prover never replays that far: the app exports [first-1, last] with the account dump (prover.rs, the 0.3.14 rule). On p1-5090 the kit's pair (host 71bc2438, export 263bf4ce; the same bytes in the 0.3.17 and 0.3.19 kits; the proving crate and the exec types identical across both trees) fed the app's form reads "account dump: 83 accounts after chain block 160829, state root equals the node's; replayed 8 segments, every state root equals the node's", so the pair is right; the fleet rolls it one box at a time with box-prover.py exporting the app's way, the two pairing lines read after one segment. The from-27276 divergence at 72142 is with the node and exec lanes (not on any proof path). "e809e396" is not a prover on the box (the hands run igneumd only). CI: tools/ci/prover-pair-check.sh (the prover's evm-types tree equals the pinned node's; --self-test; in pre-push, 32 checks) reads ok on the pin. One oddity for the node lane: igneum_exportSegments ["0x2747d","0x27485"] answered with segments 160829 to 160837, 64 blocks below the ask. + +## 29. The 0.3.20 tree as of 10:2xZ (after the split and the Mac's reboot) + +- Numbers: 0.3.19 = the app-only miner-ui-5 cut on pin 5899f603 (release-0.3.19); this tree = 0.3.20 (release-0.3.20 app, release-0.3.20-node = dc141409 on the mirror, the canary on it running as 0.3.20's gate); decimals 0.3.21 unless main says otherwise. +- Node side to come on release-0.3.20-node (the node lane): aea0ca5c the proof archive; the amended class v4 (CLASS_SIGNAL_V4 = 5; byte-4 signals never count; the kaspa-pow vector test; the daemon's window line naming object and sub-version; igneum-pow at the hash lane's a0aaca92 with the seven packs under the sub-version-1 stamp); the exec RPC listener watchdog (a dead listener rebound once with a log line, a second death within a minute exits; gated on the every-method test and a kill-the-listener unit test); N8's subsidy height (DEVNET_PARAMS at the cut). The flip arithmetic (the Counter ASIC lane, plan 6.6 on ca3-v4-node fa5bc9e6): the two v4 fields publish only after the one-sweep rollout and every worker on the 0.3.20 tree; the floor moves to the publish DAA + 604,800 rounded up to the epoch boundary (882,000 for a 12:00 UK publish on 7 October; recomputed from the live DAA at the publish), the window 86,400 unchanged; the earliest flip about 6 days 10 hours after the publish, never before every node has had the sweep plus a week. The rollout clock for that: 32 minutes for the 14 standing boxes under the lock rule, the hands and the seed about 3 minutes after, the Mac and PCs within minutes. +- App side: ember-heat (worktree igneum-wt-ember-heat, 7c779035, cd1034a2, 0d5fc6d2 on e9fe1106: heat mode in the engine and Ember, the region and price step at first run, the cost-against-rent row, two gate checks; app 198, UI 56, gate 32 green), main's word; its PC 1 4-hour hold is a runbook, not a gate. The ui-ota channel (the same lane): a "ui" object inside the signed manifest body, one signature; the bundle under dl/ as the installers; ui.version three-part; publish-manifest.sh gains --ui (the one writer); the kill switch is the object's absence plus a fallback on any mismatch; a CI check that the manifest's ui.sha256 equals the public tar. The 0.3.19 gate module (execrpc) and version carry over at the merge. +- Ledger: N10 (eadae138): the 72142 port-versus-node root is the thin-record export after a snapshot cut at FULL_RECORDS 1,200, not a rule; the exec lane owes the one-time re-execution that fattens thin records and an exporter that refuses a thin segment; "accounts" in an export is the tip state. +- The Mac rule (main, after the 10:5x UK crash): the Mac builds only the macOS binaries and the DMG, one at a time under the build lock; every other build, suite and the Windows cross-build on the box or a PC; the app gate runs on the box. + +**Node lane, 10:3xZ:** (1) the exec RPC listener watchdog is written for the node line (`rpc::serve_watched`: the listener task polled every 10 s, rebound once on a death with "exec RPC listener died: {reason}; rebound on {listen}", a second death within a minute exits 3 "so the app sees it"; gated by the every-method test and a tokio kill-the-task test). (2) **The igneum-pow of the 0.3.20 cut is the hash lane's 8c728ca3** (ca3-v4-amend), not a0aaca92: a0aaca92 keyed the load-source rule on the whole class with the shadow's pass count inside, so the base program moved with the ladder rung (caught by the fork's ladder test on the box 10:06Z) and did not compile against dc141409 (no chain_program_shadow); 8c728ca3 keys it on the class with the pass count set aside and carries the ladder igneum-pow underneath; the pinned ids do not move. (3) On the node line for the observer: igneum_claimSegment, igneum_getProofClaims and `claims` on igneum_getProofRecords (the claim posted before a prove), plus the app lane's four finality methods. Tips as each lands. + +## 30. The dc141409 canary: synced 10:29:19Z, every decisive read clean (the fleet) + +c18-1 (RTX 3070 pod, wiped datadir, from 08:51:50Z; the Mac's reboot cut the form's shell at 10:5x UK and it re-attached): synced at 141,357 blocks (headers 141,617, 3 peers). IBD-end line: "10:29:13.927+00:00 [INFO ] IBD with peer 213.173.107.74:16516 completed successfully; finality time: bodies 16592238 ms over 141699 blocks, virtual 1061858 ms over 36183 changes, weight tables 968243 ms over 359709 tables (3832285840 blocks walked), signatures 711416 ms over 439307, persists 40537 ms over 3324"; the relay catch-ups after it a second each. Counts: "Proofs: asking" 0, "carries N proof record" 0 (the oracle switch holds), SendPingsFlow 0, idle-drop 0, the class-signal warning 1 line, 6 IBD sessions, 2 "completed with error" before the re-attach (lines owed with the restart reads). The app's poller: 4,217 eth_getBlockByNumber calls, 0 errors, 0 non-null, the node alive. At the synced line the exec layer read "exec not synced: this node's consensus starts at pruning point 36a7ba0d" (executedTipHash null). Next: ten minutes of mining, the hub read about 10:40Z, the restart reads to about 10:55Z, the cases on the fresh pods. Prover roll 7 of 13 paid; hub-1's prover moved to the pair and the [first-1, last] export. + +**App side taken for 0.3.20:** ui-ota 0247b065, c337f768, 10c881dc (on miner-ui-5 b322e9fa: the "ui" object inside the signed body plus the entry's own signature, kept; "size"; src/uiota.rs; Settings > Interface; publish-manifest.sh --ui/--no-ui; tools/ui-ota/publish.mjs with --verify as the post-deploy step; ui/VERSION 1.0.0 embedded, 1.0.1 the first bundle, min_engine 0.3.20 so a 0.3.19 engine ignores it) and ember-heat 7c779035, cd1034a2, 0d5fc6d2; both green on the box. The miner-reliability branch (workers start only when READY = synced and an executed tip; the node watchdog never counts the catch-up; the restart ladder with no permanent fault; fault lines to the intake) is main's call: a 0.3.19 follow-up on the same pin, or this tree's app. + +**Fleet kit rule (main, 10:3xZ):** one prover identity per box; the kit never ships an identity file; box-prover generates its own at first start from the box's label and keeps it in the registry row; a shipped or duplicated identity is refused at start with a line. Migration on the shared boxes (9e4ba6b0 on three, faa34a1a on one) one at a time, prover only; prover identity keys are not vote keys (no weight, no signal), so the lock rule does not apply. + +**Main (10:4xZ): miner-reliability rides 0.3.20's app** with ember-heat and ui-ota (ee09ae8b, docs only, goes with its three); no app-only follow-up and no renumber. One exception: if the reliability lane's watchdog-clock and export-lock changes land small and green before the node line is ready, main decides an app-only 0.3.20 then (the feature node would become 0.3.21). PC 1 today: the Arc held off and the packs-ahead restart on 0.3.19. + +## 31. Rows from PC 1 on 0.3.19 (11:3x to 11:4x UK) + +- The template path on the 0.3.17 node: on PC 1 (24 identities, 3 cards x 8) every getBlockTemplate times out at 5 s on every identity ("template fetch timed out (5 s) for identity N", 59 + 43 + 28 lines in two minutes), no STATUS line; the 0.3.19 watchdog treats it as the miner's heartbeat ("waiting for the node to answer block templates") so the cards wait rather than fault. The node logs no per-request time on this tree (the timers are 500ddd66, 0.3.20). Mitigation today: identities down to 2 per card by the project lead's tap (no signed job can set identities: a script may not POST /api/cards, and the runner's --cards-off only toggles enabled; a runner option for identities is a small jobrun.rs change, main's word). The fix is the 0.3.20 node on PC 1 first (the memoised tally 500ddd66; fd7de1b4 the off-path refresh is 0.3.21 material unless main moves it). +- Two app faults for the reliability lane's rules, both 0.3.20's app (main): (1) engine.rs:3032, the runner's --stop-miners hold is not released while a following job runs (the resume fires only when job_hold is set and no job holds the miners), so a read-only watch job kept both cards off for three minutes; (2) orphan igneum-miner.exe processes the app no longer tracks (two alive under --stop-miners with their rows at pid 0, one after) hammer the node's template RPC beside the tracked miners, part of why PC 1's template calls ran past 5 s. Sizing of the orphan-kill for an app-only 0.3.20: below. +- The fleet's prover-identity finding was withdrawn (no box shares a key; the "shared" hashes were a carrier block's record list); no migration. The kit rule stands on another ground: `igneum-miner key-hash