This repository has been archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
imports.rs
123 lines (107 loc) · 3.85 KB
/
imports.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// This file is part of Substrate.
// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{host::HostContext, runtime::StoreData};
use sc_executor_common::error::WasmError;
use sp_wasm_interface::{FunctionContext, HostFunctions};
use std::collections::HashMap;
use wasmtime::{ExternType, FuncType, ImportType, Linker, Module, Trap};
/// Goes over all imports of a module and prepares the given linker for instantiation of the module.
/// Returns an error if there are imports that cannot be satisfied.
pub(crate) fn prepare_imports<H>(
linker: &mut Linker<StoreData>,
module: &Module,
allow_missing_func_imports: bool,
) -> Result<(), WasmError>
where
H: HostFunctions,
{
let mut pending_func_imports = HashMap::new();
for import_ty in module.imports() {
let name = import_ty.name();
if import_ty.module() != "env" {
return Err(WasmError::Other(format!(
"host doesn't provide any imports from non-env module: {}:{}",
import_ty.module(),
name,
)))
}
match import_ty.ty() {
ExternType::Func(func_ty) => {
pending_func_imports.insert(name.to_owned(), (import_ty, func_ty));
},
_ =>
return Err(WasmError::Other(format!(
"host doesn't provide any non function imports: {}:{}",
import_ty.module(),
name,
))),
};
}
let mut registry = Registry { linker, pending_func_imports };
H::register_static(&mut registry)?;
if !registry.pending_func_imports.is_empty() {
if allow_missing_func_imports {
for (name, (import_ty, func_ty)) in registry.pending_func_imports {
let error = format!("call to a missing function {}:{}", import_ty.module(), name);
log::debug!("Missing import: '{}' {:?}", name, func_ty);
linker
.func_new("env", &name, func_ty.clone(), move |_, _, _| {
Err(Trap::new(error.clone()))
})
.expect("adding a missing import stub can only fail when the item already exists, and it is missing here; qed");
}
} else {
let mut names = Vec::new();
for (name, (import_ty, _)) in registry.pending_func_imports {
names.push(format!("'{}:{}'", import_ty.module(), name));
}
let names = names.join(", ");
return Err(WasmError::Other(format!(
"runtime requires function imports which are not present on the host: {}",
names
)))
}
}
Ok(())
}
struct Registry<'a, 'b> {
linker: &'a mut Linker<StoreData>,
pending_func_imports: HashMap<String, (ImportType<'b>, FuncType)>,
}
impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> {
type State = StoreData;
type Error = WasmError;
type FunctionContext = HostContext<'a>;
fn with_function_context<R>(
caller: wasmtime::Caller<Self::State>,
callback: impl FnOnce(&mut dyn FunctionContext) -> R,
) -> R {
callback(&mut HostContext { caller })
}
fn register_static<Params, Results>(
&mut self,
fn_name: &str,
func: impl wasmtime::IntoFunc<Self::State, Params, Results>,
) -> Result<(), Self::Error> {
if self.pending_func_imports.remove(fn_name).is_some() {
self.linker.func_wrap("env", fn_name, func).map_err(|error| {
WasmError::Other(format!(
"failed to register host function '{}' with the WASM linker: {}",
fn_name, error
))
})?;
}
Ok(())
}
}