snarkvm_ledger_block/transaction/execution/
mod.rsmod bytes;
mod serialize;
mod string;
use crate::{Transaction, Transition};
use console::{account::Field, network::prelude::*, program::ProgramID};
use synthesizer_snark::Proof;
use indexmap::IndexMap;
#[derive(Clone, Default, PartialEq, Eq)]
pub struct Execution<N: Network> {
transitions: IndexMap<N::TransitionID, Transition<N>>,
global_state_root: N::StateRoot,
proof: Option<Proof<N>>,
}
impl<N: Network> Execution<N> {
pub fn new() -> Self {
Self { transitions: Default::default(), global_state_root: Default::default(), proof: None }
}
pub fn from(
transitions: impl Iterator<Item = Transition<N>>,
global_state_root: N::StateRoot,
proof: Option<Proof<N>>,
) -> Result<Self> {
let execution = Self { transitions: transitions.map(|t| (*t.id(), t)).collect(), global_state_root, proof };
ensure!(!execution.transitions.is_empty(), "Execution cannot initialize from empty list of transitions");
Ok(execution)
}
pub fn size_in_bytes(&self) -> Result<u64> {
Ok(u64::try_from(self.to_bytes_le()?.len())?)
}
pub const fn global_state_root(&self) -> N::StateRoot {
self.global_state_root
}
pub const fn proof(&self) -> Option<&Proof<N>> {
self.proof.as_ref()
}
pub fn to_execution_id(&self) -> Result<Field<N>> {
Ok(*Transaction::execution_tree(self, &None)?.root())
}
}
impl<N: Network> Execution<N> {
pub fn contains_transition(&self, transition_id: &N::TransitionID) -> bool {
self.transitions.contains_key(transition_id)
}
pub fn get_transition(&self, transition_id: &N::TransitionID) -> Option<&Transition<N>> {
self.transitions.get(transition_id)
}
pub fn get_program_id(&self, transition_id: &N::TransitionID) -> Option<&ProgramID<N>> {
self.transitions.get(transition_id).map(|t| t.program_id())
}
pub fn get(&self, index: usize) -> Result<&Transition<N>> {
match self.transitions.get_index(index) {
Some((_, transition)) => Ok(transition),
None => bail!("Transition index {index} out of bounds in the execution object"),
}
}
pub fn peek(&self) -> Result<&Transition<N>> {
self.get(self.len() - 1)
}
pub fn push(&mut self, transition: Transition<N>) {
self.transitions.insert(*transition.id(), transition);
}
pub fn pop(&mut self) -> Result<Transition<N>> {
match self.transitions.pop() {
Some((_, transition)) => Ok(transition),
None => bail!("Cannot pop a transition from an empty execution object"),
}
}
pub fn len(&self) -> usize {
self.transitions.len()
}
pub fn is_empty(&self) -> bool {
self.transitions.is_empty()
}
}
impl<N: Network> Execution<N> {
pub fn into_transitions(self) -> impl ExactSizeIterator + DoubleEndedIterator<Item = Transition<N>> {
self.transitions.into_values()
}
pub fn transitions(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &Transition<N>> {
self.transitions.values()
}
pub fn commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.transitions.values().flat_map(Transition::commitments)
}
}
#[cfg(test)]
pub mod test_helpers {
use super::*;
type CurrentNetwork = console::network::MainnetV0;
pub(crate) fn sample_execution(rng: &mut TestRng) -> Execution<CurrentNetwork> {
let block = crate::test_helpers::sample_genesis_block(rng);
let transaction = block.transactions().iter().next().unwrap().deref().clone();
if let Transaction::Execute(_, execution, _) = transaction { execution } else { unreachable!() }
}
}