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

            
22
extern crate alloc;
23

            
24
use alloc::{borrow::Cow, vec, vec::Vec};
25
use core::{iter::Iterator, marker::PhantomData, mem, result};
26

            
27
#[cfg(not(all(feature = "std", feature = "wasmtime")))]
28
#[macro_export]
29
macro_rules! if_wasmtime_is_enabled {
30
	($($token:tt)*) => {};
31
}
32

            
33
#[cfg(all(feature = "std", feature = "wasmtime"))]
34
#[macro_export]
35
macro_rules! if_wasmtime_is_enabled {
36
    ($($token:tt)*) => {
37
        $($token)*
38
    }
39
}
40

            
41
if_wasmtime_is_enabled! {
42
	// Reexport wasmtime so that its types are accessible from the procedural macro.
43
	pub use wasmtime;
44

            
45
	// Wasmtime uses anyhow types but doesn't reexport them.
46
	pub use anyhow;
47
}
48

            
49
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
50

            
51
/// Result type used by traits in this crate.
52
#[cfg(feature = "std")]
53
pub type Result<T> = result::Result<T, String>;
54
#[cfg(not(feature = "std"))]
55
pub type Result<T> = result::Result<T, &'static str>;
56

            
57
/// Value types supported by Substrate on the boundary between host/Wasm.
58
#[derive(Copy, Clone, PartialEq, Debug, Eq)]
59
pub enum ValueType {
60
	/// An `i32` value type.
61
	I32,
62
	/// An `i64` value type.
63
	I64,
64
	/// An `f32` value type.
65
	F32,
66
	/// An `f64` value type.
67
	F64,
68
}
69

            
70
impl From<ValueType> for u8 {
71
	fn from(val: ValueType) -> u8 {
72
		match val {
73
			ValueType::I32 => 0,
74
			ValueType::I64 => 1,
75
			ValueType::F32 => 2,
76
			ValueType::F64 => 3,
77
		}
78
	}
79
}
80

            
81
impl TryFrom<u8> for ValueType {
82
	type Error = ();
83

            
84
	fn try_from(val: u8) -> core::result::Result<ValueType, ()> {
85
		match val {
86
			0 => Ok(Self::I32),
87
			1 => Ok(Self::I64),
88
			2 => Ok(Self::F32),
89
			3 => Ok(Self::F64),
90
			_ => Err(()),
91
		}
92
	}
93
}
94

            
95
/// Values supported by Substrate on the boundary between host/Wasm.
96
#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
97
pub enum Value {
98
	/// A 32-bit integer.
99
	I32(i32),
100
	/// A 64-bit integer.
101
	I64(i64),
102
	/// A 32-bit floating-point number stored as raw bit pattern.
103
	///
104
	/// You can materialize this value using `f32::from_bits`.
105
	F32(u32),
106
	/// A 64-bit floating-point number stored as raw bit pattern.
107
	///
108
	/// You can materialize this value using `f64::from_bits`.
109
	F64(u64),
110
}
111

            
112
impl Value {
113
	/// Returns the type of this value.
114
	pub fn value_type(&self) -> ValueType {
115
		match self {
116
			Value::I32(_) => ValueType::I32,
117
			Value::I64(_) => ValueType::I64,
118
			Value::F32(_) => ValueType::F32,
119
			Value::F64(_) => ValueType::F64,
120
		}
121
	}
122

            
123
	/// Return `Self` as `i32`.
124
	pub fn as_i32(&self) -> Option<i32> {
125
		match self {
126
			Self::I32(val) => Some(*val),
127
			_ => None,
128
		}
129
	}
130
}
131

            
132
/// Provides `Sealed` trait to prevent implementing trait `PointerType` and `WasmTy` outside of this
133
/// crate.
134
mod private {
135
	pub trait Sealed {}
136

            
137
	impl Sealed for u8 {}
138
	impl Sealed for u16 {}
139
	impl Sealed for u32 {}
140
	impl Sealed for u64 {}
141

            
142
	impl Sealed for i32 {}
143
	impl Sealed for i64 {}
144
}
145

            
146
/// Something that can be wrapped in a wasm `Pointer`.
147
///
148
/// This trait is sealed.
149
pub trait PointerType: Sized + private::Sealed {
150
	/// The size of the type in wasm.
151
	const SIZE: u32 = mem::size_of::<Self>() as u32;
152
}
153

            
154
impl PointerType for u8 {}
155
impl PointerType for u16 {}
156
impl PointerType for u32 {}
157
impl PointerType for u64 {}
158

            
159
/// Type to represent a pointer in wasm at the host.
160
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
161
pub struct Pointer<T: PointerType> {
162
	ptr: u32,
163
	_marker: PhantomData<T>,
164
}
165

            
166
impl<T: PointerType> Pointer<T> {
167
	/// Create a new instance of `Self`.
168
	pub fn new(ptr: u32) -> Self {
169
		Self { ptr, _marker: Default::default() }
170
	}
171

            
172
	/// Calculate the offset from this pointer.
173
	///
174
	/// `offset` is in units of `T`. So, `3` means `3 * mem::size_of::<T>()` as offset to the
175
	/// pointer.
176
	///
177
	/// Returns an `Option` to respect that the pointer could probably overflow.
178
	pub fn offset(self, offset: u32) -> Option<Self> {
179
		offset
180
			.checked_mul(T::SIZE)
181
			.and_then(|o| self.ptr.checked_add(o))
182
			.map(|ptr| Self { ptr, _marker: Default::default() })
183
	}
184

            
185
	/// Create a null pointer.
186
	pub fn null() -> Self {
187
		Self::new(0)
188
	}
189

            
190
	/// Cast this pointer of type `T` to a pointer of type `R`.
191
	pub fn cast<R: PointerType>(self) -> Pointer<R> {
192
		Pointer::new(self.ptr)
193
	}
194
}
195

            
196
impl<T: PointerType> From<u32> for Pointer<T> {
197
	fn from(ptr: u32) -> Self {
198
		Pointer::new(ptr)
199
	}
200
}
201

            
202
impl<T: PointerType> From<Pointer<T>> for u32 {
203
	fn from(ptr: Pointer<T>) -> Self {
204
		ptr.ptr
205
	}
206
}
207

            
208
impl<T: PointerType> From<Pointer<T>> for u64 {
209
	fn from(ptr: Pointer<T>) -> Self {
210
		u64::from(ptr.ptr)
211
	}
212
}
213

            
214
impl<T: PointerType> From<Pointer<T>> for usize {
215
	fn from(ptr: Pointer<T>) -> Self {
216
		ptr.ptr as _
217
	}
218
}
219

            
220
impl<T: PointerType> IntoValue for Pointer<T> {
221
	const VALUE_TYPE: ValueType = ValueType::I32;
222
	fn into_value(self) -> Value {
223
		Value::I32(self.ptr as _)
224
	}
225
}
226

            
227
impl<T: PointerType> TryFromValue for Pointer<T> {
228
	fn try_from_value(val: Value) -> Option<Self> {
229
		match val {
230
			Value::I32(val) => Some(Self::new(val as _)),
231
			_ => None,
232
		}
233
	}
234
}
235

            
236
/// The word size used in wasm. Normally known as `usize` in Rust.
237
pub type WordSize = u32;
238

            
239
/// The Signature of a function
240
#[derive(Eq, PartialEq, Debug, Clone)]
241
pub struct Signature {
242
	/// The arguments of a function.
243
	pub args: Cow<'static, [ValueType]>,
244
	/// The optional return value of a function.
245
	pub return_value: Option<ValueType>,
246
}
247

            
248
impl Signature {
249
	/// Create a new instance of `Signature`.
250
	pub fn new<T: Into<Cow<'static, [ValueType]>>>(
251
		args: T,
252
		return_value: Option<ValueType>,
253
	) -> Self {
254
		Self { args: args.into(), return_value }
255
	}
