From 165cdf9e8fbb51b772bb36dcb523b6619d65e6a2 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:38:43 +0000 Subject: [PATCH] fud ledger N9 second half closed: the joiner's fetch side held no proof whose record its trailing state refused; 70e4601e, the testnet lane's late-join re-run green in 35 s Co-Authored-By: Claude Fable 5.1 --- docs/fud-ledger.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 5772dbbae..858470236 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -2417,6 +2417,10 @@ Per tier: every fresh or wiped 0.3.18 install (a home miner's reinstall, a new p Fix on release-0.3.18-node: `ProofOracle::active_from` carries the switch (the sink takes it from `Params::proving_consensus_verify_daa` through `proof_sink`); the body rule, the IBD fetch and (through the rule) the relay retry apply to blocks at or above it only, so at never the node is 0.3.17 on this path, and with the switch set the history below it is not demanded. Known failed first on the pure gate (`the_carried_proof_rule_applies_from_the_switch_only`: the canary's block under never is not under the rule; the testnet's switch at genesis puts every block under it). What a switch set from genesis needs for a fresh join after the pool's retention is the testnet lane's go item: peers must serve the proofs of the pruning window. Fixed in dc141409 on release-0.3.19-node (09:36 UK; igneum-exec 27, consensus-core 123 with the gate's known-failed test, consensus 111 plus the two moved targets, p2p-flows 37, the kaspad and testing-integration checks clean on igneum-build-1); the fleet's re-run of the c18-1 wipe on it is the gate. The second half, the proof archive, is aea0ca5c on release-0.3.19-node (10:04 UK; igneum-exec 28 with `the_archive_serves_a_carried_proof_past_the_pools_window_and_drops_below_the_pruning_point`, p2p-flows 37, the kaspad and testing-integration checks clean): every carried record's proof kept on disk under the exec db dir's proofs/ by the carrying block's DAA, served after the pool's 600-chain-block window, dropped below the pruning point; the rule applies above the pruning point only. The late-join harness case (a fresh join after the window, on a chain with records) is the testnet lane's to run on its fast-time network with provers, with the hook e5f993d4 on ca3-v4-node and the pre-archive binary as the known-failed side. +### N9, second half, closed (7 October 2026, 13:36Z): a joiner never held a served proof whose record its trailing exec state refused + +The testnet lane's late-join gate on aea0ca5c (13:02 to 13:12Z): a fresh node B on the headers-proof path stalled at chain block f4f918f7 (DAA 1,828, above A's pruning point) with "carries 1 proof records whose proofs this peer did not deliver in 20 s", six times, while A's archive held the file for that DAA. The gap was B's fetch side, not A's serve: A answers `IgneumRequestProofRecords` from the pool and then the archive by proof hash (the file name), and sends the record; B's `submit_segment` ran the native check against B's own exec state before storing anything, that state trails the carried block on a joiner, the check refused the record and the proof was never held, so the body rule read `holds_proof` false for 20 s and failed the IBD. Fix 70e4601e (branch proof-hold-fix from c4459193; in 0.3.21): the proof is held by hash the moment its bytes match the record, before the native checks, in both submit paths (the pool entry, payable and offered to templates, still needs the checks); the serve side prints a line when it holds fewer proofs than asked. Gate: `a_served_proof_is_held_by_hash_even_when_the_native_check_refuses_the_record` (the empty state refuses the record and the old rule left the proof unheld; now held, no pool entry), and the testnet lane's re-run at 13:36Z on 70e4601e cherry-picked as 26e648ff: B joined A's 6,297-DAA chain through the headers proof and reached its sink in 35 s with 4,618 headers, 0 errors, every proof below the pool's window served from A's archive (testnet-go.md row 9b). + ### N10. A node resumed from a pre-fix snapshot holds thin records above the exec restart, and its export of chain block 72142 carries none of the eight transfers the block executed, so every replay from 27276 parts from the live root there (the fleet lane's port replays, 7 October 2026) The three 0.3.17 nodes (hub-1, p1-5090, PC 2) all read 0x9851d7e2... at 72142 while every port (the floor exporter, master's 6c3cc8b9 core, the kit's 263bf4ce) computes 0x8e1bef4b... from the node's `igneum_exportSegments [27276, tip]`; the roots agree over the 44,866 chain blocks 27276 to 72141. The cause is the export's input, not a rule. The hub's records for every block below its snapshot tip less 1,200 are thin: it resumed at 16:21Z on 6 October from seed-1's snapshot (tip 130,272, "130273 records (1200 full)"), cut by a binary still at `FULL_RECORDS` 1,200, so `thin()` had cleared `executed`, `skipped`, `mergeset`, `boundaries` and `carried` of every record from 27276 to about 129,000; p1-5090 and PC 2 carry the same lineage. The header fields survive, and they name the block: 72142 (DAA 111705, 05 October 2026 15:31Z, hash 0x665a30b8...) reads `gasUsed` 168,000, `pgasUsed` 1,600, `executionMicros` 230 and `transactions` 0 (its neighbours read 0, 0, 7 to 18 and 0). Eight 21,000-gas transfers were executed there (the txgen run of that afternoon); 72145 and 72146 carry one and two more. A scan of every record from 27276 to 72159 finds no other block with gas, proving gas or transactions, so 72142 is the first block at or above the restart that ever executed a transaction. The exporter rebuilds a segment's transactions from `executed`, finds none, replays the block as empty, and parts from the root the node computed with the transfers in it. Rewards, the pool credit and the 342 payouts below 72142 live in the header fields, which is why 45,000 reward-only blocks replayed clean.