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}