miden_objects/batch/
account_update.rs

1use alloc::vec::Vec;
2
3use crate::{
4    Digest,
5    account::{AccountId, delta::AccountUpdateDetails},
6    errors::BatchAccountUpdateError,
7    transaction::{ProvenTransaction, TransactionId},
8    utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
9};
10
11// BATCH ACCOUNT UPDATE
12// ================================================================================================
13
14/// Represents the changes made to an account resulting from executing a batch of transactions.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct BatchAccountUpdate {
17    /// ID of the updated account.
18    account_id: AccountId,
19
20    /// Commitment to the state of the account before this update is applied.
21    ///
22    /// Equal to `Digest::default()` for new accounts.
23    initial_state_commitment: Digest,
24
25    /// Commitment to the state of the account after this update is applied.
26    final_state_commitment: Digest,
27
28    /// IDs of all transactions that updated the account.
29    transactions: Vec<TransactionId>,
30
31    /// A set of changes which can be applied to the previous account state (i.e. `initial_state`)
32    /// to get the new account state. For private accounts, this is set to
33    /// [`AccountUpdateDetails::Private`].
34    details: AccountUpdateDetails,
35}
36
37impl BatchAccountUpdate {
38    // CONSTRUCTORS
39    // --------------------------------------------------------------------------------------------
40
41    /// Creates a [`BatchAccountUpdate`] by cloning the update and other details from the provided
42    /// [`ProvenTransaction`].
43    pub fn from_transaction(transaction: &ProvenTransaction) -> Self {
44        Self {
45            account_id: transaction.account_id(),
46            initial_state_commitment: transaction.account_update().initial_state_commitment(),
47            final_state_commitment: transaction.account_update().final_state_commitment(),
48            transactions: vec![transaction.id()],
49            details: transaction.account_update().details().clone(),
50        }
51    }
52
53    // PUBLIC ACCESSORS
54    // --------------------------------------------------------------------------------------------
55
56    /// Returns the ID of the updated account.
57    pub fn account_id(&self) -> AccountId {
58        self.account_id
59    }
60
61    /// Returns a commitment to the state of the account before this update is applied.
62    ///
63    /// This is equal to [`Digest::default()`] for new accounts.
64    pub fn initial_state_commitment(&self) -> Digest {
65        self.initial_state_commitment
66    }
67
68    /// Returns a commitment to the state of the account after this update is applied.
69    pub fn final_state_commitment(&self) -> Digest {
70        self.final_state_commitment
71    }
72
73    /// Returns a slice of [`TransactionId`]s that updated this account's state.
74    pub fn transactions(&self) -> &[TransactionId] {
75        &self.transactions
76    }
77
78    /// Returns the contained [`AccountUpdateDetails`].
79    ///
80    /// This update can be used to build the new account state from the previous account state.
81    pub fn details(&self) -> &AccountUpdateDetails {
82        &self.details
83    }
84
85    /// Returns `true` if the account update details are for a private account.
86    pub fn is_private(&self) -> bool {
87        self.details.is_private()
88    }
89
90    // MUTATORS
91    // --------------------------------------------------------------------------------------------
92
93    /// Merges the transaction's update into this account update.
94    ///
95    /// # Errors
96    ///
97    /// Returns an error if:
98    /// - The account ID of the merging transaction does not match the account ID of the existing
99    ///   update.
100    /// - The merging transaction's initial state commitment does not match the final state
101    ///   commitment of the current update.
102    /// - If the underlying [`AccountUpdateDetails::merge`] fails.
103    pub fn merge_proven_tx(
104        &mut self,
105        tx: &ProvenTransaction,
106    ) -> Result<(), BatchAccountUpdateError> {
107        if self.account_id != tx.account_id() {
108            return Err(BatchAccountUpdateError::AccountUpdateIdMismatch {
109                transaction: tx.id(),
110                expected_account_id: self.account_id,
111                actual_account_id: tx.account_id(),
112            });
113        }
114
115        if self.final_state_commitment != tx.account_update().initial_state_commitment() {
116            return Err(BatchAccountUpdateError::AccountUpdateInitialStateMismatch(tx.id()));
117        }
118
119        self.details = self.details.clone().merge(tx.account_update().details().clone()).map_err(
120            |source_err| BatchAccountUpdateError::TransactionUpdateMergeError(tx.id(), source_err),
121        )?;
122        self.final_state_commitment = tx.account_update().final_state_commitment();
123        self.transactions.push(tx.id());
124
125        Ok(())
126    }
127
128    // CONVERSIONS
129    // --------------------------------------------------------------------------------------------
130
131    /// Consumes the update and returns the non-[`Copy`] parts.
132    pub fn into_parts(self) -> (Vec<TransactionId>, AccountUpdateDetails) {
133        (self.transactions, self.details)
134    }
135}
136
137// SERIALIZATION
138// ================================================================================================
139
140impl Serializable for BatchAccountUpdate {
141    fn write_into<W: ByteWriter>(&self, target: &mut W) {
142        self.account_id.write_into(target);
143        self.initial_state_commitment.write_into(target);
144        self.final_state_commitment.write_into(target);
145        self.transactions.write_into(target);
146        self.details.write_into(target);
147    }
148}
149
150impl Deserializable for BatchAccountUpdate {
151    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
152        Ok(Self {
153            account_id: AccountId::read_from(source)?,
154            initial_state_commitment: Digest::read_from(source)?,
155            final_state_commitment: Digest::read_from(source)?,
156            transactions: <Vec<TransactionId>>::read_from(source)?,
157            details: AccountUpdateDetails::read_from(source)?,
158        })
159    }
160}