miden_client/sync/
block_header.rs1use alloc::vec::Vec;
2
3use crypto::merkle::{InOrderIndex, MmrDelta, MmrPeaks, PartialMmr};
4use miden_objects::{
5 Digest,
6 block::{BlockHeader, BlockNumber},
7 crypto::{self, merkle::MerklePath},
8};
9use tracing::warn;
10
11use super::NoteUpdates;
12use crate::{
13 Client, ClientError,
14 note::NoteScreener,
15 store::{ChainMmrNodeFilter, NoteFilter, StoreError},
16};
17
18pub(crate) const MAX_BLOCK_NUMBER_DELTA: u32 = 256;
21
22impl Client {
24 pub(crate) async fn update_mmr_data(&mut self) -> Result<(), ClientError> {
27 let mut current_partial_mmr = self.build_current_partial_mmr(true).await?;
28
29 let mut changed_notes = vec![];
30 for mut note in self.store.get_input_notes(NoteFilter::Unverified).await? {
31 let block_num = note
32 .inclusion_proof()
33 .expect("Commited notes should have inclusion proofs")
34 .location()
35 .block_num();
36 let block_header = self
37 .get_and_store_authenticated_block(block_num, &mut current_partial_mmr)
38 .await?;
39
40 if note.block_header_received(&block_header)? {
41 changed_notes.push(note);
42 }
43 }
44
45 self.store.upsert_input_notes(&changed_notes).await?;
46
47 Ok(())
48 }
49
50 pub async fn ensure_genesis_in_place(&mut self) -> Result<BlockHeader, ClientError> {
53 let genesis = self.store.get_block_header_by_num(0.into()).await?;
54
55 match genesis {
56 Some((block, _)) => Ok(block),
57 None => self.retrieve_and_store_genesis().await,
58 }
59 }
60
61 async fn retrieve_and_store_genesis(&mut self) -> Result<BlockHeader, ClientError> {
64 let (genesis_block, _) = self
65 .rpc_api
66 .get_block_header_by_number(Some(BlockNumber::GENESIS), false)
67 .await?;
68
69 let blank_mmr_peaks =
70 MmrPeaks::new(0, vec![]).expect("Blank MmrPeaks should not fail to instantiate");
71 self.store.insert_block_header(&genesis_block, blank_mmr_peaks, true).await?;
74 Ok(genesis_block)
75 }
76
77 pub(crate) async fn check_block_relevance(
83 &mut self,
84 committed_notes: &NoteUpdates,
85 ) -> Result<bool, ClientError> {
86 let note_screener = NoteScreener::new(self.store.clone());
90
91 for input_note in committed_notes.updated_input_notes() {
93 if !note_screener
94 .check_relevance(&input_note.try_into().map_err(ClientError::NoteRecordError)?)
95 .await?
96 .is_empty()
97 {
98 return Ok(true);
99 }
100 }
101
102 Ok(false)
103 }
104
105 pub(crate) async fn build_current_partial_mmr(
112 &self,
113 include_current_block: bool,
114 ) -> Result<PartialMmr, ClientError> {
115 let current_block_num = self.store.get_sync_height().await?;
116
117 let tracked_nodes = self.store.get_chain_mmr_nodes(ChainMmrNodeFilter::All).await?;
118 let current_peaks = self.store.get_chain_mmr_peaks_by_block_num(current_block_num).await?;
119
120 let track_latest = if current_block_num.as_u32() != 0 {
121 match self
122 .store
123 .get_block_header_by_num(BlockNumber::from(current_block_num.as_u32() - 1))
124 .await?
125 {
126 Some((_, previous_block_had_notes)) => previous_block_had_notes,
127 None => false,
128 }
129 } else {
130 false
131 };
132
133 let mut current_partial_mmr =
134 PartialMmr::from_parts(current_peaks, tracked_nodes, track_latest);
135
136 if include_current_block {
137 let (current_block, has_client_notes) = self
138 .store
139 .get_block_header_by_num(current_block_num)
140 .await?
141 .expect("Current block should be in the store");
142
143 current_partial_mmr.add(current_block.commitment(), has_client_notes);
144 }
145
146 Ok(current_partial_mmr)
147 }
148
149 pub(crate) async fn get_and_store_authenticated_block(
155 &self,
156 block_num: BlockNumber,
157 current_partial_mmr: &mut PartialMmr,
158 ) -> Result<BlockHeader, ClientError> {
159 if current_partial_mmr.is_tracked(block_num.as_usize()) {
160 warn!("Current partial MMR already contains the requested data");
161 let (block_header, _) = self
162 .store
163 .get_block_header_by_num(block_num)
164 .await?
165 .expect("Block header should be tracked");
166 return Ok(block_header);
167 }
168 let (block_header, mmr_proof) = self.rpc_api.get_block_header_with_proof(block_num).await?;
169
170 let path_nodes = adjust_merkle_path_for_forest(
173 &mmr_proof.merkle_path,
174 block_num,
175 current_partial_mmr.forest(),
176 );
177
178 let merkle_path = MerklePath::new(path_nodes.iter().map(|(_, n)| *n).collect());
179
180 current_partial_mmr
181 .track(block_num.as_usize(), block_header.commitment(), &merkle_path)
182 .map_err(StoreError::MmrError)?;
183
184 self.store
186 .insert_block_header(&block_header, current_partial_mmr.peaks(), true)
187 .await?;
188 self.store.insert_chain_mmr_nodes(&path_nodes).await?;
189
190 Ok(block_header)
191 }
192
193 pub async fn get_epoch_block(
197 &mut self,
198 block_num: BlockNumber,
199 ) -> Result<BlockHeader, ClientError> {
200 let epoch = block_num.block_epoch();
201 let epoch_block_number = BlockNumber::from_epoch(epoch);
202
203 if let Some((epoch_block, _)) =
204 self.store.get_block_header_by_num(epoch_block_number).await?
205 {
206 return Ok(epoch_block);
207 }
208
209 if epoch_block_number == 0.into() {
210 return self.ensure_genesis_in_place().await;
211 }
212
213 let mut current_partial_mmr = self.build_current_partial_mmr(true).await?;
214 let anchor_block = self
215 .get_and_store_authenticated_block(epoch_block_number, &mut current_partial_mmr)
216 .await?;
217
218 Ok(anchor_block)
219 }
220
221 pub async fn get_latest_epoch_block(&mut self) -> Result<BlockHeader, ClientError> {
225 let current_block_num = self.store.get_sync_height().await?;
226 self.get_epoch_block(current_block_num).await
227 }
228}
229
230fn adjust_merkle_path_for_forest(
242 merkle_path: &MerklePath,
243 block_num: BlockNumber,
244 forest: usize,
245) -> Vec<(InOrderIndex, Digest)> {
246 assert!(
247 forest > block_num.as_usize(),
248 "Can't adjust merkle path for a forest that does not include the block number"
249 );
250
251 let rightmost_index = InOrderIndex::from_leaf_pos(forest - 1);
252
253 let mut idx = InOrderIndex::from_leaf_pos(block_num.as_usize());
254 let mut path_nodes = vec![];
255 for node in merkle_path.iter() {
256 idx = idx.sibling();
257 if idx <= rightmost_index {
260 path_nodes.push((idx, *node));
261 }
262 idx = idx.parent();
263 }
264
265 path_nodes
266}
267
268pub(crate) fn apply_mmr_changes(
271 current_partial_mmr: PartialMmr,
272 mmr_delta: MmrDelta,
273 current_block_header: &BlockHeader,
274 current_block_has_relevant_notes: bool,
275) -> Result<(MmrPeaks, Vec<(InOrderIndex, Digest)>), StoreError> {
276 let mut partial_mmr: PartialMmr = current_partial_mmr;
277
278 let new_authentication_nodes = partial_mmr
280 .add(current_block_header.commitment(), current_block_has_relevant_notes)
281 .into_iter();
282
283 let new_authentication_nodes: Vec<(InOrderIndex, Digest)> = partial_mmr
285 .apply(mmr_delta)
286 .map_err(StoreError::MmrError)?
287 .into_iter()
288 .chain(new_authentication_nodes)
289 .collect();
290
291 Ok((partial_mmr.peaks(), new_authentication_nodes))
292}