mod leaf;
pub use leaf::*;
mod merkle;
pub use merkle::*;
mod bytes;
mod serialize;
mod string;
use crate::{
ledger::{vm::VM, Origin, Transition},
process::{Authorization, Deployment, Execution},
program::Program,
ProgramStorage,
};
use console::{
account::PrivateKey,
collections::merkle_tree::MerklePath,
network::{prelude::*, BHPMerkleTree},
program::{Identifier, Plaintext, ProgramID, Record, Value},
types::{Field, Group},
};
pub type AdditionalFee<N> = Transition<N>;
#[derive(Clone, PartialEq, Eq)]
pub enum Transaction<N: Network> {
Deploy(N::TransactionID, Deployment<N>, AdditionalFee<N>),
Execute(N::TransactionID, Execution<N>, Option<AdditionalFee<N>>),
}
impl<N: Network> Transaction<N> {
pub fn from_deployment(deployment: Deployment<N>, additional_fee: AdditionalFee<N>) -> Result<Self> {
ensure!(!deployment.program().functions().is_empty(), "Attempted to create an empty transaction deployment");
let id = *Self::deployment_tree(&deployment, &additional_fee)?.root();
Ok(Self::Deploy(id.into(), deployment, additional_fee))
}
pub fn from_execution(execution: Execution<N>, additional_fee: Option<AdditionalFee<N>>) -> Result<Self> {
ensure!(!execution.is_empty(), "Attempted to create an empty transaction execution");
let id = *Self::execution_tree(&execution, &additional_fee)?.root();
Ok(Self::Execute(id.into(), execution, additional_fee))
}
}
impl<N: Network> Transaction<N> {
const MAX_TRANSITIONS: usize = usize::pow(2, TRANSACTION_DEPTH as u32);
pub fn deploy<P: ProgramStorage<N>, R: Rng + CryptoRng>(
vm: &VM<N, P>,
private_key: &PrivateKey<N>,
program: &Program<N>,
(credits, additional_fee_in_gates): (Record<N, Plaintext<N>>, u64),
rng: &mut R,
) -> Result<Self> {
let deployment = vm.deploy(program, rng)?;
let (_, additional_fee) = vm.execute_additional_fee(private_key, credits, additional_fee_in_gates, rng)?;
Self::from_deployment(deployment, additional_fee)
}
pub fn execute_authorization<P: ProgramStorage<N>, R: Rng + CryptoRng>(
vm: &VM<N, P>,
authorization: Authorization<N>,
rng: &mut R,
) -> Result<Self> {
let (_, execution) = vm.execute(authorization, rng)?;
Self::from_execution(execution, None)
}
pub fn execute_authorization_with_additional_fee<P: ProgramStorage<N>, R: Rng + CryptoRng>(
vm: &VM<N, P>,
private_key: &PrivateKey<N>,
authorization: Authorization<N>,
additional_fee: Option<(Record<N, Plaintext<N>>, u64)>,
rng: &mut R,
) -> Result<Self> {
let (_, execution) = vm.execute(authorization, rng)?;
let additional_fee = match additional_fee {
Some((credits, additional_fee_in_gates)) => {
Some(vm.execute_additional_fee(private_key, credits, additional_fee_in_gates, rng)?.1)
}
None => None,
};
Self::from_execution(execution, additional_fee)
}
pub fn execute<P: ProgramStorage<N>, R: Rng + CryptoRng>(
vm: &VM<N, P>,
private_key: &PrivateKey<N>,
program_id: &ProgramID<N>,
function_name: Identifier<N>,
inputs: &[Value<N>],
additional_fee: Option<(Record<N, Plaintext<N>>, u64)>,
rng: &mut R,
) -> Result<Self> {
let authorization = vm.authorize(private_key, program_id, function_name, inputs, rng)?;
Self::execute_authorization_with_additional_fee(vm, private_key, authorization, additional_fee, rng)
}
}
impl<N: Network> Transaction<N> {
pub const fn id(&self) -> N::TransactionID {
match self {
Self::Deploy(id, ..) => *id,
Self::Execute(id, ..) => *id,
}
}
pub fn transitions(&self) -> impl '_ + Iterator<Item = &Transition<N>> {
match self {
Self::Deploy(_, _, additional_fee) => [].iter().chain([Some(additional_fee)].into_iter().flatten()),
Self::Execute(_, execution, additional_fee) => {
execution.iter().chain([additional_fee.as_ref()].into_iter().flatten())
}
}
}
pub fn transition_ids(&self) -> impl '_ + Iterator<Item = &N::TransitionID> {
self.transitions().map(Transition::id)
}
pub fn input_ids(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions().flat_map(Transition::input_ids)
}
pub fn serial_numbers(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions().flat_map(Transition::serial_numbers)
}
pub fn tags(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions().flat_map(Transition::tags)
}
pub fn origins(&self) -> impl '_ + Iterator<Item = &Origin<N>> {
self.transitions().flat_map(Transition::origins)
}
pub fn output_ids(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions().flat_map(Transition::output_ids)
}
pub fn commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions().flat_map(Transition::commitments)
}
pub fn nonces(&self) -> impl '_ + Iterator<Item = &Group<N>> {
self.transitions().flat_map(Transition::nonces)
}
pub fn transition_public_keys(&self) -> impl '_ + Iterator<Item = &Group<N>> {
self.transitions().map(Transition::tpk)
}
pub fn transition_commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions().map(Transition::tcm)
}
pub fn fees(&self) -> impl '_ + Iterator<Item = &i64> {
self.transitions().map(Transition::fee)
}
}
impl<N: Network> Transaction<N> {
pub fn into_transitions(self) -> impl Iterator<Item = Transition<N>> {
enum IterWrap<T, I1: Iterator<Item = T>, I2: Iterator<Item = T>> {
Deploy(I1),
Execute(I2),
}
impl<T, I1: Iterator<Item = T>, I2: Iterator<Item = T>> Iterator for IterWrap<T, I1, I2> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Deploy(iter) => iter.next(),
Self::Execute(iter) => iter.next(),
}
}
}
match self {
Self::Deploy(_, _, additional_fee) => IterWrap::Deploy(Some(additional_fee).into_iter()),
Self::Execute(_, execution, additional_fee) => {
IterWrap::Execute(execution.into_transitions().chain(additional_fee))
}
}
}
pub fn into_transition_ids(self) -> impl Iterator<Item = N::TransitionID> {
self.into_transitions().map(Transition::into_id)
}
pub fn into_transition_public_keys(self) -> impl Iterator<Item = Group<N>> {
self.into_transitions().map(Transition::into_tpk)
}
pub fn into_origins(self) -> impl Iterator<Item = Origin<N>> {
self.into_transitions().flat_map(Transition::into_origins)
}
pub fn into_tags(self) -> impl Iterator<Item = Field<N>> {
self.into_transitions().flat_map(Transition::into_tags)
}
pub fn into_serial_numbers(self) -> impl Iterator<Item = Field<N>> {
self.into_transitions().flat_map(Transition::into_serial_numbers)
}
pub fn into_commitments(self) -> impl Iterator<Item = Field<N>> {
self.into_transitions().flat_map(Transition::into_commitments)
}
pub fn into_nonces(self) -> impl Iterator<Item = Group<N>> {
self.into_transitions().flat_map(Transition::into_nonces)
}
}