radix_engine/vm/
scrypto_vm.rs

1use crate::errors::{RuntimeError, SystemUpstreamError};
2use crate::internal_prelude::*;
3use crate::vm::vm::VmInvoke;
4use crate::vm::wasm::*;
5use crate::vm::wasm_runtime::ScryptoRuntime;
6use crate::vm::VmApi;
7use radix_engine_interface::api::SystemApi;
8use radix_engine_interface::blueprints::package::CodeHash;
9use radix_engine_profiling_derive::trace_resources;
10
11pub struct ScryptoVm<W: WasmEngine> {
12    pub wasm_engine: W,
13    pub wasm_validator_config: WasmValidatorConfigV1,
14}
15
16impl<W: WasmEngine + Default> Default for ScryptoVm<W> {
17    fn default() -> Self {
18        Self {
19            wasm_engine: W::default(),
20            wasm_validator_config: WasmValidatorConfigV1::new(),
21        }
22    }
23}
24
25impl<W: WasmEngine> ScryptoVm<W> {
26    pub fn create_instance(
27        &self,
28        package_address: &PackageAddress,
29        code_hash: CodeHash,
30        instrumented_code: &[u8],
31    ) -> ScryptoVmInstance<W::WasmInstance> {
32        ScryptoVmInstance {
33            instance: self.wasm_engine.instantiate(code_hash, instrumented_code),
34            package_address: *package_address,
35        }
36    }
37}
38
39pub struct ScryptoVmInstance<I: WasmInstance> {
40    instance: I,
41    package_address: PackageAddress,
42}
43
44impl<I: WasmInstance> VmInvoke for ScryptoVmInstance<I> {
45    #[trace_resources(log=self.package_address.is_native_package(), log=self.package_address.to_hex(), log=export_name)]
46    fn invoke<Y: SystemApi<RuntimeError>, V: VmApi>(
47        &mut self,
48        export_name: &str,
49        args: &IndexedScryptoValue,
50        api: &mut Y,
51        vm_api: &V,
52    ) -> Result<IndexedScryptoValue, RuntimeError> {
53        let rtn = {
54            let mut runtime: Box<dyn WasmRuntime> = Box::new(ScryptoRuntime::new(
55                api,
56                self.package_address,
57                export_name.to_string(),
58                vm_api.get_scrypto_version(),
59            ));
60
61            let input = vec![runtime
62                .allocate_buffer(args.as_slice().to_vec())
63                .expect("Failed to allocate buffer")];
64            self.instance
65                .invoke_export(export_name, input, &mut runtime)?
66        };
67
68        let output = IndexedScryptoValue::from_vec(rtn).map_err(|e| {
69            RuntimeError::SystemUpstreamError(SystemUpstreamError::OutputDecodeError(e))
70        })?;
71
72        Ok(output)
73    }
74}
75
76#[cfg(test)]
77#[allow(dead_code)]
78mod tests {
79    const _: () = {
80        fn assert_sync<T: Sync>() {}
81
82        fn assert_all() {
83            // The ScryptoInterpreter struct captures the code and module template caches.
84            // We therefore share a ScryptoInterpreter as a shared cache across Engine runs on the node.
85            // This allows EG multiple mempool submission validations via the Core API at the same time
86            // This test ensures the requirement for this cache to be Sync isn't broken
87            // (At least when we compile with std, as the node does)
88            #[cfg(not(feature = "alloc"))]
89            assert_sync::<crate::vm::ScryptoVm<crate::vm::wasm::DefaultWasmEngine>>();
90        }
91    };
92}