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<T: IntoExecutable + Clone> IntoExecutable for &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().into());
108 }
109 for resource in &auth_zone_init.simulate_every_proof_under_resources {
110 references.insert((*resource).into());
111 }
112
113 for preallocated_address in &context.pre_allocated_addresses {
114 references.insert(preallocated_address.blueprint_id.package_address.into());
115 }
116
117 Self {
118 context,
119 transaction_intent: ExecutableIntent {
120 encoded_instructions: encoded_instructions_v1,
121 references,
122 blobs,
123 auth_zone_init,
124 children_subintent_indices: vec![],
125 },
126 subintents: vec![],
127 }
128 }
129
130 pub fn new_v2(
131 mut transaction_intent: ExecutableIntent,
132 mut subintents: Vec<ExecutableIntent>,
133 context: ExecutionContext,
134 ) -> Self {
135 {
136 let intent = &mut transaction_intent;
137 for proof in &intent.auth_zone_init.initial_non_fungible_id_proofs {
138 intent.references.insert(proof.resource_address().into());
139 }
140 for resource in &intent.auth_zone_init.simulate_every_proof_under_resources {
141 intent.references.insert((*resource).into());
142 }
143 }
144 for intent in &mut subintents {
145 for proof in &intent.auth_zone_init.initial_non_fungible_id_proofs {
146 intent.references.insert(proof.resource_address().into());
147 }
148 for resource in &intent.auth_zone_init.simulate_every_proof_under_resources {
149 intent.references.insert((*resource).into());
150 }
151 }
152
153 for preallocated_address in &context.pre_allocated_addresses {
157 transaction_intent
158 .references
159 .insert(preallocated_address.blueprint_id.package_address.into());
160 }
161
162 Self {
163 context,
164 transaction_intent,
165 subintents,
166 }
167 }
168
169 pub fn skip_epoch_range_check(mut self) -> Self {
172 self.context.epoch_range = None;
173 self
174 }
175
176 pub fn skip_intent_hash_nullification(mut self) -> Self {
177 self.context.intent_hash_nullifications.clear();
178 self
179 }
180
181 pub fn apply_free_credit(mut self, free_credit_in_xrd: Decimal) -> Self {
182 self.context.costing_parameters.free_credit_in_xrd = free_credit_in_xrd;
183 self
184 }
185
186 pub fn unique_hash(&self) -> &Hash {
187 &self.context.unique_hash
188 }
189
190 pub fn overall_epoch_range(&self) -> Option<&EpochRange> {
191 self.context.epoch_range.as_ref()
192 }
193
194 pub fn overall_proposer_timestamp_range(&self) -> Option<&ProposerTimestampRange> {
195 self.context.proposer_timestamp_range.as_ref()
196 }
197
198 pub fn costing_parameters(&self) -> &TransactionCostingParameters {
199 &self.context.costing_parameters
200 }
201
202 pub fn pre_allocated_addresses(&self) -> &[PreAllocatedAddress] {
203 &self.context.pre_allocated_addresses
204 }
205
206 pub fn payload_size(&self) -> usize {
207 self.context.payload_size
208 }
209
210 pub fn num_of_signature_validations(&self) -> usize {
211 self.context.num_of_signature_validations
212 }
213
214 pub fn disable_limits_and_costing_modules(&self) -> bool {
215 self.context.disable_limits_and_costing_modules
216 }
217
218 pub fn transaction_intent(&self) -> &ExecutableIntent {
219 &self.transaction_intent
220 }
221
222 pub fn subintents(&self) -> &[ExecutableIntent] {
223 &self.subintents
224 }
225
226 pub fn all_intents(&self) -> impl Iterator<Item = &ExecutableIntent> {
227 iter::once(&self.transaction_intent).chain(self.subintents.iter())
228 }
229
230 pub fn intent_hash_nullifications(&self) -> &[IntentHashNullification] {
231 &self.context.intent_hash_nullifications
232 }
233
234 pub fn all_blob_hashes(&self) -> IndexSet<Hash> {
235 let mut hashes = indexset!();
236
237 for intent in self.all_intents() {
238 for hash in intent.blobs.keys() {
239 hashes.insert(*hash);
240 }
241 }
242
243 hashes
244 }
245
246 pub fn all_references(&self) -> IndexSet<Reference> {
247 let mut references = indexset!();
248
249 for intent in self.all_intents() {
250 for reference in intent.references.iter() {
251 references.insert(*reference);
252 }
253 }
254
255 references
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::ExecutableTransaction;
262
263 fn assert_send<T: Send>() {}
264 fn assert_sync<T: Sync>() {}
265
266 #[test]
267 fn check_executable_transaction_can_be_cached_in_the_node_mempool_and_be_shared_between_threads(
268 ) {
269 assert_send::<ExecutableTransaction>();
270 assert_sync::<ExecutableTransaction>();
271 }
272}