256

            
257
	/// Create a new instance of `Signature` with the given `args` and without any return value.
258
	pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
259
		Self { args: args.into(), return_value: None }
260
	}
261
}
262

            
263
/// A trait that requires `RefUnwindSafe` when `feature = std`.
264
#[cfg(feature = "std")]
265
pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
266
#[cfg(feature = "std")]
267
impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
268

            
269
/// A trait that requires `RefUnwindSafe` when `feature = std`.
270
#[cfg(not(feature = "std"))]
271
pub trait MaybeRefUnwindSafe {}
272
#[cfg(not(feature = "std"))]
273
impl<T> MaybeRefUnwindSafe for T {}
274

            
275
/// Something that provides a function implementation on the host for a wasm function.
276
pub trait Function: MaybeRefUnwindSafe + Send + Sync {
277
	/// Returns the name of this function.
278
	fn name(&self) -> &str;
279
	/// Returns the signature of this function.
280
	fn signature(&self) -> Signature;
281
	/// Execute this function with the given arguments.
282
	fn execute(
283
		&self,
284
		context: &mut dyn FunctionContext,
285
		args: &mut dyn Iterator<Item = Value>,
286
	) -> Result<Option<Value>>;
287
}
288

            
289
impl PartialEq for dyn Function {
290
	fn eq(&self, other: &Self) -> bool {
291
		other.name() == self.name() && other.signature() == self.signature()
292
	}
293
}
294

            
295
/// Context used by `Function` to interact with the allocator and the memory of the wasm instance.
296
pub trait FunctionContext {
297
	/// Read memory from `address` into a vector.
298
	fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
299
		let mut vec = vec![0; size as usize];
300
		self.read_memory_into(address, &mut vec)?;
301
		Ok(vec)
302
	}
