radix_engine/transaction/
transaction_executor.rs

1use crate::errors::*;
2use crate::internal_prelude::*;
3use crate::kernel::kernel::KernelInit;
4use crate::system::system_callback::*;
5use crate::transaction::*;
6use crate::vm::*;
7use radix_common::constants::*;
8use radix_engine_interface::blueprints::transaction_processor::InstructionOutput;
9use radix_substate_store_interface::interface::*;
10use radix_transactions::model::*;
11
12/// Protocol-defined costing parameters
13#[derive(Debug, Copy, Clone, ScryptoSbor, PartialEq, Eq)]
14pub struct CostingParameters {
15    /// The price of execution cost unit in XRD.
16    pub execution_cost_unit_price: Decimal,
17    /// The max number execution cost units to consume.
18    pub execution_cost_unit_limit: u32,
19    /// The number of execution cost units loaned from system.
20    pub execution_cost_unit_loan: u32,
21
22    /// The price of finalization cost unit in XRD.
23    pub finalization_cost_unit_price: Decimal,
24    /// The max number finalization cost units to consume.
25    pub finalization_cost_unit_limit: u32,
26
27    /// The price of USD in xrd
28    pub usd_price: Decimal,
29    /// The price of state storage in xrd
30    pub state_storage_price: Decimal,
31    /// The price of archive storage in xrd
32    pub archive_storage_price: Decimal,
33}
34
35impl CostingParameters {
36    pub fn latest() -> Self {
37        Self::babylon_genesis()
38    }
39
40    #[cfg(not(feature = "coverage"))]
41    pub fn babylon_genesis() -> Self {
42        Self {
43            execution_cost_unit_price: EXECUTION_COST_UNIT_PRICE_IN_XRD.try_into().unwrap(),
44            execution_cost_unit_limit: EXECUTION_COST_UNIT_LIMIT,
45            execution_cost_unit_loan: EXECUTION_COST_UNIT_LOAN,
46            finalization_cost_unit_price: FINALIZATION_COST_UNIT_PRICE_IN_XRD.try_into().unwrap(),
47            finalization_cost_unit_limit: FINALIZATION_COST_UNIT_LIMIT,
48            usd_price: USD_PRICE_IN_XRD.try_into().unwrap(),
49            state_storage_price: STATE_STORAGE_PRICE_IN_XRD.try_into().unwrap(),
50            archive_storage_price: ARCHIVE_STORAGE_PRICE_IN_XRD.try_into().unwrap(),
51        }
52    }
53    #[cfg(feature = "coverage")]
54    pub fn babylon_genesis() -> Self {
55        Self {
56            execution_cost_unit_price: Decimal::zero(),
57            execution_cost_unit_limit: u32::MAX,
58            execution_cost_unit_loan: u32::MAX,
59            finalization_cost_unit_price: Decimal::zero(),
60            finalization_cost_unit_limit: u32::MAX,
61            usd_price: USD_PRICE_IN_XRD.try_into().unwrap(),
62            state_storage_price: Decimal::zero(),
63            archive_storage_price: Decimal::zero(),
64        }
65    }
66
67    pub fn with_execution_cost_unit_loan(mut self, loan_units: u32) -> Self {
68        self.execution_cost_unit_loan = loan_units;
69        self
70    }
71
72    pub fn with_execution_cost_unit_limit(mut self, limit: u32) -> Self {
73        self.execution_cost_unit_limit = limit;
74        self
75    }
76
77    pub fn with_finalization_cost_unit_limit(mut self, limit: u32) -> Self {
78        self.finalization_cost_unit_limit = limit;
79        self
80    }
81}
82
83#[derive(Debug, Copy, Clone, ScryptoSbor, PartialEq, Eq)]
84pub struct LimitParameters {
85    pub max_call_depth: usize,
86    pub max_heap_substate_total_bytes: usize,
87    pub max_track_substate_total_bytes: usize,
88    pub max_substate_key_size: usize,
89    pub max_substate_value_size: usize,
90    pub max_invoke_input_size: usize,
91    pub max_event_size: usize,
92    pub max_log_size: usize,
93    pub max_panic_message_size: usize,
94    pub max_number_of_logs: usize,
95    pub max_number_of_events: usize,
96}
97
98impl LimitParameters {
99    pub fn babylon_genesis() -> Self {
100        Self {
101            max_call_depth: MAX_CALL_DEPTH,
102            max_heap_substate_total_bytes: MAX_HEAP_SUBSTATE_TOTAL_BYTES,
103            max_track_substate_total_bytes: MAX_TRACK_SUBSTATE_TOTAL_BYTES,
104            max_substate_key_size: MAX_SUBSTATE_KEY_SIZE,
105            max_substate_value_size: MAX_SUBSTATE_VALUE_SIZE,
106            max_invoke_input_size: MAX_INVOKE_PAYLOAD_SIZE,
107            max_event_size: MAX_EVENT_SIZE,
108            max_log_size: MAX_LOG_SIZE,
109            max_panic_message_size: MAX_PANIC_MESSAGE_SIZE,
110            max_number_of_logs: MAX_NUMBER_OF_LOGS,
111            max_number_of_events: MAX_NUMBER_OF_EVENTS,
112        }
113    }
114
115    pub fn for_genesis_transaction() -> Self {
116        Self {
117            max_heap_substate_total_bytes: 512 * 1024 * 1024,
118            max_track_substate_total_bytes: 512 * 1024 * 1024,
119            max_number_of_events: 1024 * 1024,
120            ..Self::babylon_genesis()
121        }
122    }
123}
124
125#[derive(Debug, Clone)]
126pub struct SystemOverrides {
127    pub disable_costing: bool,
128    pub disable_limits: bool,
129    pub disable_auth: bool,
130    /// Whether to abort the transaction run when the loan is repaid.
131    /// This is used when test-executing pending transactions.
132    pub abort_when_loan_repaid: bool,
133    /// This is required for pre-bottlenose testnets which need to override
134    /// the default Mainnet network definition
135    pub network_definition: Option<NetworkDefinition>,
136    pub costing_parameters: Option<CostingParameters>,
137    pub limit_parameters: Option<LimitParameters>,
138}
139
140impl SystemOverrides {
141    const fn internal_default(network_definition: Option<NetworkDefinition>) -> Self {
142        Self {
143            disable_costing: false,
144            disable_limits: false,
145            disable_auth: false,
146            abort_when_loan_repaid: false,
147            network_definition,
148            costing_parameters: None,
149            limit_parameters: None,
150        }
151    }
152
153    pub const fn default_with_no_network() -> Self {
154        Self::internal_default(None)
155    }
156
157    pub const fn with_network(network_definition: NetworkDefinition) -> Self {
158        Self::internal_default(Some(network_definition))
159    }
160
161    pub const fn set_costing_parameters(
162        mut self,
163        costing_parameters: Option<CostingParameters>,
164    ) -> Self {
165        self.costing_parameters = costing_parameters;
166        self
167    }
168
169    pub fn set_abort_when_loan_repaid(mut self) -> Self {
170        self.abort_when_loan_repaid = true;
171        self
172    }
173}
174
175impl Default for SystemOverrides {
176    fn default() -> Self {
177        Self::default_with_no_network()
178    }
179}
180
181#[derive(Debug, Clone)]
182pub struct ExecutionConfig {
183    // These parameters do not affect state execution but only affect side effects
184    pub enable_kernel_trace: bool,
185    pub enable_cost_breakdown: bool,
186    pub execution_trace: Option<usize>,
187    pub enable_debug_information: bool,
188
189    pub system_overrides: Option<SystemOverrides>,
190}
191
192impl ExecutionConfig {
193    /// Creates an `ExecutionConfig` using default configurations.
194    /// This is internal. Clients should use `for_xxx` constructors instead.
195    const fn default_with_no_network() -> Self {
196        Self {
197            enable_kernel_trace: false,
198            enable_cost_breakdown: false,
199            execution_trace: None,
200            system_overrides: None,
201            enable_debug_information: false,
202        }
203    }
204
205    /// Creates an `ExecutionConfig` using default configurations.
206    /// This is internal. Clients should use `for_xxx` constructors instead.
207    fn default_with_network(network_definition: NetworkDefinition) -> Self {
208        Self {
209            system_overrides: Some(SystemOverrides::with_network(network_definition)),
210            ..Self::default_with_no_network()
211        }
212    }
213
214    pub fn for_genesis_transaction(network_definition: NetworkDefinition) -> Self {
215        Self::for_auth_disabled_system_transaction(network_definition)
216    }
217
218    pub fn for_auth_disabled_system_transaction(network_definition: NetworkDefinition) -> Self {
219        Self {
220            system_overrides: Some(SystemOverrides {
221                disable_costing: true,
222                disable_limits: true,
223                disable_auth: true,
224                network_definition: Some(network_definition),
225                ..Default::default()
226            }),
227            ..Self::default_with_no_network()
228        }
229    }
230
231    pub fn for_system_transaction(network_definition: NetworkDefinition) -> Self {
232        Self {
233            system_overrides: Some(SystemOverrides {
234                disable_costing: true,
235                disable_limits: true,
236                network_definition: Some(network_definition),
237                ..Default::default()
238            }),
239            ..Self::default_with_no_network()
240        }
241    }
242
243    pub fn for_validator_transaction(network_definition: NetworkDefinition) -> Self {
244        Self {
245            ..Self::default_with_network(network_definition)
246        }
247    }
248
249    pub fn for_notarized_transaction(network_definition: NetworkDefinition) -> Self {
250        Self {
251            ..Self::default_with_network(network_definition)
252        }
253    }
254
255    pub fn for_notarized_transaction_rejection_check(
256        network_definition: NetworkDefinition,
257    ) -> Self {
258        Self::default_with_network(network_definition)
259            .update_system_overrides(|overrides| overrides.set_abort_when_loan_repaid())
260    }
261
262    pub fn update_system_overrides(
263        mut self,
264        update: impl FnOnce(SystemOverrides) -> SystemOverrides,
265    ) -> Self {
266        self.system_overrides = Some(update(self.system_overrides.unwrap_or_default()));
267        self
268    }
269
270    pub fn for_test_transaction() -> Self {
271        Self {
272            enable_cost_breakdown: true,
273            ..Self::default_with_network(NetworkDefinition::simulator())
274        }
275    }
276
277    pub fn for_debug_transaction() -> Self {
278        Self {
279            enable_debug_information: true,
280            ..Self::for_test_transaction()
281        }
282    }
283
284    pub fn for_preview(network_definition: NetworkDefinition) -> Self {
285        Self {
286            enable_cost_breakdown: true,
287            execution_trace: Some(MAX_EXECUTION_TRACE_DEPTH),
288            ..Self::default_with_network(network_definition)
289        }
290    }
291
292    pub fn for_preview_no_auth(network_definition: NetworkDefinition) -> Self {
293        Self {
294            enable_cost_breakdown: true,
295            execution_trace: Some(MAX_EXECUTION_TRACE_DEPTH),
296            system_overrides: Some(SystemOverrides {
297                disable_auth: true,
298                network_definition: Some(network_definition),
299                ..Default::default()
300            }),
301            ..Self::default_with_no_network()
302        }
303    }
304
305    pub fn with_kernel_trace(mut self, enabled: bool) -> Self {
306        self.enable_kernel_trace = enabled;
307        self
308    }
309
310    pub fn with_execution_trace(mut self, depth: Option<usize>) -> Self {
311        self.execution_trace = depth;
312        self
313    }
314
315    pub fn with_cost_breakdown(mut self, enabled: bool) -> Self {
316        self.enable_cost_breakdown = enabled;
317        self
318    }
319}
320
321pub fn execute_transaction<'v, V: VmInitialize>(
322    substate_db: &impl SubstateDatabase,
323    vm_modules: &'v V,
324    execution_config: &ExecutionConfig,
325    executable: impl AsRef<ExecutableTransaction>,
326) -> TransactionReceipt {
327    let vm_init = VmInit::load(substate_db, vm_modules);
328    let system_init = SystemInit::load(substate_db, execution_config.clone(), vm_init);
329    KernelInit::load(substate_db, system_init).execute(executable.as_ref())
330}
331
332pub fn execute_and_commit_transaction<'s, V: VmInitialize>(
333    substate_db: &mut (impl SubstateDatabase + CommittableSubstateDatabase),
334    vm_modules: &'s V,
335    execution_config: &ExecutionConfig,
336    executable: impl AsRef<ExecutableTransaction>,
337) -> TransactionReceipt {
338    let receipt = execute_transaction(substate_db, vm_modules, execution_config, executable);
339    if let TransactionResult::Commit(commit) = &receipt.result {
340        substate_db.commit(&commit.state_updates.create_database_updates());
341    }
342    receipt
343}
344
345pub enum TransactionResultType {
346    Commit(Result<Vec<InstructionOutput>, RuntimeError>),
347    Reject(RejectionReason),
348    Abort(AbortReason),
349}