Skip to main content

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