303
	/// Read memory into the given `dest` buffer from `address`.
304
	fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
305
	/// Write the given data at `address` into the memory.
306
	fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
307
	/// Allocate a memory instance of `size` bytes.
308
	fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
309
	/// Deallocate a given memory instance.
310
	fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
311
	/// Registers a panic error message within the executor.
312
	///
313
	/// This is meant to be used in situations where the runtime
314
	/// encounters an unrecoverable error and intends to panic.
315
	///
316
	/// Panicking in WASM is done through the [`unreachable`](https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-control)
317
	/// instruction which causes an unconditional trap and immediately aborts
318
	/// the execution. It does not however allow for any diagnostics to be
319
	/// passed through to the host, so while we do know that *something* went
320
	/// wrong we don't have any direct indication of what *exactly* went wrong.
321
	///
322
	/// As a workaround we use this method right before the execution is
323
	/// actually aborted to pass an error message to the host so that it
324
	/// can associate it with the next trap, and return that to the caller.
325
	///
326
	/// A WASM trap should be triggered immediately after calling this method;
327
	/// otherwise the error message might be associated with a completely
328
	/// unrelated trap.
329
	///
330
	/// It should only be called once, however calling it more than once
331
	/// is harmless and will overwrite the previously set error message.
332
	fn register_panic_error_message(&mut self, message: &str);
333
}
334

            
335
if_wasmtime_is_enabled! {
336
	/// A trait used to statically register host callbacks with the WASM executor,
337
	/// so that they call be called from within the runtime with minimal overhead.
338
	///
339
	/// This is used internally to interface the wasmtime-based executor with the
340
	/// host functions' definitions generated through the runtime interface macro,
341
	/// and is not meant to be used directly.
342
	pub trait HostFunctionRegistry {
343
		type State;
344
		type Error;
345
		type FunctionContext: FunctionContext;
346

            
347
		/// Wraps the given `caller` in a type which implements `FunctionContext`
348
		/// and calls the given `callback`.
349
		fn with_function_context<R>(
350
			caller: wasmtime::Caller<Self::State>,
351
			callback: impl FnOnce(&mut dyn FunctionContext) -> R,
352
		) -> R;
353

            
354
		/// Registers a given host function with the WASM executor.
355
		///
356
		/// The function has to be statically callable, and all of its arguments
357
		/// and its return value have to be compatible with WASM FFI.
358
		fn register_static<Params, Results>(
359
			&mut self,
360
			fn_name: &str,
361
			func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
362
		) -> core::result::Result<(), Self::Error>;
363
	}
364
}
365

            
366
/// Something that provides implementations for host functions.
367
pub trait HostFunctions: 'static + Send + Sync {
368
	/// Returns the host functions `Self` provides.
