use super::*;
const TRANSITION_DEPTH: u8 = 4;
type TransitionTree<N> = BHPMerkleTree<N, TRANSITION_DEPTH>;
pub type TransitionPath<N> = MerklePath<N, TRANSITION_DEPTH>;
impl<N: Network> Transition<N> {
pub fn to_root(&self) -> Result<Field<N>> {
Ok(*self.to_tree()?.root())
}
pub fn to_path(&self, leaf: &TransitionLeaf<N>) -> Result<TransitionPath<N>> {
self.to_tree()?.prove(leaf.index() as usize, &leaf.to_bits_le())
}
pub fn to_leaf(&self, id: &Field<N>, is_input: bool) -> Result<TransitionLeaf<N>> {
let version = 0u8;
match is_input {
true => {
for (index, input) in self.inputs.iter().enumerate() {
if id == input.id() {
return Ok(TransitionLeaf::new(
version,
index as u8,
self.program_id,
self.function_name,
input.variant(),
*id,
));
}
}
bail!("Input ID not found in transition")
}
false => {
for (index, output) in self.outputs.iter().enumerate() {
if id == output.id() {
let output_index = (self.inputs.len() + index) as u8;
return Ok(TransitionLeaf::new(
version,
output_index,
self.program_id,
self.function_name,
output.variant(),
*id,
));
}
}
bail!("Output ID not found in transition")
}
}
}
pub fn to_tree(&self) -> Result<TransitionTree<N>> {
Self::function_tree(&self.program_id, &self.function_name, &self.inputs, &self.outputs)
}
pub(super) fn function_tree(
program_id: &ProgramID<N>,
function_name: &Identifier<N>,
inputs: &[Input<N>],
outputs: &[Output<N>],
) -> Result<TransitionTree<N>> {
ensure!(
inputs.len() <= N::MAX_INPUTS,
"Transition cannot exceed {} inputs, found {} inputs",
N::MAX_INPUTS,
inputs.len()
);
ensure!(
outputs.len() <= N::MAX_OUTPUTS,
"Transition cannot exceed {} outputs, found {} outputs",
N::MAX_OUTPUTS,
outputs.len()
);
let version = 0u8;
let input_leaves = inputs.iter().enumerate().map(|(index, input)| {
TransitionLeaf::new(version, index as u8, *program_id, *function_name, input.variant(), *input.id())
.to_bits_le()
});
let output_leaves = outputs.iter().enumerate().map(|(index, output)| {
TransitionLeaf::new(
version,
(inputs.len() + index) as u8,
*program_id,
*function_name,
output.variant(),
*output.id(),
)
.to_bits_le()
});
N::merkle_tree_bhp::<TRANSITION_DEPTH>(&input_leaves.chain(output_leaves).collect::<Vec<_>>())
}
}
#[cfg(test)]
mod tests {
use super::*;
use console::network::Testnet3;
type CurrentNetwork = Testnet3;
#[test]
fn test_transition_depth() {
assert_eq!(2usize.pow(TRANSITION_DEPTH as u32), CurrentNetwork::MAX_INPUTS + CurrentNetwork::MAX_OUTPUTS);
}
}