use super::chain_version;
use crate::spec::types::{ChainSpec, ParityFailure, ProofToken};
#[inline]
pub(crate) fn validate_chain(chain: &ChainSpec) -> Result<(), Box<ParityFailure>> {
let expected = match ProofToken::from_specs(&chain.specs, chain.proof_token.computed_at) {
Ok(t) => t,
Err(err) => {
return Err(Box::new(ParityFailure {
op_id: chain.id.clone(),
generator: "composition-proof".to_string(),
input_label: "construction-token".to_string(),
input: Vec::new(),
gpu_output: Vec::new(),
cpu_output: Vec::new(),
message: format!(
"composition proof token recomputation failed for {}: {err}. \
Fix: verify that all component ops satisfy their declared laws.",
chain.id
),
spec_version: chain_version(chain),
workgroup_size: 0,
}));
}
};
if chain.proof_token.theorem_claims_match(&expected) {
return Ok(());
}
Err(Box::new(ParityFailure {
op_id: chain.id.clone(),
generator: "composition-proof".to_string(),
input_label: "construction-token".to_string(),
input: Vec::new(),
gpu_output: Vec::new(),
cpu_output: Vec::new(),
message: format!(
"composition proof token mismatch for {}: claimed preserved=[{}], broken=[{}], \
theorems=[{}]; expected preserved=[{}], broken=[{}], theorems=[{}]. \
Fix: build ChainSpec through a composer or recompute ProofToken::from_specs \
before dispatch.",
chain.id,
law_names(&chain.proof_token.preserved_laws),
law_names(&chain.proof_token.broken_laws),
chain.proof_token.theorem_chain.join(","),
law_names(&expected.preserved_laws),
law_names(&expected.broken_laws),
expected.theorem_chain.join(","),
),
spec_version: chain_version(chain),
workgroup_size: 0,
}))
}
fn law_names(laws: &[crate::spec::law::AlgebraicLaw]) -> String {
laws.iter()
.map(crate::spec::law::AlgebraicLaw::name)
.collect::<Vec<_>>()
.join(",")
}