369
	fn host_functions() -> Vec<&'static dyn Function>;
370

            
371
	if_wasmtime_is_enabled! {
372
		/// Statically registers the host functions.
373
		fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
374
		where
375
			T: HostFunctionRegistry;
376
	}
377
}
378

            
379
#[impl_trait_for_tuples::impl_for_tuples(30)]
380
impl HostFunctions for Tuple {
381
	fn host_functions() -> Vec<&'static dyn Function> {
382
		let mut host_functions = Vec::new();
383

            
384
		for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
385

            
386
		host_functions
387
	}
388

            
389
	#[cfg(all(feature = "std", feature = "wasmtime"))]
390
	fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
391
	where
392
		T: HostFunctionRegistry,
393
	{
394
		for_tuples!(
395
			#( Tuple::register_static(registry)?; )*
396
		);
397

            
398
		Ok(())
399
	}
400
}
401

            
402
/// A wrapper which merges two sets of host functions, and allows the second set to override
403
/// the host functions from the first set.
404
pub struct ExtendedHostFunctions<Base, Overlay> {
405
	phantom: PhantomData<(Base, Overlay)>,
406
}
407

            
408
impl<Base, Overlay> HostFunctions for ExtendedHostFunctions<Base, Overlay>
409
where
410
	Base: HostFunctions,
411
	Overlay: HostFunctions,
412
{
413
	fn host_functions() -> Vec<&'static dyn Function> {
414
		let mut base = Base::host_functions();
415
		let overlay = Overlay::host_functions();
416
		base.retain(|host_fn| {
417
			!overlay.iter().any(|ext_host_fn| host_fn.name() == ext_host_fn.name())
418
		});
419
		base.extend(overlay);
420
		base
421
	}
422

            
423
	if_wasmtime_is_enabled! {
424
		fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
425
		where
426
			T: HostFunctionRegistry,
427
		{
428
			struct Proxy<'a, T> {
429
				registry: &'a mut T,
430
				seen_overlay: std::collections::HashSet<String>,
431
				seen_base: std::collections::HashSet<String>,
432
				overlay_registered: bool,
433
			}
434

            
435
			impl<'a, T> HostFunctionRegistry for Proxy<'a, T>
436
			where
437
				T: HostFunctionRegistry,
438
			{
439
				type State = T::State;
440
				type Error = T::Error;
441
				type FunctionContext = T::FunctionContext;
442

            
443
				fn with_function_context<R>(
444
					caller: wasmtime::Caller<Self::State>,
445
					callback: impl FnOnce(&mut dyn FunctionContext) -> R,
446
				) -> R {
447
					T::with_function_context(caller, callback)
448
				}
449

            
450
				fn register_static<Params, Results>(
451
					&mut self,
452
					fn_name: &str,
453
					func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
454
				) -> core::result::Result<(), Self::Error> {
455
					if self.overlay_registered {
456
						if !self.seen_base.insert(fn_name.to_owned()) {
457
							log::warn!(
458
								target: "extended_host_functions",
459
								"Duplicate base host function: '{}'",
460
								fn_name,
461
							);
462

            
463
							// TODO: Return an error here?
464
							return Ok(())
465
						}
466

            
467
						if self.seen_overlay.contains(fn_name) {
468
							// Was already registered when we went through the overlay, so just ignore it.
469
							log::debug!(
470
								target: "extended_host_functions",
471
								"Overriding base host function: '{}'",
472
								fn_name,
473
							);
474

            
475
							return Ok(())
476
						}
477
					} else if !self.seen_overlay.insert(fn_name.to_owned()) {
478
						log::warn!(
479
							target: "extended_host_functions",
480
							"Duplicate overlay host function: '{}'",
481
							fn_name,
482
						);
483

            
484
						// TODO: Return an error here?
485
						return Ok(())
486
					}
487

            
488
					self.registry.register_static(fn_name, func)
489
				}
490
			}
491

            
492
			let mut proxy = Proxy {
493
				registry,
494
				seen_overlay: Default::default(),
495
				seen_base: Default::default(),
496
				overlay_registered: false,
497
			};
498

            
499
			// The functions from the `Overlay` can override those from the `Base`,
500
			// so `Overlay` is registered first, and then we skip those functions
501
			// in `Base` if they were already registered from the `Overlay`.
502
			Overlay::register_static(&mut proxy)?;
503
			proxy.overlay_registered = true;
504
			Base::register_static(&mut proxy)?;
505

            
506
			Ok(())
507
		}
