use super::*;
pub(super) const TRANSACTION_DEPTH: u8 = 4;
type TransactionTree<N> = BHPMerkleTree<N, TRANSACTION_DEPTH>;
pub type TransactionPath<N> = MerklePath<N, TRANSACTION_DEPTH>;
impl<N: Network> Transaction<N> {
pub fn to_root(&self) -> Result<Field<N>> {
Ok(*self.to_tree()?.root())
}
pub fn to_leaf(&self, id: &Field<N>) -> Result<TransactionLeaf<N>> {
match self {
Self::Deploy(_, deployment, additional_fee) => {
if *id == **additional_fee.id() {
return Ok(TransactionLeaf::new(
0u8,
deployment.program().functions().len() as u16, *additional_fee.program_id(),
*additional_fee.function_name(),
*id,
));
}
for (index, function) in deployment.program().functions().values().enumerate() {
if *id == N::hash_bhp1024(&function.to_bytes_le()?.to_bits_le())? {
return Ok(TransactionLeaf::new(
0u8,
index as u16,
*deployment.program().id(),
*function.name(),
*id,
));
}
}
bail!("Function ID not found in deployment transaction");
}
Self::Execute(_, execution, additional_fee) => {
if let Some(additional_fee) = additional_fee {
if *id == **additional_fee.id() {
return Ok(TransactionLeaf::new(
1u8,
execution.len() as u16, *additional_fee.program_id(),
*additional_fee.function_name(),
*id,
));
}
}
for (index, transition) in execution.iter().enumerate() {
if *id == **transition.id() {
return Ok(TransactionLeaf::new(
1u8,
index as u16,
*transition.program_id(),
*transition.function_name(),
*id,
));
}
}
bail!("Transition ID not found in execution transaction");
}
}
}
pub fn to_path(&self, leaf: &TransactionLeaf<N>) -> Result<TransactionPath<N>> {
self.to_tree()?.prove(leaf.index() as usize, &leaf.to_bits_le())
}
pub fn to_tree(&self) -> Result<TransactionTree<N>> {
match self {
Transaction::Deploy(_, deployment, additional_fee) => Self::deployment_tree(deployment, additional_fee),
Transaction::Execute(_, execution, additional_fee) => Self::execution_tree(execution, additional_fee),
}
}
}
impl<N: Network> Transaction<N> {
pub(super) fn deployment_tree(
deployment: &Deployment<N>,
additional_fee: &AdditionalFee<N>,
) -> Result<TransactionTree<N>> {
Self::check_deployment_size(deployment)?;
let variant = 0u8;
let program = deployment.program();
let leaves = program
.functions()
.values()
.enumerate()
.map(|(index, function)| {
Ok(TransactionLeaf::new(
variant,
index as u16,
*program.id(),
*function.name(),
N::hash_bhp1024(&function.to_bytes_le()?.to_bits_le())?,
)
.to_bits_le())
})
.chain(
[Ok(TransactionLeaf::new(
variant,
program.functions().len() as u16, *additional_fee.program_id(),
*additional_fee.function_name(),
**additional_fee.id(),
)
.to_bits_le())]
.into_iter(),
);
N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&leaves.collect::<Result<Vec<_>>>()?)
}
pub(super) fn execution_tree(
execution: &Execution<N>,
additional_fee: &Option<AdditionalFee<N>>,
) -> Result<TransactionTree<N>> {
Self::check_execution_size(execution)?;
let variant = 1u8;
let leaves = execution.iter().enumerate().map(|(index, transition)| {
TransactionLeaf::new(
variant,
index as u16,
*transition.program_id(),
*transition.function_name(),
**transition.id(),
)
.to_bits_le()
});
let leaves = match additional_fee {
Some(additional_fee) => {
let leaf = TransactionLeaf::new(
variant,
execution.len() as u16, *additional_fee.program_id(),
*additional_fee.function_name(),
**additional_fee.id(),
)
.to_bits_le();
leaves.chain([leaf].into_iter()).collect::<Vec<_>>()
}
None => leaves.collect::<Vec<_>>(),
};
N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&leaves)
}
pub fn check_deployment_size(deployment: &Deployment<N>) -> Result<()> {
let program = deployment.program();
let functions = program.functions();
let verifying_keys = deployment.verifying_keys();
ensure!(
functions.len() == verifying_keys.len(),
"Number of functions ('{}') and verifying keys ('{}') do not match",
functions.len(),
verifying_keys.len()
);
ensure!(
functions.len() < Self::MAX_TRANSITIONS, "Deployment must contain less than {} functions, found {}",
Self::MAX_TRANSITIONS,
functions.len()
);
Ok(())
}
pub fn check_execution_size(execution: &Execution<N>) -> Result<()> {
ensure!(
execution.len() < Self::MAX_TRANSITIONS, "Execution must contain less than {} transitions, found {}",
Self::MAX_TRANSITIONS,
execution.len()
);
Ok(())
}
}