miden_client/sync/
block_header.rs1use alloc::{sync::Arc, vec::Vec};
2
3use crypto::merkle::{InOrderIndex, MmrPeaks, PartialMmr};
4use miden_objects::{
5 Digest,
6 block::{BlockHeader, BlockNumber},
7 crypto::{self, merkle::MerklePath},
8};
9use tracing::warn;
10
11use crate::{
12 Client, ClientError,
13 rpc::NodeRpcClient,
14 store::{PartialBlockchainFilter, StoreError},
15};
16
17impl Client {
19 pub async fn ensure_genesis_in_place(&mut self) -> Result<BlockHeader, ClientError> {
22 let genesis = self.store.get_block_header_by_num(0.into()).await?;
23
24 match genesis {
25 Some((block, _)) => Ok(block),
26 None => self.retrieve_and_store_genesis().await,
27 }
28 }
29
30 async fn retrieve_and_store_genesis(&mut self) -> Result<BlockHeader, ClientError> {
33 let (genesis_block, _) = self
34 .rpc_api
35 .get_block_header_by_number(Some(BlockNumber::GENESIS), false)
36 .await?;
37
38 let blank_mmr_peaks =
39 MmrPeaks::new(0, vec![]).expect("Blank MmrPeaks should not fail to instantiate");
40 self.store.insert_block_header(&genesis_block, blank_mmr_peaks, true).await?;
43 Ok(genesis_block)
44 }
45
46 pub(crate) async fn build_current_partial_mmr(&self) -> Result<PartialMmr, ClientError> {
56 let current_block_num = self.store.get_sync_height().await?;
57
58 let tracked_nodes =
59 self.store.get_partial_blockchain_nodes(PartialBlockchainFilter::All).await?;
60 let current_peaks =
61 self.store.get_partial_blockchain_peaks_by_block_num(current_block_num).await?;
62
63 let track_latest = if current_block_num.as_u32() != 0 {
64 match self
65 .store
66 .get_block_header_by_num(BlockNumber::from(current_block_num.as_u32() - 1))
67 .await?
68 {
69 Some((_, previous_block_had_notes)) => previous_block_had_notes,
70 None => false,
71 }
72 } else {
73 false
74 };
75
76 let mut current_partial_mmr =
77 PartialMmr::from_parts(current_peaks, tracked_nodes, track_latest);
78
79 let (current_block, has_client_notes) = self
80 .store
81 .get_block_header_by_num(current_block_num)
82 .await?
83 .expect("Current block should be in the store");
84
85 current_partial_mmr.add(current_block.commitment(), has_client_notes);
86
87 Ok(current_partial_mmr)
88 }
89
90 pub(crate) async fn get_and_store_authenticated_block(
96 &self,
97 block_num: BlockNumber,
98 current_partial_mmr: &mut PartialMmr,
99 ) -> Result<BlockHeader, ClientError> {
100 if current_partial_mmr.is_tracked(block_num.as_usize()) {
101 warn!("Current partial MMR already contains the requested data");
102 let (block_header, _) = self
103 .store
104 .get_block_header_by_num(block_num)
105 .await?
106 .expect("Block header should be tracked");
107 return Ok(block_header);
108 }
109
110 let (block_header, path_nodes) =
112 fetch_block_header(self.rpc_api.clone(), block_num, current_partial_mmr).await?;
113
114 self.store
116 .insert_block_header(&block_header, current_partial_mmr.peaks(), true)
117 .await?;
118 self.store.insert_partial_blockchain_nodes(&path_nodes).await?;
119
120 Ok(block_header)
121 }
122
123 pub async fn get_epoch_block(
127 &mut self,
128 block_num: BlockNumber,
129 ) -> Result<BlockHeader, ClientError> {
130 let epoch = block_num.block_epoch();
131 let epoch_block_number = BlockNumber::from_epoch(epoch);
132
133 if let Some((epoch_block, _)) =
134 self.store.get_block_header_by_num(epoch_block_number).await?
135 {
136 return Ok(epoch_block);
137 }
138
139 if epoch_block_number == 0.into() {
140 return self.ensure_genesis_in_place().await;
141 }
142
143 let mut current_partial_mmr = self.build_current_partial_mmr().await?;
144 let anchor_block = self
145 .get_and_store_authenticated_block(epoch_block_number, &mut current_partial_mmr)
146 .await?;
147
148 Ok(anchor_block)
149 }
150
151 pub async fn get_latest_epoch_block(&mut self) -> Result<BlockHeader, ClientError> {
155 let current_block_num = self.store.get_sync_height().await?;
156 self.get_epoch_block(current_block_num).await
157 }
158}
159
160pub(crate) fn adjust_merkle_path_for_forest(
172 merkle_path: &MerklePath,
173 block_num: BlockNumber,
174 forest: usize,
175) -> Vec<(InOrderIndex, Digest)> {
176 assert!(
177 forest > block_num.as_usize(),
178 "Can't adjust merkle path for a forest that does not include the block number"
179 );
180
181 let rightmost_index = InOrderIndex::from_leaf_pos(forest - 1);
182
183 let mut idx = InOrderIndex::from_leaf_pos(block_num.as_usize());
184 let mut path_nodes = vec![];
185 for node in merkle_path.iter() {
186 idx = idx.sibling();
187 if idx <= rightmost_index {
190 path_nodes.push((idx, *node));
191 }
192 idx = idx.parent();
193 }
194
195 path_nodes
196}
197
198pub(crate) async fn fetch_block_header(
199 rpc_api: Arc<dyn NodeRpcClient>,
200 block_num: BlockNumber,
201 current_partial_mmr: &mut PartialMmr,
202) -> Result<(BlockHeader, Vec<(InOrderIndex, Digest)>), ClientError> {
203 let (block_header, mmr_proof) = rpc_api.get_block_header_with_proof(block_num).await?;
204
205 let path_nodes = adjust_merkle_path_for_forest(
208 &mmr_proof.merkle_path,
209 block_num,
210 current_partial_mmr.forest(),
211 );
212
213 let merkle_path = MerklePath::new(path_nodes.iter().map(|(_, n)| *n).collect());
214
215 current_partial_mmr
216 .track(block_num.as_usize(), block_header.commitment(), &merkle_path)
217 .map_err(StoreError::MmrError)?;
218
219 Ok((block_header, path_nodes))
220}