Merge cache-history 459cdbc8 into master (gate: green on f0ae2039, recorded by tools/ci/pre-push.sh; landed on the box mirror)

This commit is contained in:
igneum-labs 2026-10-08 22:24:23 +00:00
commit aa46409015
5 changed files with 530 additions and 99 deletions

View file

@ -5216,21 +5216,21 @@
"manual_page": 38, "manual_page": 38,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "PASS", "run_status": "PASS",
"evidence_path": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence_path": "docs/plans/proving-enforcement/cache-history-2.json",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T21:37:02.905Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "EVM-08", "requirement_id": "EVM-08",
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the controlled verifier upgrade as a key succession (both pairs embedded, the window, the start refusal) and its fast-time crossing; the mixed-client crossing on the live network and the failed-distribution step are not run", "coverage": "partial: the controlled verifier upgrade as a key succession (both pairs embedded, the window, the start refusal) and its fast-time crossing; the mixed-client crossing on the live network and the failed-distribution step are not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5239,7 +5239,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"dependency": "the first pin into elf/prior/ (the node lane, key-succession-pin, tonight by 21:00) and the devnet-4 succession height (main, by 22:00 under the floor rule)", "dependency": "the first pin into elf/prior/ (the node lane, key-succession-pin, tonight by 21:00) and the devnet-4 succession height (main, by 22:00 under the floor rule)",
"approvals": { "approvals": {
@ -5254,13 +5254,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the controlled verifier upgrade as a key succession (both pairs embedded, the window, the start refusal) and its fast-time crossing; the mixed-client crossing on the live network and the failed-distribution step are not run", "coverage": "partial: the controlled verifier upgrade as a key succession (both pairs embedded, the window, the start refusal) and its fast-time crossing; the mixed-client crossing on the live network and the failed-distribution step are not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5269,7 +5269,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
} }
} }
} }
@ -5320,21 +5320,21 @@
"manual_page": 39, "manual_page": 39,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "NOT RUN", "run_status": "NOT RUN",
"evidence_path": "build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-exec.log; docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json; build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-consensus.log", "evidence_path": "build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-exec.log; docs/plans/proving-enforcement/cache-history-2.json; build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-consensus.log",
"run_id": "202-a284380b-5f50afd1", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T22:11:37.839Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "ZKP-01", "requirement_id": "ZKP-01",
"decision": "NOT RUN", "decision": "PASS",
"method": "native", "method": "native",
"cell": "suite:consensus", "cell": "harness:proving-enforcement",
"manifest_sha": "a284380b", "manifest_sha": "c591e63b",
"run_id": "202-a284380b-5f50afd1", "run_id": "enforced-proving-20261008-03",
"evidence": "build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-consensus.log", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: a proof-less or wrong-statement block refused by consensus", "coverage": "partial: the seven refusals as named tests (no proof never inserted; a wrong proof and another program id invalidate the block; the honest record paid once) and the fast-time crossing with a modified producer; the genuine-proof positive control through ordinary network paths is the testnet's live read, not run here",
"release_identity": { "release_identity": {
"commit": "a284380b", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5343,7 +5343,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T22:11:37.839Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"in_progress_since": "2026-10-08T19:32:50.856Z", "in_progress_since": "2026-10-08T19:32:50.856Z",
"approvals": { "approvals": {
@ -5380,13 +5380,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the seven refusals as named tests (no proof never inserted; a wrong proof and another program id invalidate the block; the honest record paid once) and the fast-time crossing with a modified producer; the genuine-proof positive control through ordinary network paths is the testnet's live read, not run here", "coverage": "partial: the seven refusals as named tests (no proof never inserted; a wrong proof and another program id invalidate the block; the honest record paid once) and the fast-time crossing with a modified producer; the genuine-proof positive control through ordinary network paths is the testnet's live read, not run here",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5395,7 +5395,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"suite:consensus": { "suite:consensus": {
"requirement_id": "ZKP-01", "requirement_id": "ZKP-01",
@ -5450,21 +5450,21 @@
"manual_page": 39, "manual_page": 39,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "PASS", "run_status": "PASS",
"evidence_path": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence_path": "docs/plans/proving-enforcement/cache-history-2.json",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T21:37:02.905Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "ZKP-02", "requirement_id": "ZKP-02",
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the pinned-id refusal on a real proof, the daemon's start refusal, key succession (the epochs, the accepted ids, a verdict counting only where its pair is accepted, the seven refusals on both sides of the height, the start refusal under a succession, the real-proof refusal of a pair the epoch does not accept) and the fast-time crossing of a scheduled succession with a real proof under each pair; the downgrade through an old node path is not run", "coverage": "partial: the pinned-id refusal on a real proof, the daemon's start refusal, key succession (the epochs, the accepted ids, a verdict counting only where its pair is accepted, the seven refusals on both sides of the height, the start refusal under a succession, the real-proof refusal of a pair the epoch does not accept) and the fast-time crossing of a scheduled succession with a real proof under each pair; the downgrade through an old node path is not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5473,7 +5473,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"dependency": "the mixed-pair crossing needs the node lane's first pin into elf/prior/ (key-succession-pin, tonight by 21:00) and the next-pair proof (build-2:/home/build/enforced-fixtures/next-pair-block-56-shard-0-compressed.bin)", "dependency": "the mixed-pair crossing needs the node lane's first pin into elf/prior/ (key-succession-pin, tonight by 21:00) and the next-pair proof (build-2:/home/build/enforced-fixtures/next-pair-block-56-shard-0-compressed.bin)",
"approvals": { "approvals": {
@ -5488,13 +5488,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the pinned-id refusal on a real proof, the daemon's start refusal, key succession (the epochs, the accepted ids, a verdict counting only where its pair is accepted, the seven refusals on both sides of the height, the start refusal under a succession, the real-proof refusal of a pair the epoch does not accept) and the fast-time crossing of a scheduled succession with a real proof under each pair; the downgrade through an old node path is not run", "coverage": "partial: the pinned-id refusal on a real proof, the daemon's start refusal, key succession (the epochs, the accepted ids, a verdict counting only where its pair is accepted, the seven refusals on both sides of the height, the start refusal under a succession, the real-proof refusal of a pair the epoch does not accept) and the fast-time crossing of a scheduled succession with a real proof under each pair; the downgrade through an old node path is not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5503,7 +5503,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
} }
} }
}, },
@ -5536,21 +5536,21 @@
"manual_page": 39, "manual_page": 39,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "NOT RUN", "run_status": "NOT RUN",
"evidence_path": "build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-exec.log; docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence_path": "build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-exec.log; docs/plans/proving-enforcement/cache-history-2.json",
"run_id": "202-a284380b-5f50afd1", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T22:11:37.839Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "ZKP-03", "requirement_id": "ZKP-03",
"decision": "NOT RUN", "decision": "PASS",
"method": "native", "method": "native",
"cell": "suite:exec", "cell": "harness:proving-enforcement",
"manifest_sha": "a284380b", "manifest_sha": "c591e63b",
"run_id": "202-a284380b-5f50afd1", "run_id": "enforced-proving-20261008-03",
"evidence": "build-1:/srv/artefacts/tas/202-a284380b-5f50afd1/node-a284380b/box4-exec.log", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: a snapshot under another digest refused, the epoch streams bound to the digest", "coverage": "partial: the chain binding (a record signed for another network), the replay, a wrong block, a wrong shard, a stale record outside the window; the fork and replayed-sync steps are not run",
"release_identity": { "release_identity": {
"commit": "a284380b", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5559,7 +5559,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T22:11:37.839Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"in_progress_since": "2026-10-08T19:32:50.856Z", "in_progress_since": "2026-10-08T19:32:50.856Z",
"approvals": { "approvals": {
@ -5596,13 +5596,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the chain binding (a record signed for another network), the replay, a wrong block, a wrong shard, a stale record outside the window; the fork and replayed-sync steps are not run", "coverage": "partial: the chain binding (a record signed for another network), the replay, a wrong block, a wrong shard, a stale record outside the window; the fork and replayed-sync steps are not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5611,7 +5611,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
} }
} }
}, },
@ -5644,21 +5644,21 @@
"manual_page": 40, "manual_page": 40,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "PASS", "run_status": "PASS",
"evidence_path": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence_path": "docs/plans/proving-enforcement/cache-history-2.json",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T21:37:02.905Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "ZKP-04", "requirement_id": "ZKP-04",
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: an altered payout address (after signing and re-signed), a statement over altered rewards or payouts vetoed natively, the inputs commitment of P22 stage 1 (shard 0 and the aggregator carry the commitment the node recomputes) and the derivation commitment of stage 2 (the payouts derived in the guest from the carried records); the rewards' proved derivation is P22 stage 3, PENDING", "coverage": "partial: an altered payout address (after signing and re-signed), a statement over altered rewards or payouts vetoed natively, the inputs commitment of P22 stage 1 (shard 0 and the aggregator carry the commitment the node recomputes) and the derivation commitment of stage 2 (the payouts derived in the guest from the carried records); the rewards' proved derivation is P22 stage 3, PENDING",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5667,7 +5667,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"dependency": "the proof side of the derivation (P22 stages 1 to 3) changes both guests' public values and so both program ids, so it ships only through a key succession (docs/design/key-succession.md, key-succession-node 291ee6ae); stage 1 (the inputs commitment carried by shard 0 and the aggregator, vetoed natively) is on branch p22-stage-1 under test since 18:46 UK; the clocks (stage 1 09:00, stage 2 14:00, stage 3's design 18:00 UK on 9 October 2026) stand because the succession's first height is asked of main by 22:00 under the floor rule; without a named height the stages are built and tested on their branch and wait for the succession that carries them", "dependency": "the proof side of the derivation (P22 stages 1 to 3) changes both guests' public values and so both program ids, so it ships only through a key succession (docs/design/key-succession.md, key-succession-node 291ee6ae); stage 1 (the inputs commitment carried by shard 0 and the aggregator, vetoed natively) is on branch p22-stage-1 under test since 18:46 UK; the clocks (stage 1 09:00, stage 2 14:00, stage 3's design 18:00 UK on 9 October 2026) stand because the succession's first height is asked of main by 22:00 under the floor rule; without a named height the stages are built and tested on their branch and wait for the succession that carries them",
"approvals": { "approvals": {
@ -5682,13 +5682,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: an altered payout address (after signing and re-signed), a statement over altered rewards or payouts vetoed natively, the inputs commitment of P22 stage 1 (shard 0 and the aggregator carry the commitment the node recomputes) and the derivation commitment of stage 2 (the payouts derived in the guest from the carried records); the rewards' proved derivation is P22 stage 3, PENDING", "coverage": "partial: an altered payout address (after signing and re-signed), a statement over altered rewards or payouts vetoed natively, the inputs commitment of P22 stage 1 (shard 0 and the aggregator carry the commitment the node recomputes) and the derivation commitment of stage 2 (the payouts derived in the guest from the carried records); the rewards' proved derivation is P22 stage 3, PENDING",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5697,7 +5697,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
} }
} }
}, },
@ -5730,21 +5730,21 @@
"manual_page": 40, "manual_page": 40,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "PASS", "run_status": "PASS",
"evidence_path": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence_path": "docs/plans/proving-enforcement/cache-history-2.json",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T21:37:02.905Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "ZKP-05", "requirement_id": "ZKP-05",
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: a duplicate of a paid record pays nothing and the honest record pays once; the race, reorder and crash-recover steps are not run", "coverage": "partial: a duplicate of a paid record pays nothing and the honest record pays once; the race, reorder and crash-recover steps are not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5753,7 +5753,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"approvals": { "approvals": {
"scope_approved": null, "scope_approved": null,
@ -5767,13 +5767,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: a duplicate of a paid record pays nothing and the honest record pays once; the race, reorder and crash-recover steps are not run", "coverage": "partial: a duplicate of a paid record pays nothing and the honest record pays once; the race, reorder and crash-recover steps are not run",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5782,7 +5782,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
} }
} }
}, },
@ -5940,21 +5940,21 @@
"manual_page": 41, "manual_page": 41,
"owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "owner_lane": "enforced-proving lane (a6e8f84588b809d62)",
"run_status": "PASS", "run_status": "PASS",
"evidence_path": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence_path": "docs/plans/proving-enforcement/cache-history-2.json",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"updated": "2026-10-08T21:37:02.905Z", "updated": "2026-10-08T22:24:23.945Z",
"evidence_record": { "evidence_record": {
"requirement_id": "ZKP-08", "requirement_id": "ZKP-08",
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the body rule and the payment rule read one floor, a producer with its body rule off still pays nothing on honest nodes (the fast-time crossing); the replacement-prover and authority steps are not run; the proof side of the derivation is P22 stage 3, PENDING", "coverage": "partial: the body rule and the payment rule read one floor, a producer with its body rule off still pays nothing on honest nodes (the fast-time crossing); the replacement-prover and authority steps are not run; the proof side of the derivation is P22 stage 3, PENDING",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5963,7 +5963,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
}, },
"dependency": "the proof side of the derivation (P22 stages 1 to 3) changes both guests' public values and so both program ids, so it ships only through a key succession (docs/design/key-succession.md, key-succession-node 291ee6ae); stage 1 (the inputs commitment carried by shard 0 and the aggregator, vetoed natively) is on branch p22-stage-1 under test since 18:46 UK; the clocks (stage 1 09:00, stage 2 14:00, stage 3's design 18:00 UK on 9 October 2026) stand because the succession's first height is asked of main by 22:00 under the floor rule; without a named height the stages are built and tested on their branch and wait for the succession that carries them", "dependency": "the proof side of the derivation (P22 stages 1 to 3) changes both guests' public values and so both program ids, so it ships only through a key succession (docs/design/key-succession.md, key-succession-node 291ee6ae); stage 1 (the inputs commitment carried by shard 0 and the aggregator, vetoed natively) is on branch p22-stage-1 under test since 18:46 UK; the clocks (stage 1 09:00, stage 2 14:00, stage 3's design 18:00 UK on 9 October 2026) stand because the succession's first height is asked of main by 22:00 under the floor rule; without a named height the stages are built and tested on their branch and wait for the succession that carries them",
"approvals": { "approvals": {
@ -5978,13 +5978,13 @@
"decision": "PASS", "decision": "PASS",
"method": "native", "method": "native",
"cell": "harness:proving-enforcement", "cell": "harness:proving-enforcement",
"manifest_sha": "3f672661", "manifest_sha": "c591e63b",
"run_id": "enforced-proving-20261008-02", "run_id": "enforced-proving-20261008-03",
"evidence": "docs/plans/proving-enforcement/succession-360-window-300-vcache-7.json", "evidence": "docs/plans/proving-enforcement/cache-history-2.json",
"in_progress": false, "in_progress": false,
"coverage": "partial: the body rule and the payment rule read one floor, a producer with its body rule off still pays nothing on honest nodes (the fast-time crossing); the replacement-prover and authority steps are not run; the proof side of the derivation is P22 stage 3, PENDING", "coverage": "partial: the body rule and the payment rule read one floor, a producer with its body rule off still pays nothing on honest nodes (the fast-time crossing); the replacement-prover and authority steps are not run; the proof side of the derivation is P22 stage 3, PENDING",
"release_identity": { "release_identity": {
"commit": "3f672661", "commit": "c591e63b",
"lockfile": "", "lockfile": "",
"binary": "", "binary": "",
"network_object": "", "network_object": "",
@ -5993,7 +5993,7 @@
}, },
"claim_impact": "", "claim_impact": "",
"reviewer": "", "reviewer": "",
"at": "2026-10-08T21:37:02.905Z" "at": "2026-10-08T22:24:23.945Z"
} }
} }
} }
@ -6121,7 +6121,20 @@
"updated": "2026-10-08T22:22:49.946Z", "updated": "2026-10-08T22:22:49.946Z",
"evidence_record": { "evidence_record": {
"reason": "proving on the mining configuration is the fleet lane's", "reason": "proving on the mining configuration is the fleet lane's",
"at": "2026-10-08T22:22:49.946Z" "at": "2026-10-08T22:22:49.946Z",
"method": "static",
"requirement_id": "CAP-02",
"decision": "NOT RUN",
"reviewer": "",
"claim_impact": "",
"release_identity": {
"commit": "",
"lockfile": "",
"binary": "",
"network_object": "",
"activation": "",
"profile_hashes": ""
}
}, },
"approvals": { "approvals": {
"scope_approved": null, "scope_approved": null,

View file

@ -0,0 +1,147 @@
{
"case": "cache-history",
"node": "/srv/builds/igneum-wt-cache/vendor/igneum-node/target/release/igneumd",
"proveBin": "/srv/builds/igneum-wt-cache/proving/igneum-prove/target/release",
"pair": {
"shard": "0x51cd8cba314a32b60fac393949a4571714da6d6656717d286011601b2a163fe7",
"aggregator": "0x05b395ec238f67406084f8a449d400f64c87dc62151daebf66695864727ded8a"
},
"startedAt": "2026-10-08T21:53:32.526Z",
"phases": {
"context": {
"block": 165,
"submit": {
"accepted": true,
"block": "0x4259577a6be0f3cf3cb1f1512b8df758caa2790d5cafebc791a55076d9cd1839",
"keyHash": "0x6ce6a6cfb1e7d69f52e0764cd4ad005d244097ee9773f7918c2ab532ad73d2df",
"new": true,
"number": "0xa5",
"reason": "accepted",
"shard": 0
},
"observed": {
"paid": [],
"carried": []
},
"verifies": {
"cacheAnswers": 0,
"calls": 1,
"contextRefusals": 1,
"sp1": 0
},
"refusals": [
"a carried proof record's proof does not verify: shard record block 165 shard 0 by 6ce6a6cfb1e7d69f52e0764cd4ad005d244097ee9773f7918c2ab532ad73d2df (proof f74f7f7daf2cdcb0): shard record block 165 shard 0 by 6ce6a6cfb1e7d69f52e0764cd4ad005d244097ee9773f7918c2ab532ad73d2df: the proof's public values hash to 0x58d620e493a23ebdacdec4f3c3f46e5936a18fbdcb3880341e2bb8b1555f7955, the record's statement is 0xd8191e436529a541554168fb68a9f6663485d6b743d1b49e15ec3bbf3a5c17f0, disconnecting from peer 127.0.0.1:49762."
]
},
"honest": {
"block": 94,
"submit": {
"accepted": true,
"block": "0x6e958a1b931c6eacce696422a6611151848bb65ca8d99c36510bd7fab2925c39",
"keyHash": "0x4a28017035561e93c93032f70dba67436b68506efd3ac761f608df142c8a7594",
"new": true,
"number": "0x5e",
"reason": "accepted",
"shard": 0
},
"observed": {
"paid": [
{
"carrierNumber": "0x169",
"keyHash": "0x4a28017035561e93c93032f70dba67436b68506efd3ac761f608df142c8a7594",
"payout": "0xc3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3",
"shard": 0,
"wei": "0x8cc4d14f7888000"
}
],
"carried": [
{
"signer": "0x4a28017035561e93c93032f70dba67436b68506efd3ac761f608df142c8a7594",
"carrier": "0x169",
"rejected": "",
"paidWei": "0x8cc4d14f7888000"
},
{
"signer": "0x4a28017035561e93c93032f70dba67436b68506efd3ac761f608df142c8a7594",
"carrier": "0x16a",
"rejected": "shard already paid",
"paidWei": "0x0"
}
]
},
"verifies": {
"cacheAnswers": 1,
"calls": 2,
"contextRefusals": 1,
"sp1": 1
}
},
"invalid": {
"blocks": [
465,
591
],
"submits": [
{
"accepted": true,
"block": "0xb80c043ced2e770092ab96769fbba1533df9a9a7eb61e054cbd7a98c678f6af9",
"keyHash": "0x89470283d097209eb0287ba87717938b8642c19b12bb37b5e30ed2a4328f2aaf",
"new": true,
"number": "0x1d1",
"reason": "accepted",
"shard": 0
},
{
"accepted": true,
"block": "0xd64c1a9c8d6c901ae1ed2cb2c1afccfa35113dcf1d38704477dfbf6a810d79e3",
"keyHash": "0xaa474491707c6931a3d6d2fdb84e4d91fa3f3c57b7776b9c1fb1b01a1f96678a",
"new": true,
"number": "0x24f",
"reason": "accepted",
"shard": 0
}
],
"verifies": {
"after3a": {
"cacheAnswers": 1,
"calls": 3,
"contextRefusals": 1,
"sp1": 2
},
"after3b": {
"cacheAnswers": 2,
"calls": 3,
"contextRefusals": 1,
"sp1": 2
}
},
"refusals": {
"after3a": 2,
"after3b": 3
},
"reasons": [
"a carried proof record's proof does not verify: shard record block 165 shard 0 by 6ce6a6cfb1e7d69f52e0764cd4ad005d244097ee9773f7918c2ab532ad73d2df (proof f74f7f7daf2cdcb0): shard record block 165 shard 0 by 6ce6a6cfb1e7d69f52e0764cd4ad005d244097ee9773f7918c2ab532ad73d2df: the proof's public values hash to 0x58d620e493a23ebdacdec4f3c3f46e5936a18fbdcb3880341e2bb8b1555f7955, the record's statement is 0xd8191e436529a541554168fb68a9f6663485d6b743d1b49e15ec3bbf3a5c17f0, disconnecting from peer 127.0.0.1:49762.",
"a carried proof record's proof does not verify: shard record block 465 shard 0 by 89470283d097209eb0287ba87717938b8642c19b12bb37b5e30ed2a4328f2aaf (proof 79e76573983222b5): shard record block 465 shard 0 by 89470283d097209eb0287ba87717938b8642c19b12bb37b5e30ed2a4328f2aaf: the proof bytes are not a bincode SP1 proof: invalid value: integer `4284109422`, expected variant index 0 <= i < 4, disconnecting from peer 127.0.0.1:47690.",
"a carried proof record's proof does not verify: shard record block 591 shard 0 by aa474491707c6931a3d6d2fdb84e4d91fa3f3c57b7776b9c1fb1b01a1f96678a (proof 79e76573983222b5): shard record block 465 shard 0 by 89470283d097209eb0287ba87717938b8642c19b12bb37b5e30ed2a4328f2aaf: the proof bytes are not a bincode SP1 proof: invalid value: integer `4284109422`, expected variant index 0 <= i < 4, disconnecting from peer 127.0.0.1:51924."
]
}
},
"proof": {
"block": 94,
"statement": "0x58d620e493a23ebdacdec4f3c3f46e5936a18fbdcb3880341e2bb8b1555f7955",
"native": "0x58d620e493a23ebdacdec4f3c3f46e5936a18fbdcb3880341e2bb8b1555f7955",
"bytes": 1272961,
"sha256": "0xf74f7f7daf2cdcb031add25f28a0787d278de1079aa81aa51ac3f2e744750df7",
"hostLine": "RESULT compressed shard 0: prove 61.0 s, proof 1272961 bytes, verify 0.080 s, VERIFIED; statement 0x58d620e493a23ebdacdec4f3c3f46e5936a18fbdcb3880341e2bb8b1555f7955 proof sha256 0xf74f7f7daf2cdcb031add25f28a0787d278de1079aa81aa51ac3f2e744750df7 prover 0xc3c3c3c3c3c3c3c3c3C3C3c3C3C3C3c3C3C3c3c3 at 2026-10-08T21:56:24Z"
},
"verdict": {
"paidOnce": true,
"sp1Verifies": 2,
"cacheAnswers": 2,
"contextRefused": true,
"contextCheap": true,
"invalidRefusedTwiceNoVerify": true,
"pass": true
},
"endedAt": "2026-10-08T22:05:36.331Z"
}

View file

@ -0,0 +1,254 @@
#!/usr/bin/env node
// The two-node cache-history case (review B F01, Phase 1 item (c), 8 October 2026): on a node with the verdict cache
// of verdict-cache-fix-node 3f672661, a proof's bytes refused once for CONTEXT (another statement) must still pay
// when the same bytes arrive later as their own honest record, answered from the cached facts with no second SP1
// verify; bytes refused once for being INVALID must be refused again at a later carrier, from the cache, with no
// second verify. Three local nodes at fast time as in proving-enforcement.mjs: H1 and H2 honest (the verifier in
// consensus), A the carrier (skip rule, trust verify) whose templates carry what its pool holds.
//
// The real proof is one of this chain's own blocks: after the chain has run, block n is exported from H1
// (igneum_exportSegments), cut by igneum-prove-export and proven compressed by igneum-prove-host on the box's CPU
// (about 70 to 110 s), so its statement is H1's native statement for (n, shard 0, PAYOUT). The node binaries and the
// proving binaries must carry the SAME pair (the node's elf/ overlay and the host's embedded pin: pin C tonight), and
// the node's object names that pair (proving_shard_program_id / proving_aggregator_id from the manifest).
//
// node infra/fast-time/proving-cache-history.mjs --prove-bin <dir with igneum-prove-host and igneum-prove-export>
// [--before 90] [--after 120] [--slot 0] [--out <json>]
//
// Verdict: (1) block n shard 0 paid exactly once, to PAYOUT; (2) H1 ran the SP1 verifier exactly twice over the run (the real
// proof once, the invalid bytes once): the context refusal of phase 1 is a pre-check (the statement differs) that runs no
// verifier and is never cached, re-read at every carrier; (3) the context refusal and the invalid refusal both read in H1's
// log; (4) the second use of the invalid bytes is answered from the cache with no new verify (cacheAnswers at least 1).
import { spawn, spawnSync } from 'node:child_process';
import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync, appendFileSync } from 'node:fs';
import { createHash, randomBytes } from 'node:crypto';
const ROOT = new URL('../../', import.meta.url).pathname;
const FILE = `${ROOT}infra/fast-time/override-60x.json`;
const MANIFEST = `${ROOT}proving/igneum-prove/elf/manifest.json`;
const IGNEUMD = process.env.IGNEUMD || `${ROOT}vendor/igneum-node/target/release/igneumd`;
const CPU_MINER = process.env.IGNEUM_MINER || `${ROOT}vendor/igneum-node/target/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) => { const i = args.indexOf(`--${name}`); return i >= 0 ? args[i + 1] : dflt; };
const BEFORE = flag('before', 90), AFTER = flag('after', 120), SLOT = flag('slot', 0);
const PROVE_BIN = sflag('prove-bin', `${ROOT}proving/igneum-prove/target/release`);
const GENESIS_BITS = flag('genesis-bits', 0x1f010000);
const OUT = sflag('out') || `${ROOT}docs/plans/proving-enforcement/cache-history.json`;
const BASE = 30890 + SLOT * 40, SUFFIX = 985 + SLOT;
const CHAIN = `igneum-devnet-${SUFFIX}`;
const TMP = `/tmp/igneum-fast-time-ch${SLOT}`;
const PIDS = `${TMP}/pids`;
const NEVER = '18446744073709551615';
for (const b of [IGNEUMD, CPU_MINER, `${PROVE_BIN}/igneum-prove-host`, `${PROVE_BIN}/igneum-prove-export`]) if (!existsSync(b)) { console.error(`missing ${b}`); process.exit(2); }
const t0 = Date.now();
const log = (s) => { const t = new Date().toISOString().slice(11, 23); console.log(`${t} ch${SLOT} ${s}`); };
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const hex = (b) => '0x' + Buffer.from(b).toString('hex');
const sha256 = (b) => createHash('sha256').update(b).digest('hex');
// leftovers of an earlier run on this slot: by the pid file only
rmSync(TMP, { recursive: true, force: true }); mkdirSync(TMP, { recursive: true });
const started = [];
const track = (proc) => { started.push(proc); try { appendFileSync(PIDS, `${proc.pid}\n`); } catch { } };
// the override: the 60x file with the pair named from the manifest, the verifier in consensus from genesis, no succession
let baseText = readFileSync(FILE, 'utf8');
for (const k of ['proving_payment_activation_daa']) baseText = baseText.replace(new RegExp(`\\s*"${k}":\\s*[^,}\\n]+,?`), '');
const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'));
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) && v !== 'true' && v !== 'false' ? JSON.stringify(v) : v}`).join(', ');
return out.replace(/,?\s*}\s*$/, `,\n ${extra}\n}\n`);
}
const override = `${TMP}/override.json`;
writeFileSync(override, mergeOverrideText(baseText, {
genesis_bits: GENESIS_BITS, skip_proof_of_work: false, proving_v0_activation_daa: '0', proving_consensus_verify_daa: '0',
proving_shard_program_id: manifest.shard.program_id, proving_aggregator_id: manifest.aggregator.program_id,
verifier_in_consensus: 'true', proving_key_succession_daa: NEVER, proving_key_succession_window_daa: '120',
proving_next_shard_program_id: '', proving_next_aggregator_id: '',
program_class_v3_activation_daa: NEVER, program_class_v4_activation_daa: NEVER,
}));
const DAY_MS = (() => { const m = /"pow_day_ms":\s*([0-9]+)/.exec(baseText); return m ? +m[1] : 1440000; })();
class Node {
constructor(name, i, peers = [], env = {}) {
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.env = env; 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 out = openSync(this.logFile, 'a');
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'];
if (this.peers.length) for (const p of this.peers) a.push(`--addpeer=127.0.0.1:${p}`); else a.push('--outpeers=0');
this.proc = spawn(IGNEUMD, a, { stdio: ['ignore', out, out], env: { ...process.env, ...this.env } });
track(this.proc);
for (let k = 0; k < 60; k++) {
await sleep(1000);
try { await this.exec('igneum_getExecStatus', []); log(`${this.name} up (pid ${this.proc.pid}) after ${k + 1} s`); return; } catch { }
if (this.proc.exitCode !== null) throw new Error(`${this.name} exited ${this.proc.exitCode}: ${readFileSync(this.logFile, 'utf8').split('\n').slice(-5).join(' | ')}`);
}
throw new Error(`${this.name} did not answer in 60 s`);
}
async exec(method, params) {
const r = await fetch(`http://127.0.0.1:${this.evmPort}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }) });
const j = await r.json();
if (j.error) throw new Error(`${method}: ${j.error.message || JSON.stringify(j.error)}`);
return j.result;
}
logText() { try { return readFileSync(this.logFile, 'utf8'); } catch { return ''; } }
stop() { try { this.proc.kill('SIGINT'); } catch { } }
}
function startMiner(node, label, secs) {
const out = openSync(`${TMP}/${label}.log`, 'a');
const p = spawn(CPU_MINER, ['mine', node.grpc, '1', 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);
return p;
}
function signRecord(label, chain, block, number, shard, payout, statement, proofHash) {
const r = spawnSync(CPU_MINER, ['sign-record', label, chain, block, String(number), String(shard), payout, statement, proofHash], { encoding: 'utf8' });
if (r.status !== 0) throw new Error(`sign-record failed: ${r.stderr || r.stdout}`);
return JSON.parse(r.stdout.trim().split('\n').pop());
}
const H1 = new Node('H1', 0);
const H2 = new Node('H2', 1, [H1.p2pPort]);
const A = new Node('A', 2, [H1.p2pPort, H2.p2pPort], { IGNEUM_TEST_SKIP_PROOF_RULE: '1', IGNEUM_PROOF_VERIFY: 'trust' });
const nodes = [H1, H2, A];
let miners = [];
async function stopAll() {
for (const m of miners) { try { m.kill('SIGTERM'); } catch { } }
for (const n of nodes) n.stop();
await sleep(2000);
for (const p of started) { try { p.kill('SIGKILL'); } catch { } }
}
process.on('SIGINT', async () => { await stopAll(); process.exit(130); });
const PAYOUT = '0x' + 'c3'.repeat(20);
async function tipNumber(node) { const s = await node.exec('igneum_getExecStatus', []); return Number(s.executedTip ?? 0); }
async function sameTip(a, h) {
try { const x = await a.exec('igneum_getExecStatus', []); const y = await h.exec('igneum_getExecStatus', []); return x.executedTipHash && x.executedTipHash === y.executedTipHash; } catch { return false; }
}
async function rejoin(label) {
for (let k = 0; k < 120; k++) { if (await sameTip(A, H1)) { log(`${label}: A is on H1's tip (${k * 5} s)`); return true; } await sleep(5000); }
log(`${label}: A did not rejoin H1's tip in 600 s`); return false;
}
async function verifies(node) { const s = await node.exec('igneum_getProvingStatus', []); return s.verifies || { calls: 0, sp1: 0, contextRefusals: 0, cacheAnswers: 0 }; }
const refusals = (node) => (node.logText().match(/a carried proof record's proof does not verify: [^\n]*/g) || []);
async function submitVia(node, name, record, proof) {
let out;
try { out = await node.exec('igneum_submitProofRecord', [{ record, proof }]); } catch (e) { out = { accepted: false, reason: String(e.message) }; }
log(`${name}: A's pool ${out.accepted ? 'accepted' : 'refused'} (${out.reason || ''})`);
return out;
}
async function observe(n) {
try {
const r = await H1.exec('igneum_getProofRecords', ['0x' + n.toString(16)]);
return { paid: (r.paid || []).filter(Boolean), carried: (r.carried || []).map(c => ({ signer: c.keyHash, carrier: c.carrierNumber, rejected: c.rejected, paidWei: c.paidWei })) };
} catch (e) { return { error: e.message }; }
}
/// A real proof of block n of this chain: exported from H1, cut and proven by the host (CPU), returning the proof
/// bytes and the statement the host printed (which must equal H1's native statement for (n, 0, PAYOUT)).
function proveBlock(n) {
const dir = `${TMP}/prove-${n}`; mkdirSync(dir, { recursive: true });
const body = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'igneum_exportSegments', params: ['0x0', '0x' + n.toString(16)] });
const r = spawnSync('curl', ['-s', '-m', '600', '-X', 'POST', `http://127.0.0.1:${H1.evmPort}`, '-H', 'Content-Type: application/json', '--data-binary', body], { encoding: 'utf8', maxBuffer: 1 << 30 });
if (r.status !== 0) throw new Error(`export failed: ${r.stderr}`);
writeFileSync(`${dir}/export.json`, JSON.stringify(JSON.parse(r.stdout).result));
const e = spawnSync(`${PROVE_BIN}/igneum-prove-export`, [`${dir}/export.json`, String(n), `${dir}/block-${n}.json`, '--source', `fast-time cache-history ${CHAIN}`], { encoding: 'utf8' });
if (e.status !== 0) throw new Error(`igneum-prove-export failed: ${(e.stdout + e.stderr).slice(-400)}`);
log(`block ${n} cut: ${(e.stdout.trim().split('\n').pop() || '').slice(0, 160)}`);
const h = spawnSync(`${PROVE_BIN}/igneum-prove-host`, [`${dir}/block-${n}.json`, '--mode', 'compressed', '--shard', '0', '--prover', PAYOUT, '--out', `${dir}/results.json`], { encoding: 'utf8', env: { ...process.env, SP1_PROVER: 'cpu' } });
const line = (h.stdout.match(/RESULT compressed shard 0: [^\n]*/) || [''])[0];
log(`host: ${line.slice(0, 200)}${h.status !== 0 ? ` (exit ${h.status}: ${(h.stderr || '').slice(-300)})` : ''}`);
if (h.status !== 0 || !/VERIFIED/.test(line)) throw new Error(`the host did not prove block ${n}`);
const file = `${dir}/block-${n}-shard-0-compressed.bin`;
if (!existsSync(file)) throw new Error(`no proof file ${file}`);
const statement = (line.match(/statement (0x[0-9a-f]{64})/) || [])[1];
return { bytes: readFileSync(file), statement, line };
}
const result = { case: 'cache-history', node: IGNEUMD, proveBin: PROVE_BIN, pair: { shard: manifest.shard.program_id, aggregator: manifest.aggregator.program_id }, startedAt: new Date().toISOString(), phases: {} };
try {
await H1.start(); await H2.start(); await A.start();
miners = [startMiner(H1, 'h1', BEFORE + 3 * AFTER + 900), startMiner(H2, 'h2', BEFORE + 3 * AFTER + 900), startMiner(A, 'attacker', BEFORE + 3 * AFTER + 900)];
log(`phase 0: mining ${BEFORE} s`);
await sleep(BEFORE * 1000);
const v0 = await verifies(H1);
// the block to prove: outside the exclusive window, executed on every node
let tip = await tipNumber(H1);
const n = Math.max(1, tip - 15);
const plan = await H1.exec('igneum_getShardPlan', ['0x' + n.toString(16), PAYOUT]);
const native = plan.shards[0].statement;
log(`block ${n} ${plan.hash}: H1's native statement for shard 0 and ${PAYOUT}: ${native}`);
const proof = proveBlock(n);
result.proof = { block: n, statement: proof.statement, native, bytes: proof.bytes.length, sha256: '0x' + sha256(proof.bytes), hostLine: proof.line };
if (proof.statement !== native) throw new Error(`the host's statement ${proof.statement} is not H1's ${native} (host and node layouts or pairs differ)`);
// phase 1: the real bytes under a record for another block (the statement of block m): refused for context
await rejoin('before phase 1');
tip = await tipNumber(A);
const m = Math.max(1, tip - 15);
const planM = await A.exec('igneum_getShardPlan', ['0x' + m.toString(16), PAYOUT]);
const recWrong = signRecord('ch-wrong', CHAIN, planM.hash, m, 0, PAYOUT, planM.shards[0].statement, '0x' + sha256(proof.bytes)).record;
const r1 = await submitVia(A, 'phase 1 (real bytes, another block\'s statement)', recWrong, hex(proof.bytes));
await sleep(AFTER * 1000);
const v1 = await verifies(H1);
const o1 = await observe(m);
result.phases.context = { block: m, submit: r1, observed: o1, verifies: v1, refusals: refusals(H1) };
log(`phase 1: H1 verifies ${JSON.stringify(v1)}; block ${m} paid ${JSON.stringify(o1.paid)}; refusals ${refusals(H1).length}`);
// phase 2: the same bytes as their own honest record: answered from the cached facts, paid once
await rejoin('before phase 2');
const recHonest = signRecord('ch-honest', CHAIN, plan.hash, n, 0, PAYOUT, native, '0x' + sha256(proof.bytes)).record;
const r2 = await submitVia(A, 'phase 2 (the same bytes, the honest record)', recHonest, hex(proof.bytes));
await sleep(AFTER * 1000);
const v2 = await verifies(H1);
const o2 = await observe(n);
result.phases.honest = { block: n, submit: r2, observed: o2, verifies: v2 };
log(`phase 2: H1 verifies ${JSON.stringify(v2)}; block ${n} paid ${JSON.stringify(o2.paid)}; carried ${JSON.stringify(o2.carried)}`);
// phase 3: invalid bytes twice, under two carriers: verified once, refused from the cache the second time
await rejoin('before phase 3');
const bad = randomBytes(2048);
tip = await tipNumber(A);
const p = Math.max(1, tip - 15);
const planP = await A.exec('igneum_getShardPlan', ['0x' + p.toString(16), PAYOUT]);
const recBad1 = signRecord('ch-bad1', CHAIN, planP.hash, p, 0, PAYOUT, planP.shards[0].statement, '0x' + sha256(bad)).record;
const r3 = await submitVia(A, 'phase 3a (invalid bytes)', recBad1, hex(bad));
await sleep(AFTER * 1000);
const v3a = await verifies(H1);
const ref3a = refusals(H1).length;
await rejoin('before phase 3b');
tip = await tipNumber(A);
const q = Math.max(1, tip - 15);
const planQ = await A.exec('igneum_getShardPlan', ['0x' + q.toString(16), PAYOUT]);
const recBad2 = signRecord('ch-bad2', CHAIN, planQ.hash, q, 0, PAYOUT, planQ.shards[0].statement, '0x' + sha256(bad)).record;
const r4 = await submitVia(A, 'phase 3b (the same invalid bytes, a later carrier)', recBad2, hex(bad));
await sleep(AFTER * 1000);
const v3b = await verifies(H1);
const ref3b = refusals(H1).length;
result.phases.invalid = { blocks: [p, q], submits: [r3, r4], verifies: { after3a: v3a, after3b: v3b }, refusals: { after3a: ref3a, after3b: ref3b }, reasons: refusals(H1) };
log(`phase 3: H1 verifies after 3a ${JSON.stringify(v3a)}, after 3b ${JSON.stringify(v3b)}; refusals ${ref3a} then ${ref3b}`);
// the verdict
const paidOnce = (o2.paid || []).length === 1 && (o1.paid || []).length === 0;
const runs = Number(v3b.sp1) - Number(v0.sp1); // SP1 verifies: the real proof once (phase 2), the invalid bytes once (3a); the context refusal of phase 1 runs no verifier
const cache = Number(v3b.cacheAnswers) - Number(v0.cacheAnswers);
const contextCheap = Number(v1.contextRefusals) - Number(v0.contextRefusals) >= 1 && Number(v1.sp1) === Number(v0.sp1);
const contextRefused = result.phases.context.refusals.length >= 1;
const invalidRefusedTwiceNoVerify = ref3b > ref3a && Number(v3b.sp1) === Number(v3a.sp1);
const pass = paidOnce && runs === 2 && cache >= 1 && contextRefused && contextCheap && invalidRefusedTwiceNoVerify;
result.verdict = { paidOnce, sp1Verifies: runs, cacheAnswers: cache, contextRefused, contextCheap, invalidRefusedTwiceNoVerify, pass };
result.endedAt = new Date().toISOString();
writeFileSync(OUT, JSON.stringify(result, null, 2));
log(`RESULT ${pass ? 'PASS' : 'FAIL'}: paid once=${paidOnce}; SP1 verifies=${runs} (expect 2: the real proof once, the invalid bytes once); context refusal read=${contextRefused} and cheap (no verifier)=${contextCheap}; cache answers=${cache} (expect >= 1); invalid refused again without a verify=${invalidRefusedTwiceNoVerify}; ${OUT}`);
await stopAll();
process.exit(pass ? 0 : 1);
} catch (e) {
log(`ERROR: ${e.message}`);
result.error = e.message; result.endedAt = new Date().toISOString();
try { writeFileSync(OUT, JSON.stringify(result, null, 2)); } catch { }
await stopAll();
process.exit(1);
}

View file

@ -276,7 +276,7 @@ async function forge(n, phase, which = 'pn') {
async function observe(n) { async function observe(n) {
try { try {
const r = await H1.exec('igneum_getProofRecords', ['0x' + n.toString(16)]); const r = await H1.exec('igneum_getProofRecords', ['0x' + n.toString(16)]);
const carried = (r.carried || []).map(c => ({ key: c.keyHash, carrier: c.carrierNumber, rejected: c.rejected, paidWei: c.paidWei })); const carried = (r.carried || []).map(c => ({ signer: c.keyHash, carrier: c.carrierNumber, rejected: c.rejected, paidWei: c.paidWei }));
// `paid` holds one entry per shard, null when unpaid: keep the paid ones only // `paid` holds one entry per shard, null when unpaid: keep the paid ones only
return { paid: (r.paid || []).filter(Boolean), carried }; return { paid: (r.paid || []).filter(Boolean), carried };
} catch (e) { return { error: e.message }; } } catch (e) { return { error: e.message }; }

View file

@ -0,0 +1,17 @@
{
"run_id": "enforced-proving-20261008-03",
"manifest_sha": "c591e63b",
"evidence_dir": "docs/plans/proving-enforcement",
"boxes": [
"build-9"
],
"method": "native",
"cells": [
{
"cell": "harness:proving-enforcement",
"status": "PASS",
"evidence": "docs/plans/proving-enforcement/cache-history-2.json"
}
],
"note": "The two-node cache-history case (review B F01) on the fix's rule at the 2.0.2 tip ab489403 (cache-history-node c591e63b; host and node on pin C): a real proof of the chain's own block refused for context under one carrier, then paid once as its own record under a later one from the cached facts with no second SP1 verify; the invalid bytes verified once and refused again from the cache at a later carrier; a context refusal is a cheap pre-check, never cached. build-9, 22:53 to 23:05 UK."
}