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