// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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. // Substrate 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 Substrate. If not, see . //! Provides implementations for the runtime interface traits. use crate::{ RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner}, util::{unpack_ptr_and_len, pack_ptr_and_len}, }; #[cfg(feature = "std")] use crate::host::*; #[cfg(not(feature = "std"))] use crate::wasm::*; #[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))] use static_assertions::assert_eq_size; #[cfg(feature = "std")] use sp_wasm_interface::{FunctionContext, Result}; use codec::{Encode, Decode}; use sp_std::{any::TypeId, mem, vec::Vec}; #[cfg(feature = "std")] use sp_std::borrow::Cow; #[cfg(not(feature = "std"))] use sp_std::{slice, boxed::Box}; // Make sure that our assumptions for storing a pointer + its size in `u64` is valid. #[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))] assert_eq_size!(usize, u32); #[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))] assert_eq_size!(*const u8, u32); /// Implement the traits for the given primitive traits. macro_rules! impl_traits_for_primitives { ( $( $rty:ty, $fty:ty, )* ) => { $( /// The type is passed directly. impl RIType for $rty { type FFIType = $fty; } #[cfg(not(feature = "std"))] impl IntoFFIValue for $rty { type Owned = (); fn into_ffi_value(&self) -> WrappedFFIValue<$fty> { (*self as $fty).into() } } #[cfg(not(feature = "std"))] impl FromFFIValue for $rty { fn from_ffi_value(arg: $fty) -> $rty { arg as $rty } } #[cfg(feature = "std")] impl FromFFIValue for $rty { type SelfInstance = $rty; fn from_ffi_value(_: &mut dyn FunctionContext, arg: $fty) -> Result<$rty> { Ok(arg as $rty) } } #[cfg(feature = "std")] impl IntoFFIValue for $rty { fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<$fty> { Ok(self as $fty) } } )* } } impl_traits_for_primitives! { u8, u8, u16, u16, u32, u32, u64, u64, i8, i8, i16, i16, i32, i32, i64, i64, } /// `bool` is passed as `u8`. /// /// - `1`: true /// - `0`: false impl RIType for bool { type FFIType = u8; } #[cfg(not(feature = "std"))] impl IntoFFIValue for bool { type Owned = (); fn into_ffi_value(&self) -> WrappedFFIValue { if *self { 1 } else { 0 }.into() } } #[cfg(not(feature = "std"))] impl FromFFIValue for bool { fn from_ffi_value(arg: u8) -> bool { arg == 1 } } #[cfg(feature = "std")] impl FromFFIValue for bool { type SelfInstance = bool; fn from_ffi_value(_: &mut dyn FunctionContext, arg: u8) -> Result { Ok(arg == 1) } } #[cfg(feature = "std")] impl IntoFFIValue for bool { fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result { Ok(if self { 1 } else { 0 }) } } /// The type is passed as `u64`. /// /// The `u64` value is build by `length 32bit << 32 | pointer 32bit` /// /// If `T == u8` the length and the pointer are taken directly from the `Self`. /// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector. impl RIType for Vec { type FFIType = u64; } #[cfg(feature = "std")] impl IntoFFIValue for Vec { fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { let vec: Cow<'_, [u8]> = if TypeId::of::() == TypeId::of::() { unsafe { Cow::Borrowed(mem::transmute(&self[..])) } } else { Cow::Owned(self.encode()) }; let ptr = context.allocate_memory(vec.as_ref().len() as u32)?; context.write_memory(ptr, &vec)?; Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32)) } } #[cfg(feature = "std")] impl FromFFIValue for Vec { type SelfInstance = Vec; fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result> { <[T] as FromFFIValue>::from_ffi_value(context, arg) } } #[cfg(not(feature = "std"))] impl IntoFFIValue for Vec { type Owned = Vec; fn into_ffi_value(&self) -> WrappedFFIValue> { self[..].into_ffi_value() } } #[cfg(not(feature = "std"))] impl FromFFIValue for Vec { fn from_ffi_value(arg: u64) -> Vec { let (ptr, len) = unpack_ptr_and_len(arg); let len = len as usize; if TypeId::of::() == TypeId::of::() { unsafe { mem::transmute(Vec::from_raw_parts(ptr as *mut u8, len, len)) } } else { let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len) }; Self::decode(&mut &slice[..]).expect("Host to wasm values are encoded correctly; qed") } } } /// The type is passed as `u64`. /// /// The `u64` value is build by `length 32bit << 32 | pointer 32bit` /// /// If `T == u8` the length and the pointer are taken directly from the `Self`. /// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector. impl RIType for [T] { type FFIType = u64; } #[cfg(feature = "std")] impl FromFFIValue for [T] { type SelfInstance = Vec; fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result> { let (ptr, len) = unpack_ptr_and_len(arg); let vec = context.read_memory(Pointer::new(ptr), len)?; if TypeId::of::() == TypeId::of::() { Ok(unsafe { mem::transmute(vec) }) } else { Ok(Vec::::decode(&mut &vec[..]).expect("Wasm to host values are encoded correctly; qed")) } } } #[cfg(feature = "std")] impl IntoPreallocatedFFIValue for [u8] { type SelfInstance = Vec; fn into_preallocated_ffi_value( self_instance: Self::SelfInstance, context: &mut dyn FunctionContext, allocated: u64, ) -> Result<()> { let (ptr, len) = unpack_ptr_and_len(allocated); if (len as usize) < self_instance.len() { Err( format!( "Preallocated buffer is not big enough (given {} vs needed {})!", len, self_instance.len() ) ) } else { context.write_memory(Pointer::new(ptr), &self_instance) } } } #[cfg(not(feature = "std"))] impl IntoFFIValue for [T] { type Owned = Vec; fn into_ffi_value(&self) -> WrappedFFIValue> { if TypeId::of::() == TypeId::of::() { let slice = unsafe { mem::transmute::<&[T], &[u8]>(self) }; pack_ptr_and_len(slice.as_ptr() as u32, slice.len() as u32).into() } else { let data = self.encode(); let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32); (ffi_value, data).into() } } } /// Implement the traits for the `[u8; N]` arrays, where `N` is the input to this macro. macro_rules! impl_traits_for_arrays { ( $( $n:expr ),* $(,)? ) => { $( /// The type is passed as `u32`. /// /// The `u32` is the pointer to the array. impl RIType for [u8; $n] { type FFIType = u32; } #[cfg(not(feature = "std"))] impl IntoFFIValue for [u8; $n] { type Owned = (); fn into_ffi_value(&self) -> WrappedFFIValue { (self.as_ptr() as u32).into() } } #[cfg(not(feature = "std"))] impl FromFFIValue for [u8; $n] { fn from_ffi_value(arg: u32) -> [u8; $n] { let mut res = [0u8; $n]; res.copy_from_slice(unsafe { slice::from_raw_parts(arg as *const u8, $n) }); // Make sure we free the pointer. let _ = unsafe { Box::from_raw(arg as *mut u8) }; res } } #[cfg(feature = "std")] impl FromFFIValue for [u8; $n] { type SelfInstance = [u8; $n]; fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; $n]> { let data = context.read_memory(Pointer::new(arg), $n)?; let mut res = [0u8; $n]; res.copy_from_slice(&data); Ok(res) } } #[cfg(feature = "std")] impl IntoFFIValue for [u8; $n] { fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { let addr = context.allocate_memory($n)?; context.write_memory(addr, &self)?; Ok(addr.into()) } } #[cfg(feature = "std")] impl IntoPreallocatedFFIValue for [u8; $n] { type SelfInstance = [u8; $n]; fn into_preallocated_ffi_value( self_instance: Self::SelfInstance, context: &mut dyn FunctionContext, allocated: u32, ) -> Result<()> { context.write_memory(Pointer::new(allocated), &self_instance) } } )* } } impl_traits_for_arrays! { 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, } impl PassBy for sp_std::result::Result { type PassBy = Codec; } impl PassBy for Option { type PassBy = Codec; } /// Implement `PassBy` with `Inner` for the given fixed sized hash types. macro_rules! for_primitive_types { { $( $hash:ident $n:expr ),* $(,)? } => { $( impl PassBy for primitive_types::$hash { type PassBy = Inner; } impl PassByInner for primitive_types::$hash { type Inner = [u8; $n]; fn inner(&self) -> &Self::Inner { &self.0 } fn into_inner(self) -> Self::Inner { self.0 } fn from_inner(inner: Self::Inner) -> Self { Self(inner) } } )* } } for_primitive_types! { H160 20, H256 32, H512 64, } /// The type is passed as `u64`. /// /// The `u64` value is build by `length 32bit << 32 | pointer 32bit` /// /// The length and the pointer are taken directly from the `Self`. impl RIType for str { type FFIType = u64; } #[cfg(feature = "std")] impl FromFFIValue for str { type SelfInstance = String; fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result { let (ptr, len) = unpack_ptr_and_len(arg); let vec = context.read_memory(Pointer::new(ptr), len)?; // The data is valid utf8, as it is stored as `&str` in wasm. String::from_utf8(vec).map_err(|_| "Invalid utf8 data provided".into()) } } #[cfg(not(feature = "std"))] impl IntoFFIValue for str { type Owned = (); fn into_ffi_value(&self) -> WrappedFFIValue { let bytes = self.as_bytes(); pack_ptr_and_len(bytes.as_ptr() as u32, bytes.len() as u32).into() } } #[cfg(feature = "std")] impl RIType for Pointer { type FFIType = u32; } /// The type is passed as `u32`. #[cfg(not(feature = "std"))] impl RIType for Pointer { type FFIType = u32; } #[cfg(not(feature = "std"))] impl IntoFFIValue for Pointer { type Owned = (); fn into_ffi_value(&self) -> WrappedFFIValue { (*self as u32).into() } } #[cfg(not(feature = "std"))] impl FromFFIValue for Pointer { fn from_ffi_value(arg: u32) -> Self { arg as _ } } #[cfg(feature = "std")] impl FromFFIValue for Pointer { type SelfInstance = Self; fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result { Ok(Pointer::new(arg)) } } #[cfg(feature = "std")] impl IntoFFIValue for Pointer { fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result { Ok(self.into()) } }