1#![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 pub use wasmtime;
58
59 pub use anyhow;
61}
62
63#[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
69mod 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#[cfg(feature = "std")]
87pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
88#[cfg(feature = "std")]
89impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
90
91#[cfg(not(feature = "std"))]
93pub trait MaybeRefUnwindSafe {}
94#[cfg(not(feature = "std"))]
95impl<T> MaybeRefUnwindSafe for T {}
96
97pub trait Function: MaybeRefUnwindSafe + Send + Sync {
99 fn name(&self) -> &str;
101 fn signature(&self) -> Signature;
103 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
131pub trait FunctionContext {
133 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 fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
141 fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
143 fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
145 fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
147 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 pub trait HostFunctionRegistry {
192 type State;
193 type Error;
194 type FunctionContext: FunctionContext;
195
196 fn with_function_context<R>(
199 caller: wasmtime::Caller<Self::State>,
200 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
201 ) -> R;
202
203 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
215pub trait HostFunctions: 'static + Send + Sync {
217 fn host_functions() -> Vec<&'static dyn Function>;
219
220 if_wasmtime_is_enabled! {
221 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
251pub 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 return Ok(())
314 }
315
316 if self.seen_overlay.contains(fn_name) {
317 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 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 Overlay::register_static(&mut proxy)?;
352 proxy.overlay_registered = true;
353 Base::register_static(&mut proxy)?;
354
355 Ok(())
356 }
357 }
358}
359
360#[cfg(all(feature = "std", feature = "wasmtime"))]
364pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
365
366#[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 {}