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 000000000..52048a8e2 --- /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 000000000..c8bf763ab --- /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 000000000..b7604565e --- /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 000000000..4890bb9ca --- /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 000000000..b45a58daa --- /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 000000000..6d4ea6cb0 --- /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 000000000..546ae42c8 --- /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 000000000..fb2480aee --- /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 000000000..7787b6d26 --- /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 000000000..63e1e20cc --- /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 000000000..016c39fea --- /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 000000000..6f32860a5 --- /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 000000000..72840c797 --- /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 000000000..72eac7f7f --- /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 000000000..3ee33a51e --- /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/infra/fast-time/fork-gate-gate.mjs b/infra/fast-time/fork-gate-gate.mjs new file mode 100755 index 000000000..df80fe43a --- /dev/null +++ b/infra/fast-time/fork-gate-gate.mjs @@ -0,0 +1,86 @@ +#!/usr/bin/env node +// The gate line of mission item 4 (docs/analysis/mission/mission.md 2.4): "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", with the +// known-failed cases first. Runs the six cases of infra/fast-time/fork-gate.mjs side by side (each on its own slot: +// ports and devnet suffix), reads each case's verdict against what it MUST be, prints the table and writes +// docs/plans/mission-item-4-gate/summary.json. Exit 0 only when every case's verdict is the one it must give. +// +// node infra/fast-time/fork-gate-gate.mjs [--parallel 6] [--only attack-gate-on-expect-hold,...] [--joint 240] [--split 180] +// [--watch 150] [--window 60] [--honest-threads 1] [--attacker-threads 3] [--attacker-joint-threads 2] +// IGNEUMD and IGNEUM_MINER name the binaries; the cases' logs land beside the summaries. +// +// The fork depth: the window is 60 DAA (the devnet's 600 s at 60x is 10 DAA, too few blocks to read; the window stays +// at 60 and the split at 180 s, three windows deep; "15 min back" on the devnet is one and a half windows, which the +// split covers from its 61st second on). The honest side mines through the split on every case (the 6 October harness +// idled it, and a withheld chain's victim keeps mining). + +import { spawn } from 'node:child_process'; +import { mkdirSync, openSync, readFileSync, writeFileSync, existsSync } from 'node:fs'; + +const ROOT = new URL('../../', import.meta.url).pathname; +const OUT_DIR = `${ROOT}docs/plans/mission-item-4-gate`; +const args = process.argv.slice(2); +const sflag = (name, dflt = null) => { const i = args.indexOf(`--${name}`); return i >= 0 ? args[i + 1] : dflt; }; +const PARALLEL = Number(sflag('parallel', '6')); +const ONLY = sflag('only') ? sflag('only').split(',') : null; +const PASS_THROUGH = ['joint', 'split', 'watch', 'window', 'honest-threads', 'attacker-threads', 'attacker-joint-threads'].flatMap(n => sflag(n) != null ? [`--${n}`, sflag(n)] : []); +const log = (...a) => console.log(new Date().toISOString().slice(11, 23), 'gate', ...a); + +// in the order the mission asks: the known-failed cases first, then the gate line, then the two sides the gate must leave alone +const 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" }, + { 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" }, + { 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' }, + { 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' }, + { mode: 'partition', gate: 'on', expect: 'reorg', must: 'PASS', line: 'partition heal with the gate on: the heavier side wins' }, + { mode: 'partition', gate: 'off', expect: 'reorg', must: 'PASS', line: 'partition heal with the gate off: the same outcome, so the heal is unchanged' }, +].map((c, slot) => ({ ...c, slot, name: `${c.mode}-gate-${c.gate}-expect-${c.expect}` })); +const cases = ONLY ? CASES.filter(c => ONLY.includes(c.name)) : CASES; +if (!cases.length) { console.error(`no case matches --only ${ONLY}`); process.exit(2); } +mkdirSync(OUT_DIR, { recursive: true }); + +function run(c) { + return new Promise((resolve) => { + const logFile = `${OUT_DIR}/fork-gate-${c.name}.log`; + const out = openSync(logFile, 'w'); + const a = [`${ROOT}infra/fast-time/fork-gate.mjs`, '--mode', c.mode, '--gate', c.gate, '--expect', c.expect, '--slot', String(c.slot), '--case', c.name, '--out', `${OUT_DIR}/fork-gate-${c.name}.json`, ...PASS_THROUGH]; + const t0 = Date.now(); + const p = spawn(process.execPath, a, { stdio: ['ignore', out, out], env: process.env }); + log(`start ${c.name} (slot ${c.slot}, pid ${p.pid}): ${c.line}`); + p.on('exit', (code) => { + const secs = Math.round((Date.now() - t0) / 1000); + let summary = null; + try { summary = JSON.parse(readFileSync(`${OUT_DIR}/fork-gate-${c.name}.json`, 'utf8')); } catch { } + const lines = existsSync(logFile) ? readFileSync(logFile, 'utf8').split('\n') : []; + const summaryLine = lines.find(l => l.includes('SUMMARY ')) || lines.filter(Boolean).at(-1) || ''; + const verdict = code === 0 ? 'PASS' : code === 1 ? 'FAIL' : `ERROR ${code}`; + log(`end ${c.name}: ${verdict} in ${secs} s (must ${c.must}) ${summaryLine.replace(/^.*?SUMMARY /, '')}`); + resolve({ ...c, verdict, as_it_must: verdict === c.must, secs, exit: code, summary_line: summaryLine.replace(/^\S+ fg\d+ /, ''), summary: summary ? { ...summary, samples: undefined } : null, log: logFile }); + }); + }); +} + +const results = []; +const queue = cases.slice(); +async function worker() { while (queue.length) results.push(await run(queue.shift())); } +await Promise.all(Array.from({ length: Math.min(PARALLEL, cases.length) }, worker)); +results.sort((x, y) => x.slot - y.slot); + +const pad = (s, n) => String(s).padEnd(n); +console.log(''); +console.log(`${pad('case', 34)} ${pad('must', 5)} ${pad('got', 8)} ${pad('ok', 4)} ${pad('side 2 at fork', 15)} ${pad('depth', 6)} ${pad('heavier', 8)} honest nodes`); +for (const r of results) { + const s = r.summary; + const nodes = s ? Object.entries(s.per_node).map(([n, p]) => `${n.toUpperCase()} ${p.reorged ? `reorged@${p.reorg_at_s}s` : 'held'}/${p.refusal_lines} refusals`).join(', ') : '(no summary)'; + console.log(`${pad(r.name, 34)} ${pad(r.must, 5)} ${pad(r.verdict, 8)} ${pad(r.as_it_must ? 'yes' : 'NO', 4)} ${pad(s ? `${s.share_at_fork.side2_bps ?? 0} bps` : '?', 15)} ${pad(s ? s.fork_depth_daa_at_heal : '?', 6)} ${pad(s ? s.checks.side2_heavier_at_heal : '?', 8)} ${nodes}`); +} +const healUnchanged = (() => { + const on = results.find(r => r.name === 'partition-gate-on-expect-reorg'), off = results.find(r => r.name === 'partition-gate-off-expect-reorg'); + if (!on || !off) return null; + return on.verdict === 'PASS' && off.verdict === 'PASS' && JSON.stringify(Object.values(on.summary?.per_node ?? {}).map(p => [p.reorged, p.refusal_lines])) === JSON.stringify(Object.values(off.summary?.per_node ?? {}).map(p => [p.reorged, p.refusal_lines])); +})(); +const allGood = results.every(r => r.as_it_must) && healUnchanged !== false; +console.log(''); +console.log(`GATE ${allGood ? 'GREEN' : 'RED'}: ${results.filter(r => r.as_it_must).length} of ${results.length} cases gave the verdict they must${healUnchanged == null ? '' : `; partition heal unchanged between gate on and off: ${healUnchanged}`}`); +writeFileSync(`${OUT_DIR}/summary.json`, JSON.stringify({ green: allGood, at: new Date().toISOString(), heal_unchanged: healUnchanged, node: process.env.IGNEUMD ?? null, miner: process.env.IGNEUM_MINER ?? null, cases: results }, null, 2)); +process.exit(allGood ? 0 : 1); diff --git a/infra/fast-time/fork-gate.mjs b/infra/fast-time/fork-gate.mjs new file mode 100755 index 000000000..70c9a8076 --- /dev/null +++ b/infra/fast-time/fork-gate.mjs @@ -0,0 +1,325 @@ +#!/usr/bin/env node +// Weight-gated deep fork choice (docs/analysis/51-percent.md rank 2; fork `deep_fork_refusal`, 0.3.16): the fast-time gate +// of mission item 4 (docs/analysis/mission/mission.md 2.4, 7 October 2026). Three nodes on one fast-time network: H1 and +// H2 are honest and mine through every phase (--honest-threads CPU threads each, so the honest side never idles); B is +// the third node. The network mines together for --joint seconds (the weight table fills: 120 DAA at 60x), then B's two +// links (pass-through proxies B dials) are cut and B mines a private chain with --attacker-threads for --split seconds, +// more than the gate's window (--window DAA, 60 here against the devnet's 600 s) and heavier than the honest chain by +// blue work. Then the links are restored and every honest node's sink is watched for --watch seconds. +// +// --mode attack B's key is FRESH: it mined nothing before the cut, so it holds 0 of the weight table at the fork +// (the 51 percent renter of 51-percent.md section 1 has no history; here B holds 60 percent of the +// CPU threads, 3 of 5, so its chain is heavier for sure; the refusal does not read how much heavier) +// --mode third B mines through the joint phase too (--attacker-joint-threads, 2 against 1 + 1: about half of the +// blue blocks at the fork, above a third), so its deep fork is ACCEPTED: both honest nodes reorg to it +// --mode partition no B: H1 against H2, each with half of the weight; H2 mines heavier through the split; at the heal +// H1 takes H2's chain and H2 keeps it, with the gate on exactly as with it off (the heal is unchanged) +// --gate on|off fork_gate_activation_daa 0, or the switch at never +// --expect hold|reorg which outcome of the honest side is a PASS. `--mode attack --gate off --expect reorg` is the +// rule's known-failed case (the attack succeeds without the gate) and must PASS; +// `--mode attack --gate off --expect hold` is the harness's own failed shape and must FAIL. +// +// node infra/fast-time/fork-gate.mjs --mode attack --gate on --expect hold [--joint 240] [--split 180] [--watch 150] +// [--window 60] [--honest-threads 1] [--attacker-threads 3] [--attacker-joint-threads 2] [--slot 0] [--out ] +// IGNEUMD and IGNEUM_MINER name the binaries. --slot k moves the ports and the devnet suffix so cases run side by side +// (infra/fast-time/fork-gate-gate.mjs runs the mission's six at once). +// +// A "reorg" is read from the chain, never from a key: the honest node's sink at the cut (its pre-cut tip) is asked of +// getVirtualChainFromBlock, and the node has reorged when that call lists removed chain blocks (the pre-cut tip left the +// selected chain). The 6 October harness read the sink's key and misread a block B had mined into the shared chain. +// +// Leftovers of an earlier run of the same slot are stopped by PID FILE, never by name (CLAUDE.md, 6 October 2026): every +// process this harness starts is written to /pids, and a pid is killed only when /proc//cmdline carries this +// slot's data directory or one of its ports. + +import { spawn } from 'node:child_process'; +import { createServer, connect as netConnect } from 'node:net'; +import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync, appendFileSync } from 'node:fs'; +import { Rpc } from '../../tools/finality-attacks/lib/rpc.mjs'; + +const ROOT = new URL('../../', import.meta.url).pathname; +const FILE = `${ROOT}infra/fast-time/override-60x.json`; +const IGNEUMD = process.env.IGNEUMD || `${ROOT}vendor/igneum-node/target-integration/release/igneumd`; +const CPU_MINER = process.env.IGNEUM_MINER || `${ROOT}vendor/igneum-node/target-integration/release/igneum-miner`; +const args = process.argv.slice(2); +const flag = (name, dflt) => { const i = args.indexOf(`--${name}`); return i >= 0 ? Number(args[i + 1]) : dflt; }; +const sflag = (name, dflt = null) => { const i = args.indexOf(`--${name}`); return i >= 0 ? args[i + 1] : dflt; }; +const MODE = sflag('mode', 'attack'); +const GATE = sflag('gate', 'on'); +const EXPECT = sflag('expect', MODE === 'attack' && GATE === 'on' ? 'hold' : 'reorg'); +const JOINT = flag('joint', 240), SPLIT = flag('split', 180), WATCH = flag('watch', 150), WINDOW = flag('window', 60); +const HT = flag('honest-threads', 1), AT = flag('attacker-threads', 3), AJT = flag('attacker-joint-threads', 2); +const SLOT = flag('slot', 0); +const GENESIS_BITS = flag('genesis-bits', 0x1f010000); +const CASE = sflag('case') || `${MODE}-gate-${GATE}-expect-${EXPECT}`; +const OUT = sflag('out') || `${ROOT}docs/plans/mission-item-4-gate/fork-gate-${CASE}.json`; +// nodes at BASE + i x 10 (gRPC, p2p, JSON-RPC, EVM RPC), the links at BASE + 31 and + 32; a slot is 40 ports wide. 30690 and up +// is clear of every other fast-time harness (difficulty 29790s, vote-or-burn 29990s, the 6 October fork gate 30090s, miner-stall +// 30290s, peer-drop 30390s, nuisance 30490s, headers-proof 30590s). +const BASE = 30690 + SLOT * 40, SUFFIX = 980 + SLOT; +const TMP = `/tmp/igneum-fast-time-fg${SLOT}`; +const NEVER = '18446744073709551615'; +if (!['attack', 'third', 'partition'].includes(MODE) || !['on', 'off'].includes(GATE) || !['hold', 'reorg'].includes(EXPECT)) { + console.error('usage: --mode attack|third|partition --gate on|off --expect hold|reorg'); process.exit(2); +} +const started = []; +const log = (...a) => console.log(new Date().toISOString().slice(11, 23), `fg${SLOT}`, ...a); +const sleep = (ms) => new Promise(r => setTimeout(r, ms)); +for (const b of [IGNEUMD, CPU_MINER]) if (!existsSync(b)) { console.error(`missing ${b}`); process.exit(2); } + +// leftovers of an earlier run of this slot, by pid file (never by name) +const PIDS = `${TMP}/pids`; +function stopLeftovers() { + if (!existsSync(PIDS)) return; + const ports = Array.from({ length: 40 }, (_, k) => `127.0.0.1:${BASE + k}`); + for (const line of readFileSync(PIDS, 'utf8').split('\n').filter(Boolean)) { + const pid = Number(line); + let cmd = ''; + try { cmd = readFileSync(`/proc/${pid}/cmdline`, 'utf8'); } catch { continue; } + if (!cmd.includes(TMP) && !ports.some(p => cmd.includes(p))) continue; + try { process.kill(pid, 'SIGKILL'); log(`stopped leftover pid ${pid} of an earlier run`); } catch { } + } +} +stopLeftovers(); +await sleep(1000); +rmSync(TMP, { recursive: true, force: true }); mkdirSync(TMP, { recursive: true }); +const track = (proc) => { started.push(proc); try { appendFileSync(PIDS, `${proc.pid}\n`); } catch { } }; + +const baseText = readFileSync(FILE, 'utf8'); +const field = (name) => { const m = new RegExp(`"${name}":\\s*([0-9]+)`).exec(baseText); return m ? +m[1] : undefined; }; +export function mergeOverrideText(text, fields) { + let out = text; + for (const k of Object.keys(fields)) out = out.replace(new RegExp(`\\s*"${k}":\\s*[^,}\\n]+,?`), ''); + const extra = Object.entries(fields).map(([k, v]) => `"${k}": ${typeof v === 'string' && !/^\d+$/.test(v) ? JSON.stringify(v) : v}`).join(', '); + return out.replace(/,?\s*}\s*$/, `,\n ${extra}\n}\n`); +} +const DAY_MS = field('pow_day_ms'); +const WEIGHT_WINDOW = field('weight_window') || 120; +const override = `${TMP}/override.json`; +writeFileSync(override, mergeOverrideText(baseText, { + genesis_bits: GENESIS_BITS, skip_proof_of_work: false, + fork_gate_activation_daa: GATE === 'on' ? '0' : NEVER, fork_gate_window_daa: WINDOW, + program_class_v3_activation_daa: NEVER, program_class_v4_activation_daa: NEVER, +})); +log(`case ${CASE}: mode ${MODE}, gate ${GATE} (window ${WINDOW} DAA), joint ${JOINT} s, split ${SPLIT} s, watch ${WATCH} s, honest ${HT} thread(s) each, attacker ${AT} (joint ${MODE === 'third' ? AJT : MODE === 'partition' ? HT : 0}), expect ${EXPECT}`); + +// a pass-through proxy: open = the link is up; closed = the partition +class Link { + constructor(listenPort, targetPort) { this.listenPort = listenPort; this.targetPort = targetPort; this.socks = new Set(); this.up = false; } + open() { + return new Promise((resolve) => { + this.server = createServer((client) => { + const upstream = netConnect(this.targetPort, '127.0.0.1'); + this.socks.add(client); this.socks.add(upstream); + client.pipe(upstream); upstream.pipe(client); + for (const s of [client, upstream]) { s.on('error', () => { }); s.on('close', () => { this.socks.delete(s); if (!client.destroyed) client.destroy(); if (!upstream.destroyed) upstream.destroy(); }); } + }); + this.server.listen(this.listenPort, '127.0.0.1', () => { this.up = true; resolve(this); }); + }); + } + close() { + return new Promise((resolve) => { + this.up = false; + for (const s of this.socks) { try { s.destroy(); } catch { } } + this.socks.clear(); + if (this.server) this.server.close(() => resolve()); else resolve(); + this.server = null; + }); + } +} + +class Node { + constructor(name, i, peers = []) { + this.name = name; this.i = i; this.grpcPort = BASE + i * 10; this.p2pPort = BASE + i * 10 + 1; this.jsonPort = BASE + i * 10 + 2; this.evmPort = BASE + i * 10 + 3; + this.peers = peers; this.dir = `${TMP}/${name}`; this.logFile = `${this.dir}/node.log`; + } + get grpc() { return `grpc://127.0.0.1:${this.grpcPort}`; } + async start() { + mkdirSync(this.dir, { recursive: true }); + const a = ['--devnet', `--devnet-suffix=${SUFFIX}`, '--nodnsseed', '--disable-upnp', '--nologfiles', '--enable-unsynced-mining', '--utxoindex', + `--appdir=${this.dir}`, `--rpclisten=127.0.0.1:${this.grpcPort}`, `--rpclisten-json=127.0.0.1:${this.jsonPort}`, `--evm-rpclisten=127.0.0.1:${this.evmPort}`, + `--listen=127.0.0.1:${this.p2pPort}`, `--override-params-file=${override}`, '--loglevel=info', '--yes']; + // --addpeer, not --connect: a dropped addpeer is dialled again, which is how a link heals + if (this.peers.length) for (const p of this.peers) a.push(`--addpeer=127.0.0.1:${p}`); else a.push('--outpeers=0'); + const out = openSync(this.logFile, 'a'); + this.proc = spawn(IGNEUMD, a, { stdio: ['ignore', out, out] }); + track(this.proc); + await sleep(1500); + if (this.proc.exitCode != null) throw new Error(`${this.name} exited ${this.proc.exitCode}: ${this.grepLog(/ERROR|Error|error|refused|invalid/).slice(-3).join(' | ')}`); + // the RPC must answer before the node is used (the 6 October harness called it one tick after the socket opened) + for (let i = 0; i < 20; i++) { + const rpc = new Rpc(`ws://127.0.0.1:${this.jsonPort}`); + try { if (await rpc.connect()) { await rpc.call('getBlockDagInfo'); this.rpc = rpc; break; } } catch { try { rpc.close(); } catch { } } + this.rpc = null; await sleep(500); + } + if (!this.rpc) throw new Error(`${this.name}: the RPC did not answer within 10 s`); + log(`${this.name} up pid ${this.proc.pid} json ${this.jsonPort} p2p ${this.p2pPort}${this.peers.length ? ` addpeer ${this.peers.join(',')}` : ''}`); + return this; + } + grepLog(re) { try { return readFileSync(this.logFile, 'utf8').split('\n').filter(l => re.test(l)); } catch { return []; } } + async block(hash) { const b = await this.rpc.call('getBlock', { hash, includeTransactions: false }); return b.block; } + async sink() { + const d = await this.rpc.call('getBlockDagInfo'); + const b = await this.block(d.sink); + const bw = b.header.blueWork; + const blueWork = typeof bw === 'string' ? BigInt(bw.startsWith('0x') ? bw : `0x${bw}`) : BigInt(bw); + return { hash: d.sink, blocks: +d.blockCount, daa: +b.header.daaScore, blue: +b.header.blueScore, blueWork, key: String(b.header.voteKeyHash) }; + } + /// whether `hash` (a block that was on this node's selected chain) has left it: the chain path from it to the sink + /// lists removed chain blocks exactly when it did + async reorgedFrom(hash) { + try { + const r = await this.rpc.call('getVirtualChainFromBlock', { startHash: hash, includeAcceptedTransactionIds: false }); + return (r.removedChainBlockHashes || []).length > 0; + } catch (e) { return null; } + } + async knows(hash) { try { await this.block(hash); return true; } catch { return false; } } +} +const miners = {}; +function miner(name, grpc, threads, secs, label = name) { + // `label` is the vote-key label (the key); `name` the log file and the handle, so a restarted miner keeps its key + const out = openSync(`${TMP}/${name}.log`, 'a'); + const p = spawn(CPU_MINER, ['mine', grpc, String(threads), String(secs), label, '--engine', 'igneum-pow', '--payout-label', label, '--status-secs', '30', '--no-vote'], { stdio: ['ignore', out, out], env: { ...process.env, IGNEUM_POW_DAY_MS: String(DAY_MS) } }); + track(p); miners[name] = p; + return p; +} +const minerKey = (name) => { try { const m = /vote_key_hash=([0-9a-f]{64})/.exec(readFileSync(`${TMP}/${name}.log`, 'utf8')); return m ? m[1] : null; } catch { return null; } }; +const links = []; +async function stopAll() { + for (const p of started.slice().reverse()) { try { p.kill('SIGINT'); } catch { } } + await sleep(1500); + for (const p of started) { try { p.kill('SIGKILL'); } catch { } } + for (const l of links) { try { await l.close(); } catch { } } +} +process.on('SIGINT', async () => { await stopAll(); process.exit(130); }); +process.on('unhandledRejection', async (e) => { log(`FAILED: ${e?.stack || e}`); await stopAll(); process.exit(3); }); + +// topology: H1 listens; H2 dials H1 (directly, or through a cuttable link in partition mode); B dials H1 and H2 through +// two cuttable links. The honest set is every node whose chain the gate is meant to keep: H1 and H2, or H1 alone in +// partition mode (where H2 is the heavier side). +const h1 = await new Node('h1', 0).start(); +let h2, b = null, side2; +if (MODE === 'partition') { + const l0 = await new Link(BASE + 31, h1.p2pPort).open(); links.push(l0); + h2 = await new Node('h2', 1, [l0.listenPort]).start(); + side2 = h2; +} else { + h2 = await new Node('h2', 1, [h1.p2pPort]).start(); + const l1 = await new Link(BASE + 31, h1.p2pPort).open(); links.push(l1); + const l2 = await new Link(BASE + 32, h2.p2pPort).open(); links.push(l2); + b = await new Node('b', 2, [l1.listenPort, l2.listenPort]).start(); + side2 = b; +} +const honest = MODE === 'partition' ? [h1] : [h1, h2]; +const side2Label = MODE === 'partition' ? 'fg-h2' : 'fg-b'; +await sleep(3000); +const t0 = Date.now(); +const since = () => ((Date.now() - t0) / 1000).toFixed(1); +const total = JOINT + SPLIT + WATCH + 60; + +// phase 1: together. The honest miners run through every phase; side 2 mines in the joint phase only in third and +// partition mode (its key must hold weight at the fork), never in attack mode (its key must be fresh). +miner('fg-h1', h1.grpc, HT, total); +if (MODE !== 'partition') miner('fg-h2', h2.grpc, HT, total); +if (MODE === 'third') miner('fg-b', b.grpc, AJT, JOINT); +if (MODE === 'partition') miner('fg-h2', h2.grpc, HT, JOINT); +await sleep(JOINT * 1000); +const keys = { h1: minerKey('fg-h1'), h2: MODE === 'partition' ? null : minerKey('fg-h2'), side2: MODE === 'third' || MODE === 'partition' ? minerKey(side2Label) : null }; +const joint = { h1: await h1.sink(), h2: await h2.sink(), side2: await side2.sink() }; +log(`phase 1 done at ${since()} s: H1 ${joint.h1.blocks} blocks sink ${joint.h1.hash.slice(0, 8)} daa ${joint.h1.daa}; H2 ${joint.h2.blocks} sink ${joint.h2.hash.slice(0, 8)}; side 2 (${side2.name}) ${joint.side2.blocks} sink ${joint.side2.hash.slice(0, 8)}; keys H1 ${keys.h1?.slice(0, 8)} H2 ${keys.h2?.slice(0, 8)} side2 ${keys.side2?.slice(0, 8) ?? 'fresh (none yet)'}`); +// the weight at the fork: builders of the last WEIGHT_WINDOW chain blocks of H1's chain and their mergesets, by key +async function shareAt(node, upTo, key) { + let cur = upTo, mine = 0, others = 0; + for (let i = 0; i < WEIGHT_WINDOW; i++) { + const blk = await node.block(cur); + const sp = blk.verboseData?.selectedParentHash; + for (const h of [cur, ...(blk.verboseData?.mergeSetBluesHashes || []).filter(x => x !== sp)]) { + const hb = h === cur ? blk : await node.block(h); + if (key && String(hb.header.voteKeyHash) === key) mine++; else others++; + } + if (!sp || +blk.header.daaScore <= 1) break; cur = sp; + } + return { side2: mine, others, side2_bps: mine + others ? Math.round(10000 * mine / (mine + others)) : null }; +} +const share = await shareAt(h1, joint.h1.hash, keys.side2); +log(`weight at the fork (last ${share.side2 + share.others} blue blocks of H1's chain): side 2 ${share.side2}, others ${share.others}, side 2 ${share.side2_bps} bps`); + +// phase 2: the partition; the honest side keeps mining, side 2 mines heavier +for (const l of links) await l.close(); +if (miners[side2Label]) { try { miners[side2Label].kill('SIGINT'); } catch { } await sleep(2000); } +miner(`${side2Label}-split`, side2.grpc, AT, SPLIT + WATCH + 60, side2Label); +log(`links cut at ${since()} s; side 2 (${side2.name}) now mines with ${AT} thread(s), the honest side with ${HT} each`); +await sleep(SPLIT * 1000); +if (!keys.side2) keys.side2 = minerKey(`${side2Label}-split`); +const preCut = {}; +for (const n of honest) preCut[n.name] = await n.sink(); +const split = { h1: await h1.sink(), h2: await h2.sink(), side2: await side2.sink() }; +const forkDaa = joint.h1.daa; +const forkDepthAtHeal = Math.max(split.side2.daa, split.h1.daa) - forkDaa; +const heavier = split.side2.blueWork > split.h1.blueWork; +log(`phase 2 done at ${since()} s: H1 ${split.h1.blocks} blocks sink ${split.h1.hash.slice(0, 8)} daa ${split.h1.daa} blue ${split.h1.blue} work ${split.h1.blueWork}; side 2 ${split.side2.blocks} sink ${split.side2.hash.slice(0, 8)} daa ${split.side2.daa} blue ${split.side2.blue} work ${split.side2.blueWork} (side 2 heavier: ${heavier}); fork depth ${forkDepthAtHeal} DAA against window ${WINDOW}`); + +// phase 3: heal and watch every honest node's chain +for (const l of links) await l.open(); +log(`links restored at ${since()} s; watching ${honest.map(n => n.name.toUpperCase()).join(' and ')} for ${WATCH} s`); +const samples = []; +const reorgAt = {}; +const healAt = Date.now(); +const side2PreHeal = split.side2; +while (Date.now() - healAt < WATCH * 1000) { + await sleep(5000); + const s = { t: +since() }; + for (const n of honest) { + const sk = await n.sink(); + const reorged = await n.reorgedFrom(preCut[n.name].hash); + s[n.name] = { blocks: sk.blocks, sink: sk.hash.slice(0, 16), daa: sk.daa, blue: sk.blue, key: sk.key.slice(0, 8), reorged, knows_side2_tip: await n.knows(side2PreHeal.hash) }; + if (reorged && reorgAt[n.name] == null) { reorgAt[n.name] = +since(); log(`${n.name.toUpperCase()} left its pre-cut chain at ${since()} s: sink ${sk.hash.slice(0, 16)} by ${sk.key.slice(0, 8)}`); } + } + const s2 = await side2.sink(); + s.side2 = { blocks: s2.blocks, sink: s2.hash.slice(0, 16), blue: s2.blue, reorged: await side2.reorgedFrom(side2PreHeal.hash) }; + samples.push(s); + if (samples.length % 6 === 0) log(`t=${since()} s ${honest.map(n => `${n.name.toUpperCase()} ${s[n.name].blocks} blocks sink ${s[n.name].sink.slice(0, 8)} ${s[n.name].reorged ? 'REORGED' : 'held'}`).join('; ')}; side 2 ${s2.blocks} blocks sink ${s2.hash.slice(0, 8)}`); +} +const last = samples.at(-1); +const refusals = {}; +for (const n of honest) refusals[n.name] = n.grepLog(/Fork choice: block .* not a sink candidate/).length; +const perNode = {}; +for (const n of honest) perNode[n.name] = { held: samples.every(s => s[n.name].reorged === false), reorged: last?.[n.name].reorged === true, reorg_at_s: reorgAt[n.name] ?? null, knows_side2_tip: last?.[n.name].knows_side2_tip === true, refusal_lines: refusals[n.name] }; +const every = (f) => honest.every(n => f(perNode[n.name])); +const checks = { + side2_under_a_third_at_fork: share.side2_bps != null && share.side2_bps * 3 < 10000, + fork_deeper_than_window: forkDepthAtHeal > WINDOW, + side2_heavier_at_heal: heavier, + every_honest_node_learned_side2_chain: every(p => p.knows_side2_tip), + every_honest_node_held: every(p => p.held), + every_honest_node_reorged: every(p => p.reorged), + every_honest_node_logged_a_refusal: every(p => p.refusal_lines > 0), + no_honest_node_logged_a_refusal: every(p => p.refusal_lines === 0), + side2_kept_its_chain: samples.every(s => s.side2.reorged === false), +}; +const wantUnderThird = MODE === 'attack'; +const good = EXPECT === 'hold' + ? checks.side2_under_a_third_at_fork === wantUnderThird && checks.fork_deeper_than_window && checks.side2_heavier_at_heal && checks.every_honest_node_learned_side2_chain && checks.every_honest_node_held && checks.every_honest_node_logged_a_refusal && checks.side2_kept_its_chain + : checks.side2_under_a_third_at_fork === wantUnderThird && checks.fork_deeper_than_window && checks.side2_heavier_at_heal && checks.every_honest_node_reorged && checks.no_honest_node_logged_a_refusal && checks.side2_kept_its_chain; +const needed = EXPECT === 'hold' + ? ['side2_under_a_third_at_fork', 'fork_deeper_than_window', 'side2_heavier_at_heal', 'every_honest_node_learned_side2_chain', 'every_honest_node_held', 'every_honest_node_logged_a_refusal', 'side2_kept_its_chain'] + : ['side2_under_a_third_at_fork', 'fork_deeper_than_window', 'side2_heavier_at_heal', 'every_honest_node_reorged', 'no_honest_node_logged_a_refusal', 'side2_kept_its_chain']; +const fails = needed.filter(k => (k === 'side2_under_a_third_at_fork' ? checks[k] !== wantUnderThird : !checks[k])); +const refusalExample = honest.map(n => n.grepLog(/Fork choice: block .* not a sink candidate/)[0]).find(Boolean)?.replace(/^.*?Fork choice/, 'Fork choice') ?? null; +const summary = { + pass: good, expect: EXPECT, case: CASE, mode: MODE, gate: GATE, window: WINDOW, joint: JOINT, split: SPLIT, watch: WATCH, + threads: { honest_each: HT, attacker_split: AT, attacker_joint: MODE === 'third' ? AJT : MODE === 'partition' ? HT : 0 }, + keys: Object.fromEntries(Object.entries(keys).map(([k, v]) => [k, short(v)])), share_at_fork: share, fork_daa: forkDaa, fork_depth_daa_at_heal: forkDepthAtHeal, + sinks: { joint: strip(joint), split: strip(split) }, per_node: perNode, checks, failed_checks: fails, refusal_example: refusalExample, + samples, node: IGNEUMD, miner: CPU_MINER, slot: SLOT, ports: { base: BASE, suffix: SUFFIX }, +}; +// a key in a summary is its first 8 hex and an ellipsis, never the 64 (7 October 2026: the 6 October summaries' raw keys +// turned the no-secrets check red on every CI run of their branch; a 64-hex value next to the word key is a secret shape) +const short = (k) => (typeof k === 'string' && k.length === 64 ? `${k.slice(0, 8)}…` : k); +function strip(o) { const r = {}; for (const [k, v] of Object.entries(o)) r[k] = { ...v, blueWork: v.blueWork.toString(), key: short(v.key) }; return r; } +mkdirSync(OUT.replace(/\/[^/]+$/, ''), { recursive: true }); +writeFileSync(OUT, JSON.stringify(summary, null, 2)); +log(`SUMMARY ${good ? 'PASS' : 'FAIL'} (${CASE}): side 2 held ${share.side2_bps ?? 0} bps of the blue blocks at the fork; fork depth ${forkDepthAtHeal} DAA against window ${WINDOW}; side 2 blue work ${split.side2.blueWork} against H1 ${split.h1.blueWork} at the heal; ${honest.map(n => `${n.name.toUpperCase()} ${perNode[n.name].reorged ? `reorged at ${perNode[n.name].reorg_at_s} s` : 'held'} (${perNode[n.name].refusal_lines} refusal lines, knows side 2's tip: ${perNode[n.name].knows_side2_tip})`).join('; ')}; side 2 kept its chain: ${checks.side2_kept_its_chain}${fails.length ? `; FAILED CHECK ${fails.join(', ')}` : ''}`); +log(`summary: ${OUT}`); +await stopAll(); +process.exit(good ? 0 : 1); diff --git a/tools/ci/whole-body-check.sh b/tools/ci/whole-body-check.sh index 983681055..b395986ea 100755 --- a/tools/ci/whole-body-check.sh +++ b/tools/ci/whole-body-check.sh @@ -9,7 +9,7 @@ # tools/ci/whole-body-check.sh --self-test # the real tools pass; a copy with the block removed fails set -euo pipefail cd "$(dirname "$0")/../.." -TOOLS=(tools/build-remote.sh tools/cross-remote.sh tools/workers-remote.sh infra/build-server/hands/move-hand.sh) +TOOLS=(tools/build-remote.sh tools/cross-remote.sh tools/workers-remote.sh tools/fast-time-remote.sh infra/build-server/hands/move-hand.sh) check() { # local f="$1" src src=$(grep -nE '^\. "\$HERE/(\.\./)+(infra/build-server/)?lib\.sh"' "$f" | head -1 | cut -d: -f1) diff --git a/tools/fast-time-remote.sh b/tools/fast-time-remote.sh new file mode 100755 index 000000000..c5f3e3a21 --- /dev/null +++ b/tools/fast-time-remote.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2034 # the BS_* context variables are read by lib.sh +# Run a fast-time harness (infra/fast-time/*.mjs, tools/finality-attacks) ON a build box instead of the Mac (CLAUDE.md, +# 7 October 2026: nothing heavy on the Mac), under a box slot with a holder line the workers dashboard shows and one JSONL +# line in /srv/builds/_log/builds.jsonl, the way tools/build-remote.sh runs cargo. The repo worktree's HEAD goes to the box +# through the bare mirror (checked out at /srv/builds/), the harness directories are overlaid by rsync (uncommitted +# edits travel, every written file re-stamped with touch in lib.sh's bs_overlay_dir), the command runs at the worktree root +# on the box with IGNEUMD and IGNEUM_MINER pointing at a node build already there (a fork worktree's target/release under the +# same worktree root, built by tools/build-remote.sh from that fork worktree), and the result directory comes back. +# +# tools/fast-time-remote.sh [--box N] [--priority gate|normal] --node-bin +# [--fetch ] [--label ] -- +# +# tools/fast-time-remote.sh --priority gate --node-bin vendor/igneum-node-horizon/target/release \ +# --fetch docs/plans/mission-item-4-gate -- node infra/fast-time/fork-gate-gate.mjs +# +# Class: `--priority gate` (nice 0, the full core set, a slot ahead of queued suites; box 1: a release or mission gate) or +# normal (nice 10 on the last 32 cores like a suite, box 2 by lib.sh bs_route's attack class). The command never starts with +# cargo: build on the box first with tools/build-remote.sh from the fork worktree, then point --node-bin at its target. +# Added for mission item 4 (the fork-gate gate), 7 October 2026. +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck disable=SC2034 +BS_TOOL=fast-time-remote +# shellcheck source=../infra/build-server/lib.sh +. "$HERE/../infra/build-server/lib.sh" + +{ # whole-body: bash parses this block entirely before running a line of it, so an edit to this file while a run is in + # flight cannot reach the running copy (7 Oct 2026: build-remote.sh was edited mid-run and died on shifted bytes after a 4-min build) +BOX="${BOX:-}"; PRIORITY="${PRIORITY:-normal}"; NODE_BIN=""; FETCH=""; LABEL=""; CMD=() +while [ $# -gt 0 ]; do + case "$1" in + --box) BOX="$2"; shift 2 ;; + --priority) PRIORITY="$2"; shift 2 ;; + --node-bin) NODE_BIN="$2"; shift 2 ;; + --fetch) FETCH="$2"; shift 2 ;; + --label) LABEL="$2"; shift 2 ;; + --) shift; CMD=("$@"); break ;; + *) bs_die "unknown argument $1 (the command follows --)" ;; + esac +done +[ ${#CMD[@]} -gt 0 ] || bs_die "no command: tools/fast-time-remote.sh [options] -- node infra/fast-time/.mjs ..." +[ -n "$NODE_BIN" ] || bs_die "--node-bin names the directory on the box that holds igneumd and igneum-miner (a fork worktree's target/release)" +case "$PRIORITY" in gate|normal) ;; *) bs_die "--priority takes gate or normal, not '$PRIORITY'" ;; esac +case "${CMD[0]}" in cargo) bs_die "the command must not be cargo: build with tools/build-remote.sh first" ;; esac +# the class: a gate runs at nice 0 on the full set, a slot ahead of queued suites, on box 1; normal is the bounded class on box 2 +if [ "$PRIORITY" = gate ]; then BR_NICE=0; BR_CORES=0; BR_JOBS_CAP=0; BR_PRIORITY=gate; BR_KIND=gate; else BR_NICE=10; BR_CORES=32; BR_JOBS_CAP=32; BR_PRIORITY=normal; BR_KIND=other; fi +export BR_NICE BR_CORES BR_JOBS_CAP BR_PRIORITY BR_KIND +if [ -z "$BOX" ]; then if [ "$PRIORITY" = gate ]; then BOX=1; else BOX=$(bs_route attack); fi; fi +bs_host "$BOX" +# the context by hand (bs_context wants a crate): the repo worktree root is the tree; lib.sh reads these +BS_TOP=$(git -C "$HERE" rev-parse --show-toplevel); BS_WT_ROOT="$BS_TOP"; BS_KIND=repo; BS_MIRROR="$BS_MIRROR_REPO"; BS_TOP_REL=. +BS_WT=$(basename "$BS_WT_ROOT"); BS_CRATE_REL=infra/fast-time; BS_REMOTE_WT="$BS_ROOT_REMOTE/$BS_WT"; BS_REMOTE_CRATE="$BS_REMOTE_WT" +BS_BRANCH=$(git -C "$BS_TOP" branch --show-current 2>/dev/null || true); BS_SHA=$(git -C "$BS_TOP" rev-parse HEAD); [ -n "$BS_BRANCH" ] || BS_BRANCH="detached-$(git -C "$BS_TOP" rev-parse --short HEAD)" +BS_LOCAL_DIRS="infra/fast-time tools/finality-attacks"; BS_VENDOR_REPOS="" +case "$NODE_BIN" in /*) ;; *) NODE_BIN="$BS_REMOTE_WT/$NODE_BIN" ;; esac +bs_log "box $BOX ($BS_HOST) for priority $PRIORITY: ${CMD[*]} from $BS_WT at $BS_SHA ($BS_BRANCH), node binaries $NODE_BIN" +bs_ssh "[ -x '$NODE_BIN/igneumd' ] && [ -x '$NODE_BIN/igneum-miner' ]" || bs_die "no igneumd and igneum-miner at $NODE_BIN on the box: build them there first (tools/build-remote.sh from the fork worktree)" +# the harness directories by overlay only, never a checkout of the worktree root: on a box where the root is no repo +# checkout (every box a node build alone has touched) remote-run's checkout mode replaces the directory, and at 13:44 UK on +# 7 October 2026 the first run of this wrapper took igneum-build-2's /srv/builds/igneum-wt-horizon/vendor (the fork sources +# and the gate binary just built there) with it +bs_wt_lock +bs_ssh "mkdir -p '$BS_REMOTE_WT'" +for d in $BS_LOCAL_DIRS; do bs_overlay_dir "$d"; done +bs_log "harness sources in place (overlay only; changed files re-stamped with touch by bs_overlay_dir)" +quoted=""; for a in "${CMD[@]}"; do quoted="$quoted $(printf '%q' "$a")"; done +cmd="export IGNEUMD=$(printf '%q' "$NODE_BIN/igneumd") IGNEUM_MINER=$(printf '%q' "$NODE_BIN/igneum-miner") IGNEUM_NODE_ROOT=$(printf '%q' "$BS_REMOTE_WT/"); $quoted" +BR_COMMAND="${CMD[*]}"; BR_TARGET=x86_64-unknown-linux-gnu; BR_ARTEFACTS=""; export BR_COMMAND BR_TARGET BR_ARTEFACTS +[ -n "$LABEL" ] || LABEL="fast-time ${CMD[*]}" +label="$BS_WT $LABEL; kind=$BR_KIND nice=$BR_NICE cores=$( [ "$BR_CORES" = 0 ] && echo 96 || echo "$BR_CORES")" +set +e +bs_remote_run "$BS_REMOTE_WT" "$label" "$cmd" +rc=$? +set -e +if [ -n "$FETCH" ]; then + mkdir -p "$BS_WT_ROOT/$FETCH" + bs_rsync -r "$BS_HOST:$BS_REMOTE_WT/$FETCH/" "$BS_WT_ROOT/$FETCH/" && bs_log "fetched $FETCH from the box" || bs_log "fetch of $FETCH failed (the run's rc was $rc)" +fi +bs_log "done: rc $rc" +[ "$rc" = 0 ] || exit "$rc" +exit 0 +}