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, false).await?;
41 Ok(genesis_block)
42 }
43
44 pub(crate) async fn build_current_partial_mmr(&self) -> Result<PartialMmr, ClientError> {
54 let current_block_num = self.store.get_sync_height().await?;
55
56 let tracked_nodes =
57 self.store.get_partial_blockchain_nodes(PartialBlockchainFilter::All).await?;
58 let current_peaks =
59 self.store.get_partial_blockchain_peaks_by_block_num(current_block_num).await?;
60
61 let track_latest = if current_block_num.as_u32() != 0 {
62 match self
63 .store
64 .get_block_header_by_num(BlockNumber::from(current_block_num.as_u32() - 1))
65 .await?
66 {
67 Some((_, previous_block_had_notes)) => previous_block_had_notes,
68 None => false,
69 }
70 } else {
71 false
72 };
73
74 let mut current_partial_mmr =
75 PartialMmr::from_parts(current_peaks, tracked_nodes, track_latest);
76
77 let (current_block, has_client_notes) = self
78 .store
79 .get_block_header_by_num(current_block_num)
80 .await?
81 .expect("Current block should be in the store");
82
83 current_partial_mmr.add(current_block.commitment(), has_client_notes);
84
85 Ok(current_partial_mmr)
86 }
87
88 pub(crate) async fn get_and_store_authenticated_block(
94 &self,
95 block_num: BlockNumber,
96 current_partial_mmr: &mut PartialMmr,
97 ) -> Result<BlockHeader, ClientError> {
98 if current_partial_mmr.is_tracked(block_num.as_usize()) {
99 warn!("Current partial MMR already contains the requested data");
100 let (block_header, _) = self
101 .store
102 .get_block_header_by_num(block_num)
103 .await?
104 .expect("Block header should be tracked");
105 return Ok(block_header);
106 }
107
108 let (block_header, path_nodes) =
110 fetch_block_header(self.rpc_api.clone(), block_num, current_partial_mmr).await?;
111
112 self.store
114 .insert_block_header(&block_header, current_partial_mmr.peaks(), true)
115 .await?;
116 self.store.insert_partial_blockchain_nodes(&path_nodes).await?;
117
118 Ok(block_header)
119 }
120}
121
122pub(crate) fn adjust_merkle_path_for_forest(
134 merkle_path: &MerklePath,
135 block_num: BlockNumber,
136 forest: usize,
137) -> Vec<(InOrderIndex, Digest)> {
138 assert!(
139 forest > block_num.as_usize(),
140 "Can't adjust merkle path for a forest that does not include the block number"
141 );
142
143 let rightmost_index = InOrderIndex::from_leaf_pos(forest - 1);
144
145 let mut idx = InOrderIndex::from_leaf_pos(block_num.as_usize());
146 let mut path_nodes = vec![];
147 for node in merkle_path.iter() {
148 idx = idx.sibling();
149 if idx <= rightmost_index {
152 path_nodes.push((idx, *node));
153 }
154 idx = idx.parent();
155 }
156
157 path_nodes
158}
159
160pub(crate) async fn fetch_block_header(
161 rpc_api: Arc<dyn NodeRpcClient>,
162 block_num: BlockNumber,
163 current_partial_mmr: &mut PartialMmr,
164) -> Result<(BlockHeader, Vec<(InOrderIndex, Digest)>), ClientError> {
165 let (block_header, mmr_proof) = rpc_api.get_block_header_with_proof(block_num).await?;
166
167 let path_nodes = adjust_merkle_path_for_forest(
170 &mmr_proof.merkle_path,
171 block_num,
172 current_partial_mmr.forest(),
173 );
174
175 let merkle_path = MerklePath::new(path_nodes.iter().map(|(_, n)| *n).collect());
176
177 current_partial_mmr
178 .track(block_num.as_usize(), block_header.commitment(), &merkle_path)
179 .map_err(StoreError::MmrError)?;
180
181 Ok((block_header, path_nodes))
182}