use super::*;
macro_rules! prepare_impl {
($self:ident, $transitions:ident, $query:ident, $current_state_root:ident, $get_state_path_for_commitment:ident $(, $await:ident)?) => {{
Transaction::<N>::check_execution_size($transitions.len())?;
let mut transaction_tree = N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&[])?;
let mut assignments = vec![];
let global_state_root = {
$query.$current_state_root()
$(.$await)?
}?;
if *global_state_root == Field::zero() {
bail!("Inclusion expected the global state root in the execution to *not* be zero")
}
for (transition_index, transition) in $transitions.iter().enumerate() {
let transaction_leaf = TransactionLeaf::new_execution(transition_index as u16, **transition.id());
match $self.input_tasks.get(transition.id()) {
Some(tasks) => {
for task in tasks {
let local_state_root = (*transaction_tree.root()).into();
let state_path = match &task.local {
Some((transaction_leaf, transition_root, tcm, transition_path, transition_leaf)) => {
let transaction_path =
transaction_tree.prove(transaction_leaf.index() as usize, &transaction_leaf.to_bits_le())?;
StatePath::new_local(
global_state_root,
local_state_root,
transaction_path,
*transaction_leaf,
*transition_root,
*tcm,
transition_path.clone(),
*transition_leaf,
)?
}
None => {
$query.$get_state_path_for_commitment(&task.commitment)
$(.$await)?
}?
};
if global_state_root != state_path.global_state_root() {
bail!("Inclusion expected the global state root to be the same across iterations")
}
let assignment = InclusionAssignment::new(
state_path,
task.commitment,
task.gamma,
task.serial_number,
local_state_root,
task.local.is_none(), );
assignments.push(assignment);
}
}
None => bail!("Missing input tasks for transition {} in inclusion", transition.id()),
}
transaction_tree.append(&[transaction_leaf.to_bits_le()])?;
}
Ok((assignments, global_state_root))
}};
}
impl<N: Network> Inclusion<N> {
pub fn prepare(
&self,
transitions: &[Transition<N>],
query: impl QueryTrait<N>,
) -> Result<(Vec<InclusionAssignment<N>>, N::StateRoot)> {
prepare_impl!(self, transitions, query, current_state_root, get_state_path_for_commitment)
}
#[cfg(feature = "async")]
pub async fn prepare_async(
&self,
transitions: &[Transition<N>],
query: impl QueryTrait<N>,
) -> Result<(Vec<InclusionAssignment<N>>, N::StateRoot)> {
prepare_impl!(self, transitions, query, current_state_root_async, get_state_path_for_commitment_async, await)
}
}