sc_executor_wasmtime/
imports.rs1use crate::{host::HostContext, runtime::StoreData};
20use sc_executor_common::error::WasmError;
21use sp_wasm_interface::{FunctionContext, HostFunctions};
22use std::collections::HashMap;
23use wasmtime::{ExternType, FuncType, ImportType, Linker, Module};
24
25pub(crate) fn prepare_imports<H>(
28 linker: &mut Linker<StoreData>,
29 module: &Module,
30 allow_missing_func_imports: bool,
31) -> Result<(), WasmError>
32where
33 H: HostFunctions,
34{
35 let mut pending_func_imports = HashMap::new();
36 for import_ty in module.imports() {
37 let name = import_ty.name();
38
39 if import_ty.module() != "env" {
40 return Err(WasmError::Other(format!(
41 "host doesn't provide any imports from non-env module: {}:{}",
42 import_ty.module(),
43 name,
44 )))
45 }
46
47 match import_ty.ty() {
48 ExternType::Func(func_ty) => {
49 pending_func_imports.insert(name.to_owned(), (import_ty, func_ty));
50 },
51 _ =>
52 return Err(WasmError::Other(format!(
53 "host doesn't provide any non function imports: {}:{}",
54 import_ty.module(),
55 name,
56 ))),
57 };
58 }
59
60 let mut registry = Registry { linker, pending_func_imports };
61 H::register_static(&mut registry)?;
62
63 if !registry.pending_func_imports.is_empty() {
64 if allow_missing_func_imports {
65 for (name, (import_ty, func_ty)) in registry.pending_func_imports {
66 let error = format!("call to a missing function {}:{}", import_ty.module(), name);
67 log::debug!("Missing import: '{}' {:?}", name, func_ty);
68 linker
69 .func_new("env", &name, func_ty.clone(), move |_, _, _| {
70 Err(anyhow::Error::msg(error.clone()))
71 })
72 .expect("adding a missing import stub can only fail when the item already exists, and it is missing here; qed");
73 }
74 } else {
75 let mut names = Vec::new();
76 for (name, (import_ty, _)) in registry.pending_func_imports {
77 names.push(format!("'{}:{}'", import_ty.module(), name));
78 }
79 let names = names.join(", ");
80 return Err(WasmError::Other(format!(
81 "runtime requires function imports which are not present on the host: {}",
82 names
83 )))
84 }
85 }
86
87 Ok(())
88}
89
90struct Registry<'a, 'b> {
91 linker: &'a mut Linker<StoreData>,
92 pending_func_imports: HashMap<String, (ImportType<'b>, FuncType)>,
93}
94
95impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> {
96 type State = StoreData;
97 type Error = WasmError;
98 type FunctionContext = HostContext<'a>;
99
100 fn with_function_context<R>(
101 caller: wasmtime::Caller<Self::State>,
102 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
103 ) -> R {
104 callback(&mut HostContext { caller })
105 }
106
107 fn register_static<Params, Results>(
108 &mut self,
109 fn_name: &str,
110 func: impl wasmtime::IntoFunc<Self::State, Params, Results>,
111 ) -> Result<(), Self::Error> {
112 if self.pending_func_imports.remove(fn_name).is_some() {
113 self.linker.func_wrap("env", fn_name, func).map_err(|error| {
114 WasmError::Other(format!(
115 "failed to register host function '{}' with the WASM linker: {:#}",
116 fn_name, error
117 ))
118 })?;
119 }
120
121 Ok(())
122 }
123}