mod configuration;
pub use configuration::*;
mod header_leaf;
pub use header_leaf::*;
mod transaction_leaf;
pub use transaction_leaf::*;
pub mod transition_leaf;
pub use transition_leaf::*;
mod bytes;
mod parse;
mod serialize;
mod verify;
use snarkvm_console_network::prelude::*;
use snarkvm_console_types::Field;
#[derive(Clone, PartialEq, Eq)]
pub struct StatePath<N: Network> {
global_state_root: N::StateRoot,
block_path: BlockPath<N>,
block_hash: N::BlockHash,
previous_block_hash: N::BlockHash,
header_root: Field<N>,
header_path: HeaderPath<N>,
header_leaf: HeaderLeaf<N>,
transactions_path: TransactionsPath<N>,
transaction_id: N::TransactionID,
transaction_path: TransactionPath<N>,
transaction_leaf: TransactionLeaf<N>,
transition_path: TransitionPath<N>,
transition_leaf: TransitionLeaf<N>,
}
impl<N: Network> StatePath<N> {
pub fn new_local(
global_state_root: N::StateRoot,
local_state_root: N::TransactionID,
transaction_path: TransactionPath<N>,
transaction_leaf: TransactionLeaf<N>,
transition_path: TransitionPath<N>,
transition_leaf: TransitionLeaf<N>,
) -> Result<Self> {
let transactions_tree: TransactionsTree<N> = N::merkle_tree_bhp(&[local_state_root.to_bits_le()])?;
let transactions_path = transactions_tree.prove(0, &local_state_root.to_bits_le())?;
let transactions_root = transactions_tree.root();
let header_leaf = HeaderLeaf::<N>::new(0, *transactions_root);
let header_tree: HeaderTree<N> = N::merkle_tree_bhp(&[header_leaf.to_bits_le()])?;
let header_path = header_tree.prove(0, &header_leaf.to_bits_le())?;
let header_root = *header_tree.root();
let previous_block_hash: N::BlockHash = Field::<N>::zero().into();
let block_hash: N::BlockHash = previous_block_hash;
let block_tree: BlockTree<N> = N::merkle_tree_bhp(&[block_hash.to_bits_le()])?;
let block_path = block_tree.prove(0, &block_hash.to_bits_le())?;
Ok(Self {
global_state_root,
block_path,
block_hash,
previous_block_hash,
header_root,
header_path,
header_leaf,
transactions_path,
transaction_id: local_state_root,
transaction_path,
transaction_leaf,
transition_path,
transition_leaf,
})
}
#[allow(clippy::too_many_arguments)]
pub fn from(
global_state_root: N::StateRoot,
block_path: BlockPath<N>,
block_hash: N::BlockHash,
previous_block_hash: N::BlockHash,
header_root: Field<N>,
header_path: HeaderPath<N>,
header_leaf: HeaderLeaf<N>,
transactions_path: TransactionsPath<N>,
transaction_id: N::TransactionID,
transaction_path: TransactionPath<N>,
transaction_leaf: TransactionLeaf<N>,
transition_path: TransitionPath<N>,
transition_leaf: TransitionLeaf<N>,
) -> Self {
Self {
global_state_root,
block_path,
block_hash,
previous_block_hash,
header_root,
header_path,
header_leaf,
transactions_path,
transaction_id,
transaction_path,
transaction_leaf,
transition_path,
transition_leaf,
}
}
pub const fn global_state_root(&self) -> N::StateRoot {
self.global_state_root
}
pub const fn block_path(&self) -> &BlockPath<N> {
&self.block_path
}
pub const fn block_hash(&self) -> N::BlockHash {
self.block_hash
}
pub const fn previous_block_hash(&self) -> N::BlockHash {
self.previous_block_hash
}
pub const fn header_root(&self) -> &Field<N> {
&self.header_root
}
pub const fn header_path(&self) -> &HeaderPath<N> {
&self.header_path
}
pub const fn header_leaf(&self) -> &HeaderLeaf<N> {
&self.header_leaf
}
pub const fn transactions_path(&self) -> &TransactionsPath<N> {
&self.transactions_path
}
pub const fn transaction_id(&self) -> &N::TransactionID {
&self.transaction_id
}
pub const fn transaction_path(&self) -> &TransactionPath<N> {
&self.transaction_path
}
pub const fn transaction_leaf(&self) -> &TransactionLeaf<N> {
&self.transaction_leaf
}
pub const fn transition_path(&self) -> &TransitionPath<N> {
&self.transition_path
}
pub const fn transition_leaf(&self) -> &TransitionLeaf<N> {
&self.transition_leaf
}
}
#[cfg(any(test, feature = "test"))]
pub mod test_helpers {
use super::*;
use snarkvm_console_network::prelude::TestRng;
pub fn sample_global_state_path<N: Network>(
commitment: Option<Field<N>>,
rng: &mut TestRng,
) -> Result<StatePath<N>> {
let commitment = match commitment {
Some(commitment) => commitment,
None => Field::rand(rng),
};
let transition_leaf = TransitionLeaf::new_with_version(0, 3, commitment);
let transition_tree: TransitionTree<N> = N::merkle_tree_bhp(&[transition_leaf.to_bits_le()])?;
let transition_id = transition_tree.root();
let transition_path = transition_tree.prove(0, &transition_leaf.to_bits_le())?;
let transaction_leaf = TransactionLeaf::new_execution(0, *transition_id);
let transaction_tree: TransactionTree<N> = N::merkle_tree_bhp(&[transaction_leaf.to_bits_le()])?;
let transaction_id = *transaction_tree.root();
let transaction_path = transaction_tree.prove(0, &transaction_leaf.to_bits_le())?;
let transactions_tree: TransactionsTree<N> = N::merkle_tree_bhp(&[transaction_id.to_bits_le()])?;
let transactions_root = transactions_tree.root();
let transactions_path = transactions_tree.prove(0, &transaction_id.to_bits_le())?;
let header_leaf = HeaderLeaf::<N>::new(1, *transactions_root);
let header_tree: HeaderTree<N> =
N::merkle_tree_bhp(&[Field::<N>::zero().to_bits_le(), header_leaf.to_bits_le()])?;
let header_root = header_tree.root();
let header_path = header_tree.prove(1, &header_leaf.to_bits_le())?;
let previous_block_hash: N::BlockHash = Field::<N>::rand(rng).into();
let preimage = (*previous_block_hash).to_bits_le().into_iter().chain(header_root.to_bits_le().into_iter());
let block_hash = N::hash_bhp1024(&preimage.collect::<Vec<_>>())?;
let block_tree: BlockTree<N> = N::merkle_tree_bhp(&[block_hash.to_bits_le()])?;
let global_state_root = *block_tree.root();
let block_path = block_tree.prove(0, &block_hash.to_bits_le())?;
Ok(StatePath::<N>::from(
global_state_root.into(),
block_path,
block_hash.into(),
previous_block_hash,
*header_root,
header_path,
header_leaf,
transactions_path,
transaction_id.into(),
transaction_path,
transaction_leaf,
transition_path,
transition_leaf,
))
}
pub fn sample_local_state_path<N: Network>(
commitment: Option<Field<N>>,
rng: &mut TestRng,
) -> Result<StatePath<N>> {
let commitment = match commitment {
Some(commitment) => commitment,
None => Field::rand(rng),
};
let transition_leaf = TransitionLeaf::new_with_version(0, 3, commitment);
let transition_tree: TransitionTree<N> = N::merkle_tree_bhp(&[transition_leaf.to_bits_le()])?;
let transition_id = transition_tree.root();
let transition_path = transition_tree.prove(0, &transition_leaf.to_bits_le())?;
let transaction_leaf = TransactionLeaf::new_execution(0, *transition_id);
let transaction_tree: TransactionTree<N> = N::merkle_tree_bhp(&[transaction_leaf.to_bits_le()])?;
let transaction_id = *transaction_tree.root();
let transaction_path = transaction_tree.prove(0, &transaction_leaf.to_bits_le())?;
let transactions_tree: TransactionsTree<N> = N::merkle_tree_bhp(&[transaction_id.to_bits_le()])?;
let transactions_root = transactions_tree.root();
let transactions_path = transactions_tree.prove(0, &transaction_id.to_bits_le())?;
let random_header_index = rng.gen_range(0..7);
let mut random_header_leaves = vec![Field::<N>::zero().to_bits_le(); (random_header_index + 1) as usize];
let header_leaf = HeaderLeaf::<N>::new(random_header_index, *transactions_root);
random_header_leaves[random_header_index as usize] = header_leaf.to_bits_le();
let header_tree: HeaderTree<N> = N::merkle_tree_bhp(&random_header_leaves)?;
let header_root = header_tree.root();
let header_path = header_tree.prove(random_header_index as usize, &header_leaf.to_bits_le())?;
let previous_block_hash: N::BlockHash = Field::<N>::rand(rng).into();
let block_hash: N::BlockHash = Field::<N>::rand(rng).into();
let block_tree: BlockTree<N> = N::merkle_tree_bhp(&[block_hash.to_bits_le()])?;
let global_state_root = *block_tree.root();
let block_path = block_tree.prove(0, &block_hash.to_bits_le())?;
Ok(StatePath::<N>::from(
global_state_root.into(),
block_path,
block_hash,
previous_block_hash,
*header_root,
header_path,
header_leaf,
transactions_path,
transaction_id.into(),
transaction_path,
transaction_leaf,
transition_path,
transition_leaf,
))
}
}