miden_objects/block/proven_block.rs
1use alloc::vec::Vec;
2
3use crate::{
4 Digest,
5 account::AccountId,
6 block::{BlockAccountUpdate, BlockHeader, BlockNoteIndex, BlockNoteTree, OutputNoteBatch},
7 note::Nullifier,
8 transaction::{OutputNote, TransactionId},
9 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
10};
11
12// PROVEN BLOCK
13// ================================================================================================
14
15/// A block in the Miden chain.
16///
17/// A block is built from batches of transactions, i.e. multiple
18/// [`ProvenBatch`](crate::batch::ProvenBatch)es, and each batch contains multiple
19/// [`ProvenTransaction`](crate::transaction::ProvenTransaction)s.
20///
21/// It consists of the following components:
22/// - A [`BlockHeader`] committing to the current state of the chain and against which account, note
23/// or nullifier inclusion or absence can be proven. See its documentation for details on what it
24/// commits to. Eventually, it will also contain a ZK proof of the validity of the block.
25/// - A list of account updates for all accounts updated in this block. For private accounts, the
26/// update contains only the new account state commitments while for public accounts, the update
27/// also includes the delta which can be applied to the previous account state to get the new
28/// account state.
29/// - A list of new notes created in this block. For private notes, the block contains only note IDs
30/// and note metadata while for public notes the full note details are included.
31/// - A list of new nullifiers created for all notes that were consumed in the block.
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct ProvenBlock {
34 /// The header of the block, committing to the current state of the chain.
35 header: BlockHeader,
36
37 /// Account updates for the block.
38 updated_accounts: Vec<BlockAccountUpdate>,
39
40 /// Note batches created by the transactions in this block.
41 output_note_batches: Vec<OutputNoteBatch>,
42
43 /// Nullifiers created by the transactions in this block through the consumption of notes.
44 created_nullifiers: Vec<Nullifier>,
45}
46
47impl ProvenBlock {
48 /// Returns a new [`ProvenBlock`] instantiated from the provided components.
49 ///
50 /// # Warning
51 ///
52 /// This constructor does not do any validation, so passing incorrect values may lead to later
53 /// panics.
54 pub fn new_unchecked(
55 header: BlockHeader,
56 updated_accounts: Vec<BlockAccountUpdate>,
57 output_note_batches: Vec<OutputNoteBatch>,
58 created_nullifiers: Vec<Nullifier>,
59 ) -> Self {
60 Self {
61 header,
62 updated_accounts,
63 output_note_batches,
64 created_nullifiers,
65 }
66 }
67
68 /// Returns the commitment to this block.
69 pub fn commitment(&self) -> Digest {
70 self.header.commitment()
71 }
72
73 /// Returns the header of this block.
74 pub fn header(&self) -> &BlockHeader {
75 &self.header
76 }
77
78 /// Returns the slice of [`BlockAccountUpdate`]s for all accounts updated in this block.
79 pub fn updated_accounts(&self) -> &[BlockAccountUpdate] {
80 &self.updated_accounts
81 }
82
83 /// Returns the slice of [`OutputNoteBatch`]es for all output notes created in this block.
84 pub fn output_note_batches(&self) -> &[OutputNoteBatch] {
85 &self.output_note_batches
86 }
87
88 /// Returns an iterator over all [`OutputNote`]s created in this block.
89 ///
90 /// Each note is accompanied by a corresponding index specifying where the note is located
91 /// in the block's [`BlockNoteTree`].
92 pub fn output_notes(&self) -> impl Iterator<Item = (BlockNoteIndex, &OutputNote)> {
93 self.output_note_batches.iter().enumerate().flat_map(|(batch_idx, notes)| {
94 notes.iter().map(move |(note_idx_in_batch, note)| {
95 (
96 // SAFETY: The proven block contains at most the max allowed number of batches
97 // and each batch is guaranteed to contain at most the
98 // max allowed number of output notes.
99 BlockNoteIndex::new(batch_idx, *note_idx_in_batch)
100 .expect("max batches in block and max notes in batches should be enforced"),
101 note,
102 )
103 })
104 })
105 }
106
107 /// Returns the [`BlockNoteTree`] containing all [`OutputNote`]s created in this block.
108 pub fn build_output_note_tree(&self) -> BlockNoteTree {
109 let entries = self
110 .output_notes()
111 .map(|(note_index, note)| (note_index, note.id(), *note.metadata()));
112
113 // SAFETY: We only construct proven blocks that:
114 // - do not contain duplicates
115 // - contain at most the max allowed number of batches and each batch is guaranteed to
116 // contain at most the max allowed number of output notes.
117 BlockNoteTree::with_entries(entries)
118 .expect("the output notes of the block should not contain duplicates and contain at most the allowed maximum")
119 }
120
121 /// Returns a reference to the slice of nullifiers for all notes consumed in the block.
122 pub fn created_nullifiers(&self) -> &[Nullifier] {
123 &self.created_nullifiers
124 }
125
126 /// Returns an iterator over all transactions which affected accounts in the block with
127 /// their corresponding account IDs.
128 pub fn transactions(&self) -> impl Iterator<Item = (TransactionId, AccountId)> + '_ {
129 self.updated_accounts.iter().flat_map(|update| {
130 update
131 .transactions()
132 .iter()
133 .map(|transaction_id| (*transaction_id, update.account_id()))
134 })
135 }
136}
137
138impl Serializable for ProvenBlock {
139 fn write_into<W: ByteWriter>(&self, target: &mut W) {
140 self.header.write_into(target);
141 self.updated_accounts.write_into(target);
142 self.output_note_batches.write_into(target);
143 self.created_nullifiers.write_into(target);
144 }
145}
146
147impl Deserializable for ProvenBlock {
148 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
149 let block = Self {
150 header: BlockHeader::read_from(source)?,
151 updated_accounts: <Vec<BlockAccountUpdate>>::read_from(source)?,
152 output_note_batches: <Vec<OutputNoteBatch>>::read_from(source)?,
153 created_nullifiers: <Vec<Nullifier>>::read_from(source)?,
154 };
155
156 Ok(block)
157 }
158}