gp_wasm_interface/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Types and traits for interfacing between the host and the wasm runtime.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use sp_std::{iter::Iterator, marker::PhantomData, result, vec, vec::Vec};
23pub use sp_wasm_interface_common::{self as common, Value, ValueType, Pointer, PointerType, IntoValue, TryFromValue, ReturnValue, WordSize, MemoryId, HostPointer, Signature};
24
25if_wasmtime_is_enabled! {
26    mod host_state;
27    pub use host_state::HostState;
28
29    mod store_data;
30    pub use store_data::StoreData;
31
32    mod memory_wrapper;
33    pub use memory_wrapper::MemoryWrapper;
34
35    pub mod util;
36}
37
38#[cfg(not(all(feature = "std", feature = "wasmtime")))]
39pub struct StoreData;
40
41#[cfg(not(all(feature = "std", feature = "wasmtime")))]
42#[macro_export]
43macro_rules! if_wasmtime_is_enabled {
44	($($token:tt)*) => {};
45}
46
47#[cfg(all(feature = "std", feature = "wasmtime"))]
48#[macro_export]
49macro_rules! if_wasmtime_is_enabled {
50    ($($token:tt)*) => {
51        $($token)*
52    }
53}
54
55if_wasmtime_is_enabled! {
56	// Reexport wasmtime so that its types are accessible from the procedural macro.
57	pub use wasmtime;
58
59	// Wasmtime uses anyhow types but doesn't reexport them.
60	pub use anyhow;
61}
62
63/// Result type used by traits in this crate.
64#[cfg(feature = "std")]
65pub type Result<T> = result::Result<T, String>;
66#[cfg(not(feature = "std"))]
67pub type Result<T> = result::Result<T, &'static str>;
68
69/// Provides `Sealed` trait to prevent implementing trait `PointerType` and `WasmTy` outside of this
70/// crate.
71mod private {
72	pub trait Sealed {}
73
74	impl Sealed for u8 {}
75	impl Sealed for u16 {}
76	impl Sealed for u32 {}
77	impl Sealed for u64 {}
78
79	impl Sealed for i32 {}
80	impl Sealed for i64 {}
81
82    pub(super) struct Token;
83}
84
85/// A trait that requires `RefUnwindSafe` when `feature = std`.
86#[cfg(feature = "std")]
87pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
88#[cfg(feature = "std")]
89impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
90
91/// A trait that requires `RefUnwindSafe` when `feature = std`.
92#[cfg(not(feature = "std"))]
93pub trait MaybeRefUnwindSafe {}
94#[cfg(not(feature = "std"))]
95impl<T> MaybeRefUnwindSafe for T {}
96
97/// Something that provides a function implementation on the host for a wasm function.
98pub trait Function: MaybeRefUnwindSafe + Send + Sync {
99	/// Returns the name of this function.
100	fn name(&self) -> &str;
101	/// Returns the signature of this function.
102	fn signature(&self) -> Signature;
103	/// Execute this function with the given arguments.
104	fn execute(
105		&self,
106		context: &mut dyn FunctionContext,
107		args: &mut dyn Iterator<Item = Value>,
108	) -> Result<Option<Value>>;
109}
110
111impl PartialEq for dyn Function {
112	fn eq(&self, other: &Self) -> bool {
113		other.name() == self.name() && other.signature() == self.signature()
114	}
115}
116
117#[cfg(not(all(feature = "std", feature = "wasmtime")))]
118pub struct Caller<'a, T>(PhantomData<&'a T>);
119
120#[cfg(all(feature = "std", feature = "wasmtime"))]
121pub use wasmtime::Caller;
122
123pub struct FunctionContextToken(private::Token);
124
125impl FunctionContextToken {
126    fn new() -> Self {
127        Self(private::Token)
128    }
129}
130
131/// Context used by `Function` to interact with the allocator and the memory of the wasm instance.
132pub trait FunctionContext {
133	/// Read memory from `address` into a vector.
134	fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
135		let mut vec = vec![0; size as usize];
136		self.read_memory_into(address, &mut vec)?;
137		Ok(vec)
138	}
139	/// Read memory into the given `dest` buffer from `address`.
140	fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
141	/// Write the given data at `address` into the memory.
142	fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
143	/// Allocate a memory instance of `size` bytes.
144	fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
145	/// Deallocate a given memory instance.
146	fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
147	/// Registers a panic error message within the executor.
148	///
149	/// This is meant to be used in situations where the runtime
150	/// encounters an unrecoverable error and intends to panic.
151	///
152	/// Panicking in WASM is done through the [`unreachable`](https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-control)
153	/// instruction which causes an unconditional trap and immediately aborts
154	/// the execution. It does not however allow for any diagnostics to be
155	/// passed through to the host, so while we do know that *something* went
156	/// wrong we don't have any direct indication of what *exactly* went wrong.
157	///
158	/// As a workaround we use this method right before the execution is
159	/// actually aborted to pass an error message to the host so that it
160	/// can associate it with the next trap, and return that to the caller.
161	///
162	/// A WASM trap should be triggered immediately after calling this method;
163	/// otherwise the error message might be associated with a completely
164	/// unrelated trap.
165	///
166	/// It should only be called once, however calling it more than once
167	/// is harmless and will overwrite the previously set error message.
168	fn register_panic_error_message(&mut self, message: &str);
169
170    fn with_caller_mut_impl(&mut self, _: FunctionContextToken, context: *mut (), callback: fn(*mut (), &mut Caller<StoreData>));
171
172}
173
174pub fn with_caller_mut<T: FnMut(&mut Caller<StoreData>)>(context: &mut dyn FunctionContext, mut callback: T) {
175    let callback: *mut T = &mut callback;
176    context.with_caller_mut_impl(FunctionContextToken::new(), callback.cast(), |callback, caller| {
177        let callback: *mut T = callback.cast();
178        let callback: &mut T = unsafe { callback.as_mut().expect("we own the value, obtain mutable reference to it and cast to pointer (correct (not null) and aligned properly); qed") };
179
180        callback(caller);
181    })
182}
183
184if_wasmtime_is_enabled! {
185	/// A trait used to statically register host callbacks with the WASM executor,
186	/// so that they call be called from within the runtime with minimal overhead.
187	///
188	/// This is used internally to interface the wasmtime-based executor with the
189	/// host functions' definitions generated through the runtime interface macro,
190	/// and is not meant to be used directly.
191	pub trait HostFunctionRegistry {
192		type State;
193		type Error;
194		type FunctionContext: FunctionContext;
195
196		/// Wraps the given `caller` in a type which implements `FunctionContext`
197		/// and calls the given `callback`.
198		fn with_function_context<R>(
199			caller: wasmtime::Caller<Self::State>,
200			callback: impl FnOnce(&mut dyn FunctionContext) -> R,
201		) -> R;
202
203		/// Registers a given host function with the WASM executor.
204		///
205		/// The function has to be statically callable, and all of its arguments
206		/// and its return value have to be compatible with WASM FFI.
207		fn register_static<Params, Results>(
208			&mut self,
209			fn_name: &str,
210			func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
211		) -> core::result::Result<(), Self::Error>;
212	}
213}
214
215/// Something that provides implementations for host functions.
216pub trait HostFunctions: 'static + Send + Sync {
217	/// Returns the host functions `Self` provides.
218	fn host_functions() -> Vec<&'static dyn Function>;
219
220	if_wasmtime_is_enabled! {
221		/// Statically registers the host functions.
222		fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
223		where
224			T: HostFunctionRegistry;
225	}
226}
227
228#[impl_trait_for_tuples::impl_for_tuples(30)]
229impl HostFunctions for Tuple {
230	fn host_functions() -> Vec<&'static dyn Function> {
231		let mut host_functions = Vec::new();
232
233		for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
234
235		host_functions
236	}
237
238	#[cfg(all(feature = "std", feature = "wasmtime"))]
239	fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
240	where
241		T: HostFunctionRegistry,
242	{
243		for_tuples!(
244			#( Tuple::register_static(registry)?; )*
245		);
246
247		Ok(())
248	}
249}
250
251/// A wrapper which merges two sets of host functions, and allows the second set to override
252/// the host functions from the first set.
253pub struct ExtendedHostFunctions<Base, Overlay> {
254	phantom: PhantomData<(Base, Overlay)>,
255}
256
257impl<Base, Overlay> HostFunctions for ExtendedHostFunctions<Base, Overlay>
258where
259	Base: HostFunctions,
260	Overlay: HostFunctions,
261{
262	fn host_functions() -> Vec<&'static dyn Function> {
263		let mut base = Base::host_functions();
264		let overlay = Overlay::host_functions();
265		base.retain(|host_fn| {
266			!overlay.iter().any(|ext_host_fn| host_fn.name() == ext_host_fn.name())
267		});
268		base.extend(overlay);
269		base
270	}
271
272	if_wasmtime_is_enabled! {
273		fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
274		where
275			T: HostFunctionRegistry,
276		{
277			struct Proxy<'a, T> {
278				registry: &'a mut T,
279				seen_overlay: std::collections::HashSet<String>,
280				seen_base: std::collections::HashSet<String>,
281				overlay_registered: bool,
282			}
283
284			impl<'a, T> HostFunctionRegistry for Proxy<'a, T>
285			where
286				T: HostFunctionRegistry,
287			{
288				type State = T::State;
289				type Error = T::Error;
290				type FunctionContext = T::FunctionContext;
291
292				fn with_function_context<R>(
293					caller: wasmtime::Caller<Self::State>,
294					callback: impl FnOnce(&mut dyn FunctionContext) -> R,
295				) -> R {
296					T::with_function_context(caller, callback)
297				}
298
299				fn register_static<Params, Results>(
300					&mut self,
301					fn_name: &str,
302					func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
303				) -> core::result::Result<(), Self::Error> {
304					if self.overlay_registered {
305						if !self.seen_base.insert(fn_name.to_owned()) {
306							log::warn!(
307								target: "extended_host_functions",
308								"Duplicate base host function: '{}'",
309								fn_name,
310							);
311
312							// TODO: Return an error here?
313							return Ok(())
314						}
315
316						if self.seen_overlay.contains(fn_name) {
317							// Was already registered when we went through the overlay, so just ignore it.
318							log::debug!(
319								target: "extended_host_functions",
320								"Overriding base host function: '{}'",
321								fn_name,
322							);
323
324							return Ok(())
325						}
326					} else if !self.seen_overlay.insert(fn_name.to_owned()) {
327						log::warn!(
328							target: "extended_host_functions",
329							"Duplicate overlay host function: '{}'",
330							fn_name,
331						);
332
333						// TODO: Return an error here?
334						return Ok(())
335					}
336
337					self.registry.register_static(fn_name, func)
338				}
339			}
340
341			let mut proxy = Proxy {
342				registry,
343				seen_overlay: Default::default(),
344				seen_base: Default::default(),
345				overlay_registered: false,
346			};
347
348			// The functions from the `Overlay` can override those from the `Base`,
349			// so `Overlay` is registered first, and then we skip those functions
350			// in `Base` if they were already registered from the `Overlay`.
351			Overlay::register_static(&mut proxy)?;
352			proxy.overlay_registered = true;
353			Base::register_static(&mut proxy)?;
354
355			Ok(())
356		}
357	}
358}
359
360/// A trait for types directly usable at the WASM FFI boundary without any conversion at all.
361///
362/// This trait is sealed and should not be implemented downstream.
363#[cfg(all(feature = "std", feature = "wasmtime"))]
364pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
365
366/// A trait for types directly usable at the WASM FFI boundary without any conversion at all.
367///
368/// This trait is sealed and should not be implemented downstream.
369#[cfg(not(all(feature = "std", feature = "wasmtime")))]
370pub trait WasmTy: private::Sealed {}
371
372impl WasmTy for i32 {}
373impl WasmTy for u32 {}
374impl WasmTy for i64 {}
375impl WasmTy for u64 {}