snarkvm_ledger_block/transaction/execution/
mod.rs1mod bytes;
17mod serialize;
18mod string;
19
20use crate::{Transaction, Transition};
21use console::{account::Field, network::prelude::*, program::ProgramID};
22use synthesizer_snark::Proof;
23
24use indexmap::IndexMap;
25
26#[derive(Clone, Default, PartialEq, Eq)]
27pub struct Execution<N: Network> {
28 transitions: IndexMap<N::TransitionID, Transition<N>>,
30 global_state_root: N::StateRoot,
32 proof: Option<Proof<N>>,
34}
35
36impl<N: Network> Execution<N> {
37 pub fn new() -> Self {
39 Self { transitions: Default::default(), global_state_root: Default::default(), proof: None }
40 }
41
42 pub fn from(
44 transitions: impl Iterator<Item = Transition<N>>,
45 global_state_root: N::StateRoot,
46 proof: Option<Proof<N>>,
47 ) -> Result<Self> {
48 let execution = Self { transitions: transitions.map(|t| (*t.id(), t)).collect(), global_state_root, proof };
50 ensure!(!execution.transitions.is_empty(), "Execution cannot initialize from empty list of transitions");
52 Ok(execution)
54 }
55
56 pub fn size_in_bytes(&self) -> Result<u64> {
58 Ok(u64::try_from(self.to_bytes_le()?.len())?)
59 }
60
61 pub const fn global_state_root(&self) -> N::StateRoot {
63 self.global_state_root
64 }
65
66 pub const fn proof(&self) -> Option<&Proof<N>> {
68 self.proof.as_ref()
69 }
70
71 pub fn to_execution_id(&self) -> Result<Field<N>> {
73 Ok(*Transaction::execution_tree(self)?.root())
74 }
75}
76
77impl<N: Network> Execution<N> {
78 pub fn contains_transition(&self, transition_id: &N::TransitionID) -> bool {
80 self.transitions.contains_key(transition_id)
81 }
82
83 pub fn get_transition(&self, transition_id: &N::TransitionID) -> Option<&Transition<N>> {
85 self.transitions.get(transition_id)
86 }
87
88 pub fn get_program_id(&self, transition_id: &N::TransitionID) -> Option<&ProgramID<N>> {
90 self.transitions.get(transition_id).map(|t| t.program_id())
91 }
92
93 pub fn get(&self, index: usize) -> Result<&Transition<N>> {
95 match self.transitions.get_index(index) {
96 Some((_, transition)) => Ok(transition),
97 None => bail!("Transition index {index} out of bounds in the execution object"),
98 }
99 }
100
101 pub fn peek(&self) -> Result<&Transition<N>> {
103 self.get(self.len() - 1)
104 }
105
106 pub fn push(&mut self, transition: Transition<N>) {
108 self.transitions.insert(*transition.id(), transition);
109 }
110
111 pub fn pop(&mut self) -> Result<Transition<N>> {
113 match self.transitions.pop() {
114 Some((_, transition)) => Ok(transition),
115 None => bail!("Cannot pop a transition from an empty execution object"),
116 }
117 }
118
119 pub fn len(&self) -> usize {
121 self.transitions.len()
122 }
123
124 pub fn is_empty(&self) -> bool {
126 self.transitions.is_empty()
127 }
128}
129
130impl<N: Network> Execution<N> {
131 pub fn into_transitions(self) -> impl ExactSizeIterator + DoubleEndedIterator<Item = Transition<N>> {
133 self.transitions.into_values()
134 }
135
136 pub fn transitions(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &Transition<N>> {
138 self.transitions.values()
139 }
140
141 pub fn commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
143 self.transitions.values().flat_map(Transition::commitments)
144 }
145}
146
147#[cfg(test)]
148pub mod test_helpers {
149 use super::*;
150
151 type CurrentNetwork = console::network::MainnetV0;
152
153 pub(crate) fn sample_execution(rng: &mut TestRng) -> Execution<CurrentNetwork> {
155 let block = crate::test_helpers::sample_genesis_block(rng);
157 let transaction = block.transactions().iter().next().unwrap().deref().clone();
159 if let Transaction::Execute(_, _, execution, _) = transaction { *execution } else { unreachable!() }
161 }
162}