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