1use crate::blueprints::access_controller::v1::*;
2use crate::blueprints::access_controller::v2::*;
3use crate::blueprints::account::AccountBlueprintCuttlefishExtension;
4use crate::blueprints::account::{AccountBlueprintBottlenoseExtension, AccountNativePackage};
5use crate::blueprints::consensus_manager::{
6 ConsensusManagerNativePackage, ConsensusManagerSecondsPrecisionNativeCode,
7};
8use crate::blueprints::identity::IdentityNativePackage;
9use crate::blueprints::identity::IdentityV1MinorVersion;
10use crate::blueprints::locker::LockerNativePackage;
11use crate::blueprints::package::PackageNativePackage;
12use crate::blueprints::pool::v1::package::*;
13use crate::blueprints::resource::{ResourceNativePackage, WorktopBlueprintCuttlefishExtension};
14use crate::blueprints::test_utils::TestUtilsNativePackage;
15use crate::blueprints::transaction_processor::{
16 TransactionProcessorNativePackage, TransactionProcessorV1MinorVersion,
17};
18use crate::blueprints::transaction_tracker::TransactionTrackerNativePackage;
19use crate::errors::{NativeRuntimeError, RuntimeError, VmError};
20use crate::internal_prelude::*;
21use crate::kernel::kernel_api::{KernelNodeApi, KernelSubstateApi};
22use crate::object_modules::metadata::MetadataNativePackage;
23use crate::object_modules::role_assignment::*;
24use crate::object_modules::royalty::RoyaltyNativePackage;
25use crate::system::system_callback::SystemBasedKernelInternalApi;
26use crate::system::system_callback::SystemLockData;
27use crate::vm::{VmApi, VmInvoke};
28use radix_engine_interface::api::SystemApi;
29use radix_engine_interface::blueprints::package::*;
30use radix_engine_profiling_derive::trace_resources;
31
32#[derive(Clone)]
33pub struct NativeVm<E: NativeVmExtension> {
34 extension: E,
35}
36
37impl<E: NativeVmExtension> NativeVm<E> {
38 pub fn new_with_extension(extension: E) -> Self {
39 Self { extension }
40 }
41
42 pub fn create_instance(
43 &self,
44 package_address: &PackageAddress,
45 code: &[u8],
46 ) -> Result<NativeVmInstance<E::Instance>, RuntimeError> {
47 if let Some(custom_invoke) = self.extension.try_create_instance(code) {
48 return Ok(NativeVmInstance::Extension(custom_invoke));
49 }
50
51 let code: [u8; 8] = match code.try_into() {
52 Ok(code) => code,
53 Err(..) => {
59 return Err(RuntimeError::VmError(VmError::Native(
60 NativeRuntimeError::InvalidCodeId,
61 )));
62 }
63 };
64 let native_package_code_id = u64::from_be_bytes(code);
65 let instance = NativeVmInstance::Native {
66 package_address: *package_address,
67 native_package_code_id,
68 };
69
70 Ok(instance)
71 }
72}
73
74pub enum NativeVmInstance<I: VmInvoke> {
75 Native {
76 #[allow(dead_code)]
78 package_address: PackageAddress,
79 native_package_code_id: u64,
80 },
81 Extension(I),
82}
83
84impl<I: VmInvoke> NativeVmInstance<I> {
85 #[allow(dead_code)]
87 pub fn package_address(&self) -> PackageAddress {
88 match self {
89 NativeVmInstance::Native {
90 package_address, ..
91 } => *package_address,
92 _ => panic!("Profiling with NativeVmExtension is not supported."),
93 }
94 }
95}
96
97impl<I: VmInvoke> VmInvoke for NativeVmInstance<I> {
98 #[trace_resources(log=self.package_address().is_native_package(), log=self.package_address().to_hex(), log=export_name)]
99 fn invoke<
100 Y: SystemApi<RuntimeError>
101 + KernelNodeApi
102 + KernelSubstateApi<SystemLockData>
103 + SystemBasedKernelInternalApi,
104 V: VmApi,
105 >(
106 &mut self,
107 export_name: &str,
108 input: &IndexedScryptoValue,
109 api: &mut Y,
110 vm_api: &V,
111 ) -> Result<IndexedScryptoValue, RuntimeError> {
112 #[allow(unused_mut)]
113 let mut func = || match self {
114 NativeVmInstance::Extension(e) => e.invoke(export_name, input, api, vm_api),
115 NativeVmInstance::Native {
116 native_package_code_id,
117 package_address,
118 } => {
119 api.consume_cost_units(ClientCostingEntry::RunNativeCode {
120 package_address,
121 export_name,
122 input_size: input.len(),
123 })?;
124
125 let code_id = NativeCodeId::from_repr(*native_package_code_id).ok_or(
126 RuntimeError::VmError(VmError::Native(NativeRuntimeError::InvalidCodeId)),
127 )?;
128
129 match code_id {
130 NativeCodeId::PackageCode1 => PackageNativePackage::invoke_export(
131 export_name,
132 input,
133 PackageV1MinorVersion::Zero,
134 api,
135 vm_api,
136 ),
137 NativeCodeId::PackageCode2 => PackageNativePackage::invoke_export(
138 export_name,
139 input,
140 PackageV1MinorVersion::One,
141 api,
142 vm_api,
143 ),
144 NativeCodeId::ResourceCode1 => {
145 ResourceNativePackage::invoke_export(export_name, input, api)
146 }
147 NativeCodeId::ResourceCode2 => {
148 WorktopBlueprintCuttlefishExtension::invoke_export(export_name, input, api)
149 }
150 NativeCodeId::ConsensusManagerCode1 => {
151 ConsensusManagerNativePackage::invoke_export(export_name, input, api)
152 }
153 NativeCodeId::ConsensusManagerCode2 => {
154 ConsensusManagerSecondsPrecisionNativeCode::invoke_export(
155 export_name,
156 input,
157 api,
158 )
159 }
160 NativeCodeId::IdentityCode1 => IdentityNativePackage::invoke_export(
161 export_name,
162 input,
163 IdentityV1MinorVersion::Zero,
164 api,
165 ),
166 NativeCodeId::IdentityCode2 => IdentityNativePackage::invoke_export(
167 export_name,
168 input,
169 IdentityV1MinorVersion::One,
170 api,
171 ),
172 NativeCodeId::AccountCode1 => {
173 AccountNativePackage::invoke_export(export_name, input, api)
174 }
175 NativeCodeId::AccountCode2 => {
176 AccountBlueprintBottlenoseExtension::invoke_export(export_name, input, api)
177 }
178 NativeCodeId::AccountCode3 => {
179 AccountBlueprintCuttlefishExtension::invoke_export(export_name, input, api)
180 }
181 NativeCodeId::AccessControllerCode1 => {
182 AccessControllerV1NativePackage::invoke_export(export_name, input, api)
183 }
184 NativeCodeId::AccessControllerCode2 => {
185 AccessControllerV2NativePackage::invoke_export(export_name, input, api)
186 }
187 NativeCodeId::TransactionProcessorCode1 => {
188 TransactionProcessorNativePackage::invoke_export(
189 export_name,
190 input,
191 TransactionProcessorV1MinorVersion::Zero,
192 api,
193 )
194 }
195 NativeCodeId::TransactionProcessorCode2 => {
196 TransactionProcessorNativePackage::invoke_export(
197 export_name,
198 input,
199 TransactionProcessorV1MinorVersion::One,
200 api,
201 )
202 }
203 NativeCodeId::MetadataCode1 => {
204 MetadataNativePackage::invoke_export(export_name, input, api)
205 }
206 NativeCodeId::RoyaltyCode1 => {
207 RoyaltyNativePackage::invoke_export(export_name, input, api)
208 }
209 NativeCodeId::RoleAssignmentCode1 => {
210 RoleAssignmentNativePackage::invoke_export(export_name, input, api)
211 }
212 NativeCodeId::RoleAssignmentCode2 => {
213 RoleAssignmentBottlenoseExtension::invoke_export(export_name, input, api)
214 }
215 NativeCodeId::PoolCode1 => PoolNativePackage::invoke_export(
216 export_name,
217 input,
218 PoolV1MinorVersion::Zero,
219 api,
220 ),
221 NativeCodeId::PoolCode2 => PoolNativePackage::invoke_export(
222 export_name,
223 input,
224 PoolV1MinorVersion::One,
225 api,
226 ),
227 NativeCodeId::TransactionTrackerCode1 => {
228 TransactionTrackerNativePackage::invoke_export(export_name, input, api)
229 }
230 NativeCodeId::TestUtilsCode1 => {
231 TestUtilsNativePackage::invoke_export(export_name, input, api)
232 }
233 NativeCodeId::LockerCode1 => {
234 LockerNativePackage::invoke_export(export_name, input, api)
235 }
236 }
237 }
238 };
239
240 {
243 #[cfg(feature = "std")]
244 {
245 match std::panic::catch_unwind(std::panic::AssertUnwindSafe(func)) {
246 Ok(rtn) => rtn,
247 Err(cause) => {
248 let message = if let Some(s) = cause.downcast_ref::<&'static str>() {
249 (*s).to_string()
250 } else if let Some(s) = cause.downcast_ref::<String>() {
251 s.clone()
252 } else {
253 "Unknown panic!".to_string()
254 };
255 Err(RuntimeError::VmError(VmError::Native(
256 NativeRuntimeError::Trap {
257 export_name: export_name.to_owned(),
258 input: input.as_scrypto_value().clone(),
259 error: message,
260 },
261 )))
262 }
263 }
264 }
265
266 #[cfg(not(feature = "std"))]
267 func()
268 }
269 }
270}
271
272pub trait NativeVmExtension: Clone {
273 type Instance: VmInvoke + Clone;
274
275 fn try_create_instance(&self, code: &[u8]) -> Option<Self::Instance>;
276}
277
278#[derive(Clone)]
279pub struct NoExtension;
280impl NativeVmExtension for NoExtension {
281 type Instance = NullVmInvoke;
282 fn try_create_instance(&self, _code: &[u8]) -> Option<Self::Instance> {
283 None
284 }
285}
286
287pub type DefaultNativeVm = NativeVm<NoExtension>;
288
289impl DefaultNativeVm {
290 pub fn new() -> Self {
291 NativeVm::new_with_extension(NoExtension)
292 }
293}
294
295impl Default for DefaultNativeVm {
296 fn default() -> Self {
297 Self::new()
298 }
299}
300
301#[derive(Clone)]
302pub struct NullVmInvoke;
303
304impl VmInvoke for NullVmInvoke {
305 fn invoke<
306 Y: SystemApi<RuntimeError> + KernelNodeApi + KernelSubstateApi<SystemLockData>,
307 V: VmApi,
308 >(
309 &mut self,
310 _export_name: &str,
311 _input: &IndexedScryptoValue,
312 _api: &mut Y,
313 _vm_api: &V,
314 ) -> Result<IndexedScryptoValue, RuntimeError> {
315 panic!("Invocation was called on null VmInvoke");
316 }
317}
318
319#[derive(Clone)]
320pub struct OverridePackageCode<C: VmInvoke + Clone> {
321 custom_package_code_id: u64,
322 custom_invoke: C,
323}
324
325impl<C: VmInvoke + Clone> OverridePackageCode<C> {
326 pub fn new(custom_package_code_id: u64, custom_invoke: C) -> Self {
327 Self {
328 custom_package_code_id,
329 custom_invoke,
330 }
331 }
332}
333
334impl<C: VmInvoke + Clone> NativeVmExtension for OverridePackageCode<C> {
335 type Instance = C;
336
337 fn try_create_instance(&self, code: &[u8]) -> Option<C> {
338 let code_id = {
339 let code: [u8; 8] = match code.try_into() {
340 Ok(code) => code,
341 Err(..) => return None,
342 };
343 u64::from_be_bytes(code)
344 };
345
346 if self.custom_package_code_id == code_id {
347 Some(self.custom_invoke.clone())
348 } else {
349 None
350 }
351 }
352}