miden_objects/batch/
proven_batch.rs

1use alloc::collections::BTreeMap;
2use alloc::string::ToString;
3use alloc::vec::Vec;
4
5use crate::account::AccountId;
6use crate::batch::{BatchAccountUpdate, BatchId};
7use crate::block::BlockNumber;
8use crate::errors::ProvenBatchError;
9use crate::note::Nullifier;
10use crate::transaction::{InputNoteCommitment, InputNotes, OrderedTransactionHeaders, OutputNote};
11use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
12use crate::{MIN_PROOF_SECURITY_LEVEL, Word};
13
14/// A transaction batch with an execution proof.
15/// Currently, there is no proof attached. Future versions will extend this structure to include
16/// a proof artifact once recursive proving is implemented.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ProvenBatch {
19    id: BatchId,
20    reference_block_commitment: Word,
21    reference_block_num: BlockNumber,
22    account_updates: BTreeMap<AccountId, BatchAccountUpdate>,
23    input_notes: InputNotes<InputNoteCommitment>,
24    output_notes: Vec<OutputNote>,
25    batch_expiration_block_num: BlockNumber,
26    transactions: OrderedTransactionHeaders,
27}
28
29impl ProvenBatch {
30    // CONSTRUCTORS
31    // --------------------------------------------------------------------------------------------
32
33    /// Creates a new [`ProvenBatch`] from the provided parts.
34    ///
35    /// # Errors
36    ///
37    /// Returns an error if the batch expiration block number is not greater than the reference
38    /// block number.
39    pub fn new(
40        id: BatchId,
41        reference_block_commitment: Word,
42        reference_block_num: BlockNumber,
43        account_updates: BTreeMap<AccountId, BatchAccountUpdate>,
44        input_notes: InputNotes<InputNoteCommitment>,
45        output_notes: Vec<OutputNote>,
46        batch_expiration_block_num: BlockNumber,
47        transactions: OrderedTransactionHeaders,
48    ) -> Result<Self, ProvenBatchError> {
49        // Check that the batch expiration block number is greater than the reference block number.
50        if batch_expiration_block_num <= reference_block_num {
51            return Err(ProvenBatchError::InvalidBatchExpirationBlockNum {
52                batch_expiration_block_num,
53                reference_block_num,
54            });
55        }
56
57        Ok(Self {
58            id,
59            reference_block_commitment,
60            reference_block_num,
61            account_updates,
62            input_notes,
63            output_notes,
64            batch_expiration_block_num,
65            transactions,
66        })
67    }
68
69    // PUBLIC ACCESSORS
70    // --------------------------------------------------------------------------------------------
71
72    /// The ID of this batch. See [`BatchId`] for details on how it is computed.
73    pub fn id(&self) -> BatchId {
74        self.id
75    }
76
77    /// Returns the commitment to the reference block of the batch.
78    pub fn reference_block_commitment(&self) -> Word {
79        self.reference_block_commitment
80    }
81
82    /// Returns the number of the reference block of the batch.
83    pub fn reference_block_num(&self) -> BlockNumber {
84        self.reference_block_num
85    }
86
87    /// Returns the block number at which the batch will expire.
88    pub fn batch_expiration_block_num(&self) -> BlockNumber {
89        self.batch_expiration_block_num
90    }
91
92    /// Returns an iterator over the IDs of all accounts updated in this batch.
93    pub fn updated_accounts(&self) -> impl Iterator<Item = AccountId> + use<'_> {
94        self.account_updates.keys().copied()
95    }
96
97    /// Returns the proof security level of the batch.
98    pub fn proof_security_level(&self) -> u32 {
99        MIN_PROOF_SECURITY_LEVEL
100    }
101
102    /// Returns the map of account IDs mapped to their [`BatchAccountUpdate`]s.
103    ///
104    /// If an account was updated by multiple transactions, the [`BatchAccountUpdate`] is the result
105    /// of merging the individual updates.
106    ///
107    /// For example, suppose an account's state before this batch is `A` and the batch contains two
108    /// transactions that updated it. Applying the first transaction results in intermediate state
109    /// `B`, and applying the second one results in state `C`. Then the returned update represents
110    /// the state transition from `A` to `C`.
111    pub fn account_updates(&self) -> &BTreeMap<AccountId, BatchAccountUpdate> {
112        &self.account_updates
113    }
114
115    /// Returns the [`InputNotes`] of this batch.
116    pub fn input_notes(&self) -> &InputNotes<InputNoteCommitment> {
117        &self.input_notes
118    }
119
120    /// Returns an iterator over the nullifiers created in this batch.
121    pub fn created_nullifiers(&self) -> impl Iterator<Item = Nullifier> + use<'_> {
122        self.input_notes.iter().map(InputNoteCommitment::nullifier)
123    }
124
125    /// Returns the output notes of the batch.
126    ///
127    /// This is the aggregation of all output notes by the transactions in the batch, except the
128    /// ones that were consumed within the batch itself.
129    pub fn output_notes(&self) -> &[OutputNote] {
130        &self.output_notes
131    }
132
133    /// Returns the [`OrderedTransactionHeaders`] included in this batch.
134    pub fn transactions(&self) -> &OrderedTransactionHeaders {
135        &self.transactions
136    }
137
138    // MUTATORS
139    // --------------------------------------------------------------------------------------------
140
141    /// Consumes self and returns the contained [`OrderedTransactionHeaders`] of this batch.
142    pub fn into_transactions(self) -> OrderedTransactionHeaders {
143        self.transactions
144    }
145}
146
147// SERIALIZATION
148// ================================================================================================
149
150impl Serializable for ProvenBatch {
151    fn write_into<W: ByteWriter>(&self, target: &mut W) {
152        self.id.write_into(target);
153        self.reference_block_commitment.write_into(target);
154        self.reference_block_num.write_into(target);
155        self.account_updates.write_into(target);
156        self.input_notes.write_into(target);
157        self.output_notes.write_into(target);
158        self.batch_expiration_block_num.write_into(target);
159        self.transactions.write_into(target);
160    }
161}
162
163impl Deserializable for ProvenBatch {
164    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
165        let id = BatchId::read_from(source)?;
166        let reference_block_commitment = Word::read_from(source)?;
167        let reference_block_num = BlockNumber::read_from(source)?;
168        let account_updates = BTreeMap::read_from(source)?;
169        let input_notes = InputNotes::<InputNoteCommitment>::read_from(source)?;
170        let output_notes = Vec::<OutputNote>::read_from(source)?;
171        let batch_expiration_block_num = BlockNumber::read_from(source)?;
172        let transactions = OrderedTransactionHeaders::read_from(source)?;
173
174        Self::new(
175            id,
176            reference_block_commitment,
177            reference_block_num,
178            account_updates,
179            input_notes,
180            output_notes,
181            batch_expiration_block_num,
182            transactions,
183        )
184        .map_err(|e| DeserializationError::UnknownError(e.to_string()))
185    }
186}