radix_transactions/model/execution/
executable_transaction.rs1use std::iter;
2
3use crate::internal_prelude::*;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct ExecutableIntent {
7 pub encoded_instructions: Vec<u8>,
8 pub auth_zone_init: AuthZoneInit,
9 pub references: IndexSet<Reference>,
10 pub blobs: IndexMap<Hash, Vec<u8>>,
11 pub children_subintent_indices: Vec<SubintentIndex>,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, ManifestSbor)]
18#[sbor(transparent)]
19pub struct SubintentIndex(pub usize);
20
21pub trait IntoExecutable {
22 type Error: Debug;
23
24 fn into_executable(
25 self,
26 validator: &TransactionValidator,
27 ) -> Result<ExecutableTransaction, Self::Error>;
28
29 fn into_executable_unwrap(self) -> ExecutableTransaction
32 where
33 Self: Sized,
34 {
35 self.into_executable(
36 &TransactionValidator::new_with_static_config_network_agnostic(
37 TransactionValidationConfig::latest(),
38 ),
39 )
40 .unwrap()
41 }
42}
43
44impl<'a, T: IntoExecutable + Clone> IntoExecutable for &'a T {
45 type Error = T::Error;
46
47 fn into_executable(
48 self,
49 validator: &TransactionValidator,
50 ) -> Result<ExecutableTransaction, Self::Error> {
51 self.clone().into_executable(validator)
52 }
53}
54
55impl IntoExecutable for ExecutableTransaction {
56 type Error = core::convert::Infallible;
57
58 fn into_executable(
59 self,
60 _validator: &TransactionValidator,
61 ) -> Result<ExecutableTransaction, Self::Error> {
62 Ok(self)
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct ExecutableTransaction {
71 pub(crate) transaction_intent: ExecutableIntent,
72 pub(crate) subintents: Vec<ExecutableIntent>,
73 pub(crate) context: ExecutionContext,
74}
75
76impl AsRef<ExecutableTransaction> for ExecutableTransaction {
77 fn as_ref(&self) -> &ExecutableTransaction {
78 self
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct ExecutionContext {
84 pub unique_hash: Hash,
86 pub pre_allocated_addresses: Vec<PreAllocatedAddress>,
87 pub payload_size: usize,
88 pub num_of_signature_validations: usize,
89 pub costing_parameters: TransactionCostingParameters,
90 pub epoch_range: Option<EpochRange>,
91 pub proposer_timestamp_range: Option<ProposerTimestampRange>,
92 pub disable_limits_and_costing_modules: bool,
93 pub intent_hash_nullifications: Vec<IntentHashNullification>,
94}
95
96impl ExecutableTransaction {
97 pub fn new_v1(
98 encoded_instructions_v1: Vec<u8>,
99 auth_zone_init: AuthZoneInit,
100 references: IndexSet<Reference>,
101 blobs: IndexMap<Hash, Vec<u8>>,
102 context: ExecutionContext,
103 ) -> Self {
104 let mut references = references;
105
106 for proof in &auth_zone_init.initial_non_fungible_id_proofs {
107 references.insert(proof.resource_address().clone().into());
108 }
109 for resource in &auth_zone_init.simulate_every_proof_under_resources {
110 references.insert(resource.clone().into());
111 }
112
113 for preallocated_address in &context.pre_allocated_addresses {
114 references.insert(
115 preallocated_address
116 .blueprint_id
117 .package_address
118 .clone()
119 .into(),
120 );
121 }
122
123 Self {
124 context,
125 transaction_intent: ExecutableIntent {
126 encoded_instructions: encoded_instructions_v1,
127 references,
128 blobs,
129 auth_zone_init,
130 children_subintent_indices: vec![],
131 },
132 subintents: vec![],
133 }
134 }
135
136 pub fn new_v2(
137 mut transaction_intent: ExecutableIntent,
138 mut subintents: Vec<ExecutableIntent>,
139 context: ExecutionContext,
140 ) -> Self {
141 {
142 let intent = &mut transaction_intent;
143 for proof in &intent.auth_zone_init.initial_non_fungible_id_proofs {
144 intent
145 .references
146 .insert(proof.resource_address().clone().into());
147 }
148 for resource in &intent.auth_zone_init.simulate_every_proof_under_resources {
149 intent.references.insert(resource.clone().into());
150 }
151 }
152 for intent in &mut subintents {
153 for proof in &intent.auth_zone_init.initial_non_fungible_id_proofs {
154 intent
155 .references
156 .insert(proof.resource_address().clone().into());
157 }
158 for resource in &intent.auth_zone_init.simulate_every_proof_under_resources {
159 intent.references.insert(resource.clone().into());
160 }
161 }
162
163 for preallocated_address in &context.pre_allocated_addresses {
167 transaction_intent.references.insert(
168 preallocated_address
169 .blueprint_id
170 .package_address
171 .clone()
172 .into(),
173 );
174 }
175
176 Self {
177 context,
178 transaction_intent,
179 subintents,
180 }
181 }
182
183 pub fn skip_epoch_range_check(mut self) -> Self {
186 self.context.epoch_range = None;
187 self
188 }
189
190 pub fn skip_intent_hash_nullification(mut self) -> Self {
191 self.context.intent_hash_nullifications.clear();
192 self
193 }
194
195 pub fn apply_free_credit(mut self, free_credit_in_xrd: Decimal) -> Self {
196 self.context.costing_parameters.free_credit_in_xrd = free_credit_in_xrd;
197 self
198 }
199
200 pub fn unique_hash(&self) -> &Hash {
201 &self.context.unique_hash
202 }
203
204 pub fn overall_epoch_range(&self) -> Option<&EpochRange> {
205 self.context.epoch_range.as_ref()
206 }
207
208 pub fn overall_proposer_timestamp_range(&self) -> Option<&ProposerTimestampRange> {
209 self.context.proposer_timestamp_range.as_ref()
210 }
211
212 pub fn costing_parameters(&self) -> &TransactionCostingParameters {
213 &self.context.costing_parameters
214 }
215
216 pub fn pre_allocated_addresses(&self) -> &[PreAllocatedAddress] {
217 &self.context.pre_allocated_addresses
218 }
219
220 pub fn payload_size(&self) -> usize {
221 self.context.payload_size
222 }
223
224 pub fn num_of_signature_validations(&self) -> usize {
225 self.context.num_of_signature_validations
226 }
227
228 pub fn disable_limits_and_costing_modules(&self) -> bool {
229 self.context.disable_limits_and_costing_modules
230 }
231
232 pub fn transaction_intent(&self) -> &ExecutableIntent {
233 &self.transaction_intent
234 }
235
236 pub fn subintents(&self) -> &[ExecutableIntent] {
237 &self.subintents
238 }
239
240 pub fn all_intents(&self) -> impl Iterator<Item = &ExecutableIntent> {
241 iter::once(&self.transaction_intent).chain(self.subintents.iter())
242 }
243
244 pub fn intent_hash_nullifications(&self) -> &[IntentHashNullification] {
245 &self.context.intent_hash_nullifications
246 }
247
248 pub fn all_blob_hashes(&self) -> IndexSet<Hash> {
249 let mut hashes = indexset!();
250
251 for intent in self.all_intents() {
252 for hash in intent.blobs.keys() {
253 hashes.insert(*hash);
254 }
255 }
256
257 hashes
258 }
259
260 pub fn all_references(&self) -> IndexSet<Reference> {
261 let mut references = indexset!();
262
263 for intent in self.all_intents() {
264 for reference in intent.references.iter() {
265 references.insert(reference.clone());
266 }
267 }
268
269 references
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::ExecutableTransaction;
276
277 fn assert_send<T: Send>() {}
278 fn assert_sync<T: Sync>() {}
279
280 #[test]
281 fn check_executable_transaction_can_be_cached_in_the_node_mempool_and_be_shared_between_threads(
282 ) {
283 assert_send::<ExecutableTransaction>();
284 assert_sync::<ExecutableTransaction>();
285 }
286}