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 mut input = Vec::new();
62            input.push(
63                runtime
64                    .allocate_buffer(args.as_slice().to_vec())
65                    .expect("Failed to allocate buffer"),
66            );
67            self.instance
68                .invoke_export(export_name, input, &mut runtime)?
69        };
70
71        let output = IndexedScryptoValue::from_vec(rtn).map_err(|e| {
72            RuntimeError::SystemUpstreamError(SystemUpstreamError::OutputDecodeError(e))
73        })?;
74
75        Ok(output)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    const _: () = {
82        fn assert_sync<T: Sync>() {}
83
84        fn assert_all() {
85            // The ScryptoInterpreter struct captures the code and module template caches.
86            // We therefore share a ScryptoInterpreter as a shared cache across Engine runs on the node.
87            // This allows EG multiple mempool submission validations via the Core API at the same time
88            // This test ensures the requirement for this cache to be Sync isn't broken
89            // (At least when we compile with std, as the node does)
90            #[cfg(not(feature = "alloc"))]
91            assert_sync::<crate::vm::ScryptoVm<crate::vm::wasm::DefaultWasmEngine>>();
92        }
93    };
94}