From db90204b96aab4e5e79383f57858b3deeeaaebe0 Mon Sep 17 00:00:00 2001 From: David Kutz-Marks Date: Mon, 20 Jul 2026 11:38:50 -0400 Subject: [PATCH] prover: include global state in errored machine hash to match on-chain OSP The off-chain WAVM prover hashed a MachineStatus::Errored machine as keccak("Machine errored:") with no global state, while the on-chain OSP hashes it as keccak("Machine errored:" || globalStateHash) in both MachineLib.hash (per-step, used inside proveOneStep) and OneStepProofEntry.getMachineHash (block-level assertion endpoint). The Finished arm already commits the global state on both sides; only the Errored arm diverged. The honest BOLD validator commits the machine hashes produced here (via cgo; there is no Go reimplementation of the errored hash), so for any block or one-step transition whose terminal WAVM state is Errored, the hash the validator commits could never equal the hash the on-chain contract computes for the same state. A dispute involving a terminal Errored state was therefore unadjudicable: confirmEdgeByOneStepProof would produce an after-hash matching neither party's committed hash, and an errored block endpoint (getMachineHash) could not be reconciled with any arbitrator-produced small-step trace. This aligns the outlier (the Rust prover) with the already-deployed on-chain OSP and the challengeLib test helper, which both include the global state. It does not change the wasm module root (module code is unchanged) and does not change any hash for a Running or Finished machine, so honest commitments are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/prover/src/machine.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/prover/src/machine.rs b/crates/prover/src/machine.rs index 563b27b595..1dd90a9aa7 100644 --- a/crates/prover/src/machine.rs +++ b/crates/prover/src/machine.rs @@ -2935,7 +2935,15 @@ impl Machine { MachineStatus::Finished => { crypto::keccak_seq(&[b"Machine finished:", self.global_state.hash().as_ref()]) } - MachineStatus::Errored => crypto::keccak_seq(&[b"Machine errored:"]), + // The global state must be committed here to match the on-chain OSP, + // which hashes an errored machine as keccak("Machine errored:" || globalStateHash) + // in both MachineLib.hash (per-step) and OneStepProofEntry.getMachineHash + // (block endpoint). Omitting it made a terminal Errored machine unadjudicable: + // the hash the honest validator commits here (via cgo) could never equal the + // hash the on-chain contract computes for the same state. + MachineStatus::Errored => { + crypto::keccak_seq(&[b"Machine errored:", self.global_state.hash().as_ref()]) + } MachineStatus::TooFar => crypto::keccak_seq(&[b"Machine too far:"]), } }