508
	}
509
}
510

            
511
/// A trait for types directly usable at the WASM FFI boundary without any conversion at all.
512
///
513
/// This trait is sealed and should not be implemented downstream.
514
#[cfg(all(feature = "std", feature = "wasmtime"))]
515
pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
516

            
517
/// A trait for types directly usable at the WASM FFI boundary without any conversion at all.
518
///
519
/// This trait is sealed and should not be implemented downstream.
520
#[cfg(not(all(feature = "std", feature = "wasmtime")))]
521
pub trait WasmTy: private::Sealed {}
522

            
523
impl WasmTy for i32 {}
524
impl WasmTy for u32 {}
525
impl WasmTy for i64 {}
526
impl WasmTy for u64 {}
527

            
528
/// Something that can be converted into a wasm compatible `Value`.
529
pub trait IntoValue {
530
	/// The type of the value in wasm.
531
	const VALUE_TYPE: ValueType;
532

            
533
	/// Convert `self` into a wasm `Value`.
534
	fn into_value(self) -> Value;
535
}
536

            
537
/// Something that can may be created from a wasm `Value`.
538
pub trait TryFromValue: Sized {
539
	/// Try to convert the given `Value` into `Self`.
540
	fn try_from_value(val: Value) -> Option<Self>;
541
}
542

            
543
macro_rules! impl_into_and_from_value {
544
	(
545
		$(
546
			$type:ty, $( < $gen:ident >, )? $value_variant:ident,
547
		)*
548
	) => {
549
		$(
550
			impl $( <$gen> )? IntoValue for $type {
551
				const VALUE_TYPE: ValueType = ValueType::$value_variant;
552
				fn into_value(self) -> Value { Value::$value_variant(self as _) }
553
			}
554

            
555
			impl $( <$gen> )? TryFromValue for $type {
556
				fn try_from_value(val: Value) -> Option<Self> {
557
					match val {
558
						Value::$value_variant(val) => Some(val as _),
559
						_ => None,
560
					}
561
				}
562
			}
563
		)*
564
	}
565
}
566

            
567
impl_into_and_from_value! {
568
	u8, I32,
569
	u16, I32,
570
	u32, I32,
571
	u64, I64,
572
	i8, I32,
573
	i16, I32,
574
	i32, I32,
575
	i64, I64,
576
}
577

            
578
/// Typed value that can be returned from a function.
579
///
580
/// Basically a `TypedValue` plus `Unit`, for functions which return nothing.
581
#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
582
pub enum ReturnValue {
583
	/// For returning nothing.
584
	Unit,
585
	/// For returning some concrete value.
586
	Value(Value),
587
}
588

            
589
impl From<Value> for ReturnValue {
590
	fn from(v: Value) -> ReturnValue {
591
		ReturnValue::Value(v)
592
	}
593
}
594

            
595
impl ReturnValue {
596
	/// Maximum number of bytes `ReturnValue` might occupy when serialized with `SCALE`.
597
	///
598
	/// Breakdown:
599
	///  1 byte for encoding unit/value variant
600
	///  1 byte for encoding value type
601
	///  8 bytes for encoding the biggest value types available in wasm: f64, i64.
602
	pub const ENCODED_MAX_SIZE: usize = 10;
603
}
604

            
605
#[cfg(test)]
606
mod tests {
607
	use super::*;
608
	use codec::Encode;
609

            
610
	#[test]
611
	fn pointer_offset_works() {
612
		let ptr = Pointer::<u32>::null();
613

            
614
		assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
615
		assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
616

            
617
		let ptr = Pointer::<u64>::null();
618

            
619
		assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
620
		assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
621
	}
622

            
623
	#[test]
624
	fn return_value_encoded_max_size() {
625
		let encoded = ReturnValue::Value(Value::I64(-1)).encode();
626
		assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
627
	}
628
}