use miden_protobuf::{ConversionError, ConversionResultExt, Decoded, VerifyWith};
use miden_protocol::batch::{ProposedBatch, ProvenBatch};
use miden_protocol::vm::ExecutionProof;
use crate::generated as proto;
use crate::generated::remote_prover::proof::DecodedProof as ProofVariant;
impl proto::remote_prover::DecodedProof {
pub fn into_transaction(
self,
) -> Result<Decoded<proto::transaction::ProvenTransaction>, ConversionError> {
match self.proof {
ProofVariant::Transaction(proof) => Ok(proof),
_ => Err(ConversionError::message(
"proof: response variant does not match transaction request",
)),
}
}
pub fn into_batch(self) -> Result<Decoded<proto::transaction::ProvenBatch>, ConversionError> {
match self.proof {
ProofVariant::Batch(proof) => Ok(proof),
_ => Err(ConversionError::message(
"proof: response variant does not match batch request",
)),
}
}
pub fn into_block(self) -> Result<ExecutionProof, ConversionError> {
match self.proof {
ProofVariant::Block(proof) => Ok(proof),
_ => Err(ConversionError::message(
"proof: response variant does not match block request",
)),
}
}
}
impl VerifyWith<&ProposedBatch> for proto::remote_prover::DecodedProof {
type Verified = ProvenBatch;
type Error = ConversionError;
fn verify_with(self, proposal: &ProposedBatch) -> Result<Self::Verified, Self::Error> {
self.into_batch()?.verify_with(proposal).context("proof.batch")
}
}
#[cfg(test)]
mod tests {
use miden_protobuf::DecodeMessage;
use miden_protocol::testing::dummy_execution_proof;
use super::*;
fn block_response() -> proto::remote_prover::Proof {
proto::remote_prover::Proof {
proof: Some(proto::remote_prover::proof::Proof::Block(dummy_execution_proof().into())),
}
}
#[test]
fn missing_proof_is_rejected() {
let error = proto::remote_prover::Proof { proof: None }.decode_fields().unwrap_err();
assert!(error.to_string().contains("proof"));
}
#[test]
fn block_response_does_not_satisfy_transaction_or_batch_request() {
let error = block_response().decode_fields().unwrap().into_transaction().unwrap_err();
assert!(error.to_string().contains("does not match transaction request"));
let error = block_response().decode_fields().unwrap().into_batch().unwrap_err();
assert!(error.to_string().contains("does not match batch request"));
}
#[test]
fn block_response_preserves_proof() {
assert_eq!(
block_response().decode_fields().unwrap().into_block().unwrap(),
dummy_execution_proof()
);
}
#[test]
fn malformed_proof_retains_field_context() {
let response = proto::remote_prover::Proof {
proof: Some(proto::remote_prover::proof::Proof::Transaction(
proto::transaction::ProvenTransaction::default(),
)),
};
let error = response.decode_fields().unwrap_err();
assert!(error.to_string().contains("proof.transaction"));
}
}