Skip to main content

miden_tx_batch_prover/
local_batch_prover.rs

1use alloc::boxed::Box;
2
3use miden_protocol::batch::{ProposedBatch, ProvenBatch};
4use miden_protocol::errors::ProvenBatchError;
5use miden_tx::TransactionVerifier;
6
7// LOCAL BATCH PROVER
8// ================================================================================================
9
10/// A local prover for transaction batches, proving the transactions in a [`ProposedBatch`] and
11/// returning a [`ProvenBatch`].
12#[derive(Clone)]
13pub struct LocalBatchProver {
14    proof_security_level: u32,
15}
16
17impl LocalBatchProver {
18    /// Creates a new [`LocalBatchProver`] instance.
19    pub fn new(proof_security_level: u32) -> Self {
20        Self { proof_security_level }
21    }
22
23    /// Attempts to prove the [`ProposedBatch`] into a [`ProvenBatch`].
24    ///
25    /// Currently we don't perform any recursive proving. For now, this function runs a native
26    /// verifier for each transaction separately, and outputs a `ProvenBatch` object if all of the
27    /// individual proofs verify.
28    ///
29    /// # Errors
30    ///
31    /// Returns an error if:
32    /// - a proof of any transaction in the batch fails to verify.
33    pub fn prove(&self, proposed_batch: ProposedBatch) -> Result<ProvenBatch, ProvenBatchError> {
34        let verifier = TransactionVerifier::new(self.proof_security_level);
35
36        for tx in proposed_batch.transactions() {
37            verifier.verify(tx).map_err(|source| {
38                ProvenBatchError::TransactionVerificationFailed {
39                    transaction_id: tx.id(),
40                    source: Box::new(source),
41                }
42            })?;
43        }
44
45        self.prove_inner(proposed_batch)
46    }
47
48    /// Proves the provided [`ProposedBatch`] into a [`ProvenBatch`], **without verifying batches
49    /// and proving the block**.
50    ///
51    /// This is exposed for testing purposes.
52    #[cfg(any(feature = "testing", test))]
53    pub fn prove_dummy(
54        &self,
55        proposed_batch: ProposedBatch,
56    ) -> Result<ProvenBatch, ProvenBatchError> {
57        self.prove_inner(proposed_batch)
58    }
59
60    /// Converts a proposed batch into a proven batch.
61    ///
62    /// For now, this doesn't do anything interesting.
63    fn prove_inner(&self, proposed_batch: ProposedBatch) -> Result<ProvenBatch, ProvenBatchError> {
64        let tx_headers = proposed_batch.transaction_headers();
65        let (
66            _transactions,
67            block_header,
68            _block_chain,
69            _authenticatable_unauthenticated_notes,
70            id,
71            updated_accounts,
72            input_notes,
73            output_notes,
74            batch_expiration_block_num,
75        ) = proposed_batch.into_parts();
76
77        ProvenBatch::new_unchecked(
78            id,
79            block_header.commitment(),
80            block_header.block_num(),
81            updated_accounts,
82            input_notes,
83            output_notes,
84            batch_expiration_block_num,
85            tx_headers,
86        )
87    }
88}