miden_objects/batch/
batch_id.rs

1use alloc::{string::String, vec::Vec};
2
3use crate::{
4    Digest, Felt, Hasher, ZERO,
5    account::AccountId,
6    transaction::{ProvenTransaction, TransactionId},
7    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
8};
9
10// BATCH ID
11// ================================================================================================
12
13/// Uniquely identifies a batch of transactions, i.e. both
14/// [`ProposedBatch`](crate::batch::ProposedBatch) and [`ProvenBatch`](crate::batch::ProvenBatch).
15///
16/// This is a sequential hash of the tuple `(TRANSACTION_ID || [account_id_prefix,
17/// account_id_suffix, 0, 0])` of all transactions and the accounts their executed against in the
18/// batch.
19#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
20pub struct BatchId(Digest);
21
22impl BatchId {
23    /// Calculates a batch ID from the given set of transactions.
24    pub fn from_transactions<'tx, T>(txs: T) -> Self
25    where
26        T: Iterator<Item = &'tx ProvenTransaction>,
27    {
28        Self::from_ids(txs.map(|tx| (tx.id(), tx.account_id())))
29    }
30
31    /// Calculates a batch ID from the given transaction ID and account ID tuple.
32    pub fn from_ids(iter: impl IntoIterator<Item = (TransactionId, AccountId)>) -> Self {
33        let mut elements: Vec<Felt> = Vec::new();
34        for (tx_id, account_id) in iter {
35            elements.extend_from_slice(tx_id.as_elements());
36            let [account_id_prefix, account_id_suffix] = <[Felt; 2]>::from(account_id);
37            elements.extend_from_slice(&[account_id_prefix, account_id_suffix, ZERO, ZERO]);
38        }
39
40        Self(Hasher::hash_elements(&elements))
41    }
42
43    /// Returns the elements representation of this batch ID.
44    pub fn as_elements(&self) -> &[Felt] {
45        self.0.as_elements()
46    }
47
48    /// Returns the byte representation of this batch ID.
49    pub fn as_bytes(&self) -> [u8; 32] {
50        self.0.as_bytes()
51    }
52
53    /// Returns a big-endian, hex-encoded string.
54    pub fn to_hex(&self) -> String {
55        self.0.to_hex()
56    }
57}
58
59impl core::fmt::Display for BatchId {
60    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61        write!(f, "{}", self.to_hex())
62    }
63}
64
65// SERIALIZATION
66// ================================================================================================
67
68impl Serializable for BatchId {
69    fn write_into<W: ByteWriter>(&self, target: &mut W) {
70        self.0.write_into(target);
71    }
72}
73
74impl Deserializable for BatchId {
75    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
76        Ok(Self(Digest::read_from(source)?))
77    }
78}