snarkvm_console_program/state_path/
mod.rs1mod configuration;
17pub use configuration::*;
18
19mod header_leaf;
20pub use header_leaf::*;
21
22mod transaction_leaf;
23pub use transaction_leaf::*;
24
25pub mod transition_leaf;
26pub use transition_leaf::*;
27
28mod bytes;
29mod parse;
30mod serialize;
31mod verify;
32
33use snarkvm_console_network::prelude::*;
34use snarkvm_console_types::Field;
35
36#[derive(Clone, PartialEq, Eq)]
38pub struct StatePath<N: Network> {
39 global_state_root: N::StateRoot,
41 block_path: BlockPath<N>,
43 block_hash: N::BlockHash,
45 previous_block_hash: N::BlockHash,
47 header_root: Field<N>,
49 header_path: HeaderPath<N>,
51 header_leaf: HeaderLeaf<N>,
53 transactions_path: TransactionsPath<N>,
55 transaction_id: N::TransactionID,
57 transaction_path: TransactionPath<N>,
59 transaction_leaf: TransactionLeaf<N>,
61 transition_root: Field<N>,
63 tcm: Field<N>,
65 transition_path: TransitionPath<N>,
67 transition_leaf: TransitionLeaf<N>,
69}
70
71impl<N: Network> StatePath<N> {
72 pub fn new_local(
74 global_state_root: N::StateRoot,
75 local_state_root: N::TransactionID,
76 transaction_path: TransactionPath<N>,
77 transaction_leaf: TransactionLeaf<N>,
78 transition_root: Field<N>,
79 tcm: Field<N>,
80 transition_path: TransitionPath<N>,
81 transition_leaf: TransitionLeaf<N>,
82 ) -> Result<Self> {
83 let local_state_root_bits = local_state_root.to_bits_le();
85 let transactions_tree: TransactionsTree<N> = N::merkle_tree_bhp(&[local_state_root_bits.clone()])?;
86 let transactions_path = transactions_tree.prove(0, &local_state_root_bits)?;
87 let transactions_root = transactions_tree.root();
88
89 let header_leaf = HeaderLeaf::<N>::new(0, *transactions_root);
91 let header_leaf_bits = header_leaf.to_bits_le();
92 let header_tree: HeaderTree<N> = N::merkle_tree_bhp(&[header_leaf_bits.clone()])?;
93 let header_path = header_tree.prove(0, &header_leaf_bits)?;
94 let header_root = *header_tree.root();
95
96 let previous_block_hash: N::BlockHash = Field::<N>::zero().into();
98 let block_hash: N::BlockHash = previous_block_hash;
99 let block_hash_bits = block_hash.to_bits_le();
100 let block_tree: BlockTree<N> = N::merkle_tree_bhp(&[block_hash_bits.clone()])?;
101 let block_path = block_tree.prove(0, &block_hash_bits)?;
102
103 Ok(Self {
105 global_state_root,
106 block_path,
107 block_hash,
108 previous_block_hash,
109 header_root,
110 header_path,
111 header_leaf,
112 transactions_path,
113 transaction_id: local_state_root,
114 transaction_path,
115 transaction_leaf,
116 transition_root,
117 tcm,
118 transition_path,
119 transition_leaf,
120 })
121 }
122
123 #[allow(clippy::too_many_arguments)]
125 pub fn from(
126 global_state_root: N::StateRoot,
127 block_path: BlockPath<N>,
128 block_hash: N::BlockHash,
129 previous_block_hash: N::BlockHash,
130 header_root: Field<N>,
131 header_path: HeaderPath<N>,
132 header_leaf: HeaderLeaf<N>,
133 transactions_path: TransactionsPath<N>,
134 transaction_id: N::TransactionID,
135 transaction_path: TransactionPath<N>,
136 transaction_leaf: TransactionLeaf<N>,
137 transition_root: Field<N>,
138 tcm: Field<N>,
139 transition_path: TransitionPath<N>,
140 transition_leaf: TransitionLeaf<N>,
141 ) -> Self {
142 Self {
144 global_state_root,
145 block_path,
146 block_hash,
147 previous_block_hash,
148 header_root,
149 header_path,
150 header_leaf,
151 transactions_path,
152 transaction_id,
153 transaction_path,
154 transaction_leaf,
155 transition_root,
156 tcm,
157 transition_path,
158 transition_leaf,
159 }
160 }
161
162 pub const fn global_state_root(&self) -> N::StateRoot {
164 self.global_state_root
165 }
166
167 pub const fn block_path(&self) -> &BlockPath<N> {
169 &self.block_path
170 }
171
172 pub const fn block_hash(&self) -> N::BlockHash {
174 self.block_hash
175 }
176
177 pub const fn previous_block_hash(&self) -> N::BlockHash {
179 self.previous_block_hash
180 }
181
182 pub const fn header_root(&self) -> &Field<N> {
184 &self.header_root
185 }
186
187 pub const fn header_path(&self) -> &HeaderPath<N> {
189 &self.header_path
190 }
191
192 pub const fn header_leaf(&self) -> &HeaderLeaf<N> {
194 &self.header_leaf
195 }
196
197 pub const fn transactions_path(&self) -> &TransactionsPath<N> {
199 &self.transactions_path
200 }
201
202 pub const fn transaction_id(&self) -> &N::TransactionID {
204 &self.transaction_id
205 }
206
207 pub const fn transaction_path(&self) -> &TransactionPath<N> {
209 &self.transaction_path
210 }
211
212 pub const fn transaction_leaf(&self) -> &TransactionLeaf<N> {
214 &self.transaction_leaf
215 }
216
217 pub const fn transition_root(&self) -> &Field<N> {
219 &self.transition_root
220 }
221
222 pub const fn tcm(&self) -> &Field<N> {
224 &self.tcm
225 }
226
227 pub const fn transition_path(&self) -> &TransitionPath<N> {
229 &self.transition_path
230 }
231
232 pub const fn transition_leaf(&self) -> &TransitionLeaf<N> {
234 &self.transition_leaf
235 }
236}
237
238#[cfg(any(test, feature = "test"))]
239pub mod test_helpers {
240 use super::*;
241 use snarkvm_console_network::prelude::TestRng;
242
243 pub fn sample_global_state_path<N: Network>(
246 commitment: Option<Field<N>>,
247 rng: &mut TestRng,
248 ) -> Result<StatePath<N>> {
249 let commitment = match commitment {
251 Some(commitment) => commitment,
252 None => Field::rand(rng),
253 };
254
255 let tcm = Field::rand(rng);
257
258 let transition_leaf = TransitionLeaf::new_with_version(0, 3, commitment);
260 let transition_tree: TransitionTree<N> = N::merkle_tree_bhp(&[transition_leaf.to_bits_le()])?;
261 let transition_root = *transition_tree.root();
262 let transition_id = N::hash_bhp512(&(transition_root, tcm).to_bits_le())?;
263 let transition_path = transition_tree.prove(0, &transition_leaf.to_bits_le())?;
264
265 let transaction_leaf = TransactionLeaf::new_execution(0, transition_id);
267 let transaction_tree: TransactionTree<N> = N::merkle_tree_bhp(&[transaction_leaf.to_bits_le()])?;
268 let transaction_id = *transaction_tree.root();
269 let transaction_path = transaction_tree.prove(0, &transaction_leaf.to_bits_le())?;
270
271 let transactions_tree: TransactionsTree<N> = N::merkle_tree_bhp(&[transaction_id.to_bits_le()])?;
273 let transactions_root = transactions_tree.root();
274 let transactions_path = transactions_tree.prove(0, &transaction_id.to_bits_le())?;
275
276 let header_leaf = HeaderLeaf::<N>::new(1, *transactions_root);
278 let header_tree: HeaderTree<N> =
279 N::merkle_tree_bhp(&[Field::<N>::zero().to_bits_le(), header_leaf.to_bits_le()])?;
280 let header_root = header_tree.root();
281 let header_path = header_tree.prove(1, &header_leaf.to_bits_le())?;
282
283 let previous_block_hash: N::BlockHash = Field::<N>::rand(rng).into();
284 let preimage = (*previous_block_hash).to_bits_le().into_iter().chain(header_root.to_bits_le());
285 let block_hash = N::hash_bhp1024(&preimage.collect::<Vec<_>>())?;
286
287 let block_tree: BlockTree<N> = N::merkle_tree_bhp(&[block_hash.to_bits_le()])?;
289 let global_state_root = *block_tree.root();
290 let block_path = block_tree.prove(0, &block_hash.to_bits_le())?;
291
292 Ok(StatePath::<N>::from(
293 global_state_root.into(),
294 block_path,
295 block_hash.into(),
296 previous_block_hash,
297 *header_root,
298 header_path,
299 header_leaf,
300 transactions_path,
301 transaction_id.into(),
302 transaction_path,
303 transaction_leaf,
304 transition_root,
305 tcm,
306 transition_path,
307 transition_leaf,
308 ))
309 }
310
311 pub fn sample_local_state_path<N: Network>(
314 commitment: Option<Field<N>>,
315 rng: &mut TestRng,
316 ) -> Result<StatePath<N>> {
317 let commitment = match commitment {
319 Some(commitment) => commitment,
320 None => Field::rand(rng),
321 };
322
323 let tcm = Field::rand(rng);
325
326 let transition_leaf = TransitionLeaf::new_with_version(0, 3, commitment);
328 let transition_tree: TransitionTree<N> = N::merkle_tree_bhp(&[transition_leaf.to_bits_le()])?;
329 let transition_root = *transition_tree.root();
330 let transition_id = N::hash_bhp512(&(transition_root, tcm).to_bits_le())?;
331 let transition_path = transition_tree.prove(0, &transition_leaf.to_bits_le())?;
332
333 let transaction_leaf = TransactionLeaf::new_execution(0, transition_id);
335 let transaction_tree: TransactionTree<N> = N::merkle_tree_bhp(&[transaction_leaf.to_bits_le()])?;
336 let transaction_id = *transaction_tree.root();
337 let transaction_path = transaction_tree.prove(0, &transaction_leaf.to_bits_le())?;
338
339 let transactions_tree: TransactionsTree<N> = N::merkle_tree_bhp(&[transaction_id.to_bits_le()])?;
341 let transactions_root = transactions_tree.root();
342 let transactions_path = transactions_tree.prove(0, &transaction_id.to_bits_le())?;
343
344 let random_header_index = rng.gen_range(0..7);
346 let mut random_header_leaves = vec![Field::<N>::zero().to_bits_le(); (random_header_index + 1) as usize];
347 let header_leaf = HeaderLeaf::<N>::new(random_header_index, *transactions_root);
348 random_header_leaves[random_header_index as usize] = header_leaf.to_bits_le();
349
350 let header_tree: HeaderTree<N> = N::merkle_tree_bhp(&random_header_leaves)?;
352 let header_root = header_tree.root();
353 let header_path = header_tree.prove(random_header_index as usize, &header_leaf.to_bits_le())?;
354
355 let previous_block_hash: N::BlockHash = Field::<N>::rand(rng).into();
356 let block_hash: N::BlockHash = Field::<N>::rand(rng).into();
357
358 let block_tree: BlockTree<N> = N::merkle_tree_bhp(&[block_hash.to_bits_le()])?;
360 let global_state_root = *block_tree.root();
361 let block_path = block_tree.prove(0, &block_hash.to_bits_le())?;
362
363 Ok(StatePath::<N>::from(
364 global_state_root.into(),
365 block_path,
366 block_hash,
367 previous_block_hash,
368 *header_root,
369 header_path,
370 header_leaf,
371 transactions_path,
372 transaction_id.into(),
373 transaction_path,
374 transaction_leaf,
375 transition_root,
376 tcm,
377 transition_path,
378 transition_leaf,
379 ))
380 }
381}