Skip to main content

miden_protocol/transaction/
ordered_transactions.rs

1use alloc::vec::Vec;
2
3use crate::account::AccountId;
4use crate::transaction::{TransactionHeader, TransactionId};
5use crate::utils::serde::{
6    ByteReader,
7    ByteWriter,
8    Deserializable,
9    DeserializationError,
10    Serializable,
11};
12use crate::{Felt, Hasher, Word};
13
14// ORDERED TRANSACTION HEADERS
15// ================================================================================================
16
17/// The ordered set of transaction headers in a [`ProvenBatch`](crate::batch::ProvenBatch) or
18/// [`ProvenBlock`](crate::block::ProvenBlock).
19///
20/// This is a newtype wrapper representing either:
21/// - the set of transactions in a **batch**,
22/// - or the flattened sets of transactions of each proven batch in a **block**.
23///
24/// This type cannot be constructed directly, but can be retrieved through:
25/// - [`ProposedBatch::transaction_headers`](crate::batch::ProposedBatch::transaction_headers),
26/// - [`OrderedBatches::into_transactions`](crate::batch::OrderedBatches::into_transactions).
27///
28/// The rationale for this requirement is that it allows a client to cheaply validate the
29/// correctness of the transactions in a proven block returned by a remote prover.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct OrderedTransactionHeaders(Vec<TransactionHeader>);
32
33impl OrderedTransactionHeaders {
34    /// Creates a new set of ordered transaction headers from the provided vector.
35    ///
36    /// # Warning
37    ///
38    /// See the type-level documentation for the requirements of the passed transactions.
39    pub fn new_unchecked(transactions: Vec<TransactionHeader>) -> Self {
40        Self(transactions)
41    }
42
43    /// Computes a commitment to the list of transactions.
44    ///
45    /// This is a sequential hash over each transaction's ID and its account ID.
46    pub fn commitment(&self) -> Word {
47        Self::compute_commitment(self.0.as_slice().iter().map(|tx| (tx.id(), tx.account_id())))
48    }
49
50    /// Returns the IDs of the accounts created by these transactions.
51    ///
52    /// Account-creating transactions are identified by their empty initial state commitment.
53    pub fn created_account_ids(&self) -> impl Iterator<Item = AccountId> + '_ {
54        self.0
55            .iter()
56            .filter(|transaction| transaction.initial_state_commitment().is_empty())
57            .map(TransactionHeader::account_id)
58    }
59
60    /// Returns a reference to the underlying transaction headers.
61    pub fn as_slice(&self) -> &[TransactionHeader] {
62        &self.0
63    }
64
65    /// Consumes self and returns the underlying vector of transaction headers.
66    pub fn into_vec(self) -> Vec<TransactionHeader> {
67        self.0
68    }
69
70    // PUBLIC HELPERS
71    // --------------------------------------------------------------------------------------------
72
73    /// Computes a commitment to the provided list of transactions.
74    ///
75    /// Each transaction is represented by a transaction ID and an account ID which it was executed
76    /// against. The commitment is a sequential hash over (TRANSACTION_ID, ACCOUNT_ID) tuples.
77    pub(crate) fn compute_commitment(
78        transactions: impl IntoIterator<Item = (TransactionId, AccountId)>,
79    ) -> Word {
80        let mut elements = vec![];
81        for (transaction_id, account_id) in transactions {
82            elements.extend_from_slice(transaction_id.as_elements());
83            elements.extend_from_slice(&[
84                account_id.suffix(),
85                account_id.prefix().as_felt(),
86                Felt::ZERO,
87                Felt::ZERO,
88            ]);
89        }
90
91        Hasher::hash_elements(&elements)
92    }
93}
94
95// SERIALIZATION
96// ================================================================================================
97
98impl Serializable for OrderedTransactionHeaders {
99    fn write_into<W: ByteWriter>(&self, target: &mut W) {
100        self.0.write_into(target)
101    }
102}
103
104impl Deserializable for OrderedTransactionHeaders {
105    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
106        source.read().map(OrderedTransactionHeaders::new_unchecked)
107    }
108}