From 5cc2825235497239f3052617afef45612e87bde0 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 16:22:47 +0000 Subject: [PATCH] Enforced proving spec: the fast-time crossing PASS at 17:22 UK (the finding paid below the floor, nothing paid and four refusals per honest node at it), the row-6 test's version Co-Authored-By: Claude Fable 5.1 --- docs/spec/proving-enforcement.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/spec/proving-enforcement.md b/docs/spec/proving-enforcement.md index d1560a4fa..7c2b8dd82 100644 --- a/docs/spec/proving-enforcement.md +++ b/docs/spec/proving-enforcement.md @@ -69,7 +69,7 @@ The Igneum 2.0 plan (p. 16) names six negative tests every validator must pass. | (3) a wrong chain, epoch or statement binding, replayed or misbound work | `enforced_a_record_signed_for_another_network_pays_nothing` (the chain); `enforced_a_replayed_record_pays_nothing_the_second_time` (replay); `assignment_follows_the_window_and_records_check_against_native_execution` (a wrong block, a wrong shard, a stale record outside the window, a wrong statement); the epoch binds through the sortition's epoch seed and the chain block in the statement | executor | green 16:15 UK | | (4) a changed payout identity | `enforced_an_altered_payout_address_pays_nothing` (altered after signing: the signature; re-signed: the statement binds the payout) | executor | green 16:15 UK | | (5) a duplicate proof reward: exactly the permitted payment outcome | `enforced_a_duplicate_of_a_paid_record_by_another_key_pays_nothing`; the honest record paid once in (1)'s test | executor | green 16:15 UK | -| (6) incorrect rewards or consensus inputs: derivation authenticated, not only execution over supplied inputs | `enforced_a_statement_over_altered_rewards_or_payouts_is_vetoed_native_derivation_is_the_check` (a statement whose post-root came from execution over other rewards or payouts is not the native statement and pays nothing: the native veto, every node's own derivation) | executor (proving-payment branch, on build-2 at 17:06 UK) | PENDING as the plan means it: the derivation is authenticated by every node's own execution, not inside the proof; the proof-side closure is P22's stages 1 to 3 (section 7), phase 2 | +| (6) incorrect rewards or consensus inputs: derivation authenticated, not only execution over supplied inputs | `enforced_a_statement_over_altered_rewards_or_payouts_is_vetoed_native_derivation_is_the_check` (a statement whose post-root came from execution over other rewards or payouts is not the native statement and pays nothing: the native veto, every node's own derivation) | executor, branch proving-payment of the fork at 421bb852 (on release-2.0.0-node's c04674fe), igneum-exec 67 passed on build-2 at 17:10 UK | PENDING as the plan means it: the derivation is authenticated by every node's own execution, not inside the proof; the proof-side closure is P22's stages 1 to 3 (section 7), phase 2 | The boundary sentence of the plan, carried in every served text that names the rule: a proof of execution is not a proof of authenticated consensus inputs, canonical history or data availability. What the rule proves today is that the carried record's statement is the native statement of this node's own execution and that an SP1 proof of that statement verifies; what consensus inputs the execution used, which history is canonical and whether the data is available are each the node's own reading, not the proof's. @@ -94,6 +94,7 @@ Filled from the box runs as they land; each line names the box, the command clas | 16:08 | build-2, suite class, 12 threads, nice 10 (the bounded pool held 13 free cores; the 24-thread ask waited) | `cargo test --release -p igneum-exec --lib enforced_` | 7 passed, 0 failed (the seven executor tests of section 3), 229 s wall with the compile | | 16:11 | build-2, same class | `cargo test --release -p kaspa-consensus-core --lib the_verifier_switch` | 1 passed (the switch is off on every compiled object; Devnet 3 at never; the testnet floor 0; the digest moves once set; a file that omits it changes nothing) | | 16:15 | build-2, suite class, 12 threads | `cargo test --release -p kaspa-consensus-core -p igneum-exec -p kaspa-consensus --lib` (the full lib suites on the branch; the first consensus build stopped on a missing `ConsensusApi` import at 16:11, fixed at 16:12) | igneum-exec 64 passed 0 failed; kaspa-consensus 138 passed 0 failed, 3 ignored (the six `proving_enforcement_tests::enforced_*` among them); kaspa-consensus-core 171 passed 0 failed, 4 ignored; 172 s wall with the compile | +| 17:22 | build-2, `tools/fast-time-remote.sh` (normal class), three local nodes, one CPU mining thread each | `infra/fast-time/proving-enforcement.mjs --floor 240 --before 90 --after 150 --real-proof ` (the fifth attempt; the first four were the harness's own faults: a bare boolean in the override file, the block tag's hex form, the forged block inside the exclusive window, a dead ssh leaving three nodes on the box) | RESULT PASS. Below the floor (A at DAA 118, block 101): A's trusting pool took shapes a, b, c, d and g and its templates carried them; A's own unmodified pool refused e (bad signature) and f (the native-execution veto), the same checks every honest node runs; H1 paid the first carried record, shape c (the real proof of another chain under A's statement), 0x8cc611991c3c400 wei to A's payout: ledger P21's finding, observed; the three records after it read "shard already paid" (shape g's duplicate among them). At the floor (A at DAA 247, block 229): the same five shapes carried by A; H1 paid nothing, carried nothing of A's (its blocks never entered H1's DAG), and H1 and H2 each logged four new REFUSED verdicts (3 to 7), one per carried record, in 0.000 to 0.003 s each (the cached verdict from the relay-time verify, the measured cold path above being the first verify). Result file on build-2: `/home/build/enforced-fixtures/floor-240-expect-refuse.json` | | 16:34 | build-2 (AMD EPYC 9454P, 96 threads, 125 GB), `lease pool 1 --nice 19`, one core, the box at load 85 to 95 | the verify cost per record: `nativeverify::tests::a_real_proof_verifies_and_a_wrong_statement_is_refused` on a real compressed shard proof of the testnet join pass (build-1 `/srv/builds/tn-join-pass/prover/block-763-shard-0-compressed.bin`, 1,272,897 bytes), seven runs; `/usr/bin/time -v` for the memory | measured: 0.710, 0.683, 0.701, 0.671, 0.700, 0.687, 0.668 s one core (0.668 to 0.710 s, a loaded-box figure); peak resident 34.6 MB with the verify against 4.6 MB for the same binary without it, so about 30 MB per concurrent verify | ## 7. The staging statement for P22 @@ -113,4 +114,4 @@ Until stage 3 lands, every stage's output is checked natively by every node, and ## 8. The fast-time harness case -`infra/fast-time/proving-enforcement.mjs` (section 6 says whether it ran): three nodes on one fast-time network, two honest under the floor set a few epochs ahead (`proving_consensus_verify_daa` in the override, the boundary), one attacker with the body rule off and the verifier in trust mode. The attacker reads each shard's native statement for its own payout address from its node (`igneum_getShardPlan(block, payout)`), signs it (`igneum-miner sign-record`) and submits it with proof bytes of the seven shapes through `igneum_submitProofRecord`; its templates carry the records. Below the boundary the honest nodes accept the attacker's blocks and the v0 rule pays (the finding, observed); from the boundary every honest node refuses the carrying block (`IgneumInvalidProofRecord` or the 20-s drop) and `igneum_getProofRecords` shows no paid entry for any of the seven. The honest-pays-once case needs a real shard proof of the harness's own chain, which a CPU prover makes in minutes; the unit tests hold it meanwhile and the testnet holds it live. +`infra/fast-time/proving-enforcement.mjs` (ran, PASS at 17:22 UK, section 6): three nodes on one fast-time network, two honest under the floor set a few epochs ahead (`proving_consensus_verify_daa` in the override, the boundary), one attacker with the body rule off and the verifier in trust mode. The attacker reads each shard's native statement for its own payout address from its node (`igneum_getShardPlan(block, payout)`), signs it (`igneum-miner sign-record`) and submits it with proof bytes of the seven shapes through `igneum_submitProofRecord`; its templates carry the records. Below the boundary the honest nodes accept the attacker's blocks and the v0 rule pays (the finding, observed); from the boundary every honest node refuses the carrying block (`IgneumInvalidProofRecord` or the 20-s drop) and `igneum_getProofRecords` shows no paid entry for any of the seven. The honest-pays-once case needs a real shard proof of the harness's own chain, which a CPU prover makes in minutes; the unit tests hold it meanwhile and the testnet holds it live.