miden_client/sync/
block_header.rs1use alloc::sync::Arc;
2use alloc::vec::Vec;
3
4use miden_protocol::Word;
5use miden_protocol::block::{BlockHeader, BlockNumber};
6use miden_protocol::crypto::merkle::MerklePath;
7use miden_protocol::crypto::merkle::mmr::{Forest, InOrderIndex, MmrPeaks, PartialMmr};
8use tracing::warn;
9
10use crate::rpc::NodeRpcClient;
11use crate::store::StoreError;
12use crate::{Client, ClientError};
13
14impl<AUTH> Client<AUTH> {
16 pub async fn ensure_genesis_in_place(&mut self) -> Result<BlockHeader, ClientError> {
19 let genesis = if let Some((block, _)) = self.store.get_block_header_by_num(0.into()).await?
20 {
21 block
22 } else {
23 let genesis = self.retrieve_and_store_genesis().await?;
24 self.rpc_api.set_genesis_commitment(genesis.commitment()).await?;
25 genesis
26 };
27
28 Ok(genesis)
29 }
30
31 async fn retrieve_and_store_genesis(&mut self) -> Result<BlockHeader, ClientError> {
34 let (genesis_block, _) = self
35 .rpc_api
36 .get_block_header_by_number(Some(BlockNumber::GENESIS), false)
37 .await?;
38
39 let blank_mmr_peaks = MmrPeaks::new(Forest::empty(), vec![])
40 .expect("Blank MmrPeaks should not fail to instantiate");
41 self.store.insert_block_header(&genesis_block, blank_mmr_peaks, false).await?;
42 Ok(genesis_block)
43 }
44
45 pub async fn get_current_partial_mmr(&self) -> Result<PartialMmr, ClientError> {
47 self.store.get_current_partial_mmr().await.map_err(Into::into)
48 }
49
50 pub(crate) async fn get_and_store_authenticated_block(
59 &self,
60 block_num: BlockNumber,
61 current_partial_mmr: &mut PartialMmr,
62 ) -> Result<BlockHeader, ClientError> {
63 if current_partial_mmr.is_tracked(block_num.as_usize()) {
64 warn!("Current partial MMR already contains the requested data");
65 let (block_header, _) = self
66 .store
67 .get_block_header_by_num(block_num)
68 .await?
69 .expect("Block header should be tracked");
70 return Ok(block_header);
71 }
72
73 let (block_header, path_nodes) =
75 fetch_block_header(self.rpc_api.clone(), block_num, current_partial_mmr).await?;
76
77 self.store
79 .insert_block_header(&block_header, current_partial_mmr.peaks(), true)
80 .await?;
81 self.store.insert_partial_blockchain_nodes(&path_nodes).await?;
82
83 Ok(block_header)
84 }
85}
86
87pub(crate) fn adjust_merkle_path_for_forest(
99 merkle_path: &MerklePath,
100 block_num: BlockNumber,
101 forest: Forest,
102) -> Vec<(InOrderIndex, Word)> {
103 let expected_path_len = forest
104 .leaf_to_corresponding_tree(block_num.as_usize())
105 .expect("forest includes block number") as usize;
106
107 let mut idx = InOrderIndex::from_leaf_pos(block_num.as_usize());
108 let mut path_nodes = Vec::with_capacity(expected_path_len);
109
110 for node in merkle_path.nodes().iter().take(expected_path_len) {
111 path_nodes.push((idx.sibling(), *node));
112 idx = idx.parent();
113 }
114
115 path_nodes
116}
117
118pub(crate) async fn fetch_block_header(
119 rpc_api: Arc<dyn NodeRpcClient>,
120 block_num: BlockNumber,
121 current_partial_mmr: &mut PartialMmr,
122) -> Result<(BlockHeader, Vec<(InOrderIndex, Word)>), ClientError> {
123 let (block_header, mmr_proof) = rpc_api.get_block_header_with_proof(block_num).await?;
124
125 let path_nodes = adjust_merkle_path_for_forest(
128 &mmr_proof.merkle_path,
129 block_num,
130 current_partial_mmr.forest(),
131 );
132
133 let merkle_path = MerklePath::new(path_nodes.iter().map(|(_, n)| *n).collect());
134
135 current_partial_mmr
136 .track(block_num.as_usize(), block_header.commitment(), &merkle_path)
137 .map_err(StoreError::MmrError)?;
138
139 Ok((block_header, path_nodes))
140}
141
142#[cfg(test)]
143mod tests {
144 use miden_protocol::block::BlockNumber;
145 use miden_protocol::crypto::merkle::MerklePath;
146 use miden_protocol::crypto::merkle::mmr::{Forest, InOrderIndex, Mmr, PartialMmr};
147 use miden_protocol::{Felt, Word};
148
149 use super::adjust_merkle_path_for_forest;
150
151 fn word(n: u64) -> Word {
152 Word::new([Felt::new(n), Felt::new(0), Felt::new(0), Felt::new(0)])
153 }
154
155 #[test]
156 fn adjust_merkle_path_truncates_to_forest_bounds() {
157 let forest = Forest::new(5);
158 let block_num = BlockNumber::from(4u32);
160 let path = MerklePath::new(vec![word(1), word(2), word(3)]);
161
162 let adjusted = adjust_merkle_path_for_forest(&path, block_num, forest);
163 assert!(adjusted.is_empty());
165 }
166
167 #[test]
168 fn adjust_merkle_path_keeps_proof_valid_for_smaller_forest() {
169 let mut mmr = Mmr::new();
172 for value in 0u64..8 {
173 mmr.add(word(value));
174 }
175
176 let large_forest = Forest::new(8);
177 let small_forest = Forest::new(5);
178 let leaf_pos = 4usize;
179 let block_num = BlockNumber::from(u32::try_from(leaf_pos).unwrap());
180
181 let proof = mmr.open_at(leaf_pos, large_forest).expect("valid proof");
182 let adjusted_nodes =
183 adjust_merkle_path_for_forest(&proof.merkle_path, block_num, small_forest);
184 let adjusted_path = MerklePath::new(adjusted_nodes.iter().map(|(_, n)| *n).collect());
185
186 let peaks = mmr.peaks_at(small_forest).unwrap();
187 let mut partial = PartialMmr::from_peaks(peaks);
188 let leaf = mmr.get(leaf_pos).expect("leaf exists");
189
190 partial
191 .track(leaf_pos, leaf, &adjusted_path)
192 .expect("adjusted path should verify against smaller forest peaks");
193 }
194
195 #[test]
196 fn adjust_merkle_path_correct_indices() {
197 let forest = Forest::new(6);
199 let block_num = BlockNumber::from(1u32);
201 let nodes = vec![word(10), word(11), word(12), word(13)];
202 let path = MerklePath::new(nodes.clone());
203
204 let adjusted = adjust_merkle_path_for_forest(&path, block_num, forest);
205
206 assert_eq!(adjusted.len(), 2);
207 assert_eq!(adjusted[0].1, nodes[0]);
208 assert_eq!(adjusted[1].1, nodes[1]);
209
210 let mut idx = InOrderIndex::from_leaf_pos(1);
211 let expected0 = idx.sibling();
212 idx = idx.parent();
213 let expected1 = idx.sibling();
214
215 assert_eq!(adjusted[0].0, expected0);
216 assert_eq!(adjusted[1].0, expected1);
217 }
218
219 #[test]
220 fn adjust_path_limit_correct_when_siblings_in_bounds() {
221 let large_leaves = 8usize;
224 let small_leaves = 7usize;
225 let leaf_pos = 2usize;
226 let mut mmr = Mmr::new();
227 for value in 0u64..large_leaves as u64 {
228 mmr.add(word(value));
229 }
230
231 let small_forest = Forest::new(small_leaves);
232 let proof = mmr.open_at(leaf_pos, Forest::new(large_leaves)).expect("valid proof");
233 let expected_depth =
234 small_forest.leaf_to_corresponding_tree(leaf_pos).expect("leaf is in forest") as usize;
235
236 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
239 for _ in 0..expected_depth {
240 idx = idx.parent();
241 }
242 let next_sibling = idx.sibling();
243 let rightmost = InOrderIndex::from_leaf_pos(small_leaves - 1);
244 assert!(next_sibling <= rightmost);
245 assert!(proof.merkle_path.depth() as usize > expected_depth);
246
247 let adjusted = adjust_merkle_path_for_forest(
248 &proof.merkle_path,
249 BlockNumber::from(u32::try_from(leaf_pos).unwrap()),
250 small_forest,
251 );
252 assert_eq!(adjusted.len(), expected_depth);
253 